@camerontaylor/paseo-client 0.9.1-fork.1 → 0.10.2-fork.1
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/connection/index.d.ts +1 -0
- package/dist/connection/index.js +1 -0
- package/dist/daemon-client-relay-e2ee-transport.d.ts +1 -0
- package/dist/daemon-client-relay-e2ee-transport.js +6 -2
- package/dist/daemon-client-transport.d.ts +1 -1
- package/dist/daemon-client-transport.js +1 -1
- package/dist/daemon-client.d.ts +19 -1
- package/dist/daemon-client.js +115 -21
- package/package.json +3 -3
package/dist/connection/index.js
CHANGED
|
@@ -90,6 +90,7 @@ export class ConnectionSubscriptions extends OwnedSubscriptions {
|
|
|
90
90
|
// Protocol support belongs to the installed client. Only browser hosting needs
|
|
91
91
|
// a resource supplied by the caller. Keep this exhaustive as the protocol evolves.
|
|
92
92
|
export const DEFAULT_CLIENT_CAPABILITIES = {
|
|
93
|
+
[CLIENT_CAPS.helloRejection]: true,
|
|
93
94
|
[CLIENT_CAPS.ownedSubscriptions]: true,
|
|
94
95
|
[CLIENT_CAPS.allProviders]: true,
|
|
95
96
|
[CLIENT_CAPS.selectiveAgentTimeline]: true,
|
|
@@ -4,5 +4,6 @@ export declare function createRelayE2eeTransportFactory(args: {
|
|
|
4
4
|
daemonPublicKeyB64: string;
|
|
5
5
|
logger: TransportLogger;
|
|
6
6
|
}): DaemonTransportFactory;
|
|
7
|
+
export declare function createRelayTransportFactory(baseFactory: DaemonTransportFactory): DaemonTransportFactory;
|
|
7
8
|
export declare function createEncryptedTransport(base: DaemonTransport, daemonPublicKeyB64: string, logger: TransportLogger): DaemonTransport;
|
|
8
9
|
//# sourceMappingURL=daemon-client-relay-e2ee-transport.d.ts.map
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { createClientChannel, } from "@camerontaylor/paseo-relay/e2ee";
|
|
2
2
|
import { extractRelayMessage, normalizeTransportPayload } from "./daemon-client-transport-utils.js";
|
|
3
3
|
export function createRelayE2eeTransportFactory(args) {
|
|
4
|
-
return ({ url
|
|
5
|
-
const base = args.baseFactory({ url
|
|
4
|
+
return ({ url }) => {
|
|
5
|
+
const base = args.baseFactory({ url });
|
|
6
6
|
return createEncryptedTransport(base, args.daemonPublicKeyB64, args.logger);
|
|
7
7
|
};
|
|
8
8
|
}
|
|
9
|
+
export function createRelayTransportFactory(baseFactory) {
|
|
10
|
+
// The relay upgrade precedes E2EE. Only the encrypted hello may carry daemon credentials.
|
|
11
|
+
return ({ url }) => baseFactory({ url });
|
|
12
|
+
}
|
|
9
13
|
export function createEncryptedTransport(base, daemonPublicKeyB64, logger) {
|
|
10
14
|
let channel = null;
|
|
11
15
|
let opened = false;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type { DaemonTransport, DaemonTransportFactory, TransportLogger, WebSocketFactory, WebSocketLike, } from "./daemon-client-transport-types.js";
|
|
2
2
|
export { decodeMessageData, describeTransportClose, describeTransportError, encodeUtf8String, extractRelayMessage, normalizeTransportPayload, safeRandomId, } from "./daemon-client-transport-utils.js";
|
|
3
|
-
export { createEncryptedTransport, createRelayE2eeTransportFactory, } from "./daemon-client-relay-e2ee-transport.js";
|
|
3
|
+
export { createEncryptedTransport, createRelayE2eeTransportFactory, createRelayTransportFactory, } from "./daemon-client-relay-e2ee-transport.js";
|
|
4
4
|
export { bindWsHandler, createWebSocketTransportFactory, defaultWebSocketFactory, } from "./daemon-client-websocket-transport.js";
|
|
5
5
|
//# sourceMappingURL=daemon-client-transport.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { decodeMessageData, describeTransportClose, describeTransportError, encodeUtf8String, extractRelayMessage, normalizeTransportPayload, safeRandomId, } from "./daemon-client-transport-utils.js";
|
|
2
|
-
export { createEncryptedTransport, createRelayE2eeTransportFactory, } from "./daemon-client-relay-e2ee-transport.js";
|
|
2
|
+
export { createEncryptedTransport, createRelayE2eeTransportFactory, createRelayTransportFactory, } from "./daemon-client-relay-e2ee-transport.js";
|
|
3
3
|
export { bindWsHandler, createWebSocketTransportFactory, defaultWebSocketFactory, } from "./daemon-client-websocket-transport.js";
|
|
4
4
|
//# sourceMappingURL=daemon-client-transport.js.map
|
package/dist/daemon-client.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { z } from "zod";
|
|
|
5
5
|
import type { SessionEventSubscription } from "@camerontaylor/paseo-protocol/messages";
|
|
6
6
|
import type { ClientCapability } from "@camerontaylor/paseo-protocol/client-capabilities";
|
|
7
7
|
import type { AgentAttentionNotificationPayload } from "@camerontaylor/paseo-protocol/agent-attention-notification";
|
|
8
|
-
import { AgentRefreshedStatusPayloadSchema, CheckoutRenameBranchResponseSchema, RenameTerminalResponseSchema, RestartRequestedStatusPayloadSchema, ShutdownRequestedStatusPayloadSchema, DaemonUpdateResponseSchema, type ActiveTurnBehavior, type ServerInfoStatusPayload } from "@camerontaylor/paseo-protocol/messages";
|
|
8
|
+
import { AgentRefreshedStatusPayloadSchema, CheckoutRenameBranchResponseSchema, CheckoutBaseRefSetResponseSchema, RenameTerminalResponseSchema, RestartRequestedStatusPayloadSchema, ShutdownRequestedStatusPayloadSchema, DaemonUpdateResponseSchema, type ActiveTurnBehavior, type ServerInfoStatusPayload } from "@camerontaylor/paseo-protocol/messages";
|
|
9
9
|
import type { AgentStreamEventPayload, AgentSnapshotPayload, ProjectPlacementPayload, AgentPermissionResolvedMessage, CreateAgentRequestMessage, CreatePaseoWorktreeRequest, FileDownloadTokenResponse, FileUploadResponse, FileExplorerResponse, FileVersion, FileWriteResult, FetchAgentTimelineResponseMessage, AgentForkContextResponseMessage, GitSetupOptions, CheckoutStatusResponse, CheckoutCommit, ParsedDiffFile, CheckoutCommitResponse, CheckoutMergeResponse, CheckoutMergeFromBaseResponse, CheckoutPullResponse, CheckoutPushResponse, CheckoutRefreshResponse, CheckoutPrCreateResponse, CheckoutPrMergeResponse, CheckoutPrMergeMethod, CheckoutForgeSetAutoMergeResponse, CheckoutGithubSetAutoMergeResponse, CheckoutForgeGetCheckDetailsResponse, CheckoutGithubGetCheckDetailsResponse, CheckoutPrStatusResponse, PullRequestTimelineResponse, CheckoutSwitchBranchResponse, StashSaveResponse, StashPopResponse, StashListResponse, ValidateBranchResponse, BranchSuggestionsResponse, ForgeSearchResponse, ForgeSearchRequest, GitHubSearchResponse, GitHubSearchRequest, DirectorySuggestionsResponse, PaseoWorktreeListResponse, PaseoWorktreeArchiveResponse, ProjectIconSource, ProjectIconResponse, ProjectIconGetResponse, ProjectAddResponse, ProjectCreateDirectoryResponse, OpenProjectResponseMessage, WorkspaceGithubSearchRepositoriesResponse, ProjectGithubCloneProtocol, ProjectGithubCloneResponse, ArchiveWorkspaceResponseMessage, WorkspaceSetupStatusResponseMessage, ListCommandsResponse, ListProviderFeaturesResponseMessage, ListProviderModelsResponseMessage, ListProviderModesResponseMessage, ListAvailableProvidersResponse, GetProvidersSnapshotResponseMessage, RefreshProvidersSnapshotResponseMessage, ProviderDiagnosticResponseMessage, ProviderUsageListResponseMessage, DaemonGetStatusResponse, DaemonGetPairingOfferResponse, DaemonConfigReloadResponse, DiagnosticsResponse, AgentRewindResponseMessage, ListTerminalsResponse, CreateTerminalResponse, SubscribeTerminalResponse, SubscribeTerminalRequest, CloseItemsResponse, KillTerminalResponse, CaptureTerminalResponse, TerminalInput, SessionInboundMessage, SessionOutboundMessage, SendAgentMessageRequest, PaseoConfigRaw, PaseoConfigRevision, WorkspaceCreateRequest, WorkspaceRecoveryState, PluginListItem, PluginLogEntry, PluginSourceStatusItem, PluginSourceUpdateItem, PluginUpdateSelection, PluginUpdateProposal, PluginUpdatePreview, PluginUpdateResult, AgentSkillSelection, AgentSkillsStatus, AgentSkillsSaveResult } from "@camerontaylor/paseo-protocol/messages";
|
|
10
10
|
import type { AgentPermissionRequest, AgentPermissionResponse, AgentPersistenceHandle, AgentProviderNotice, AgentProvider, AgentSessionConfig } from "@camerontaylor/paseo-protocol/agent-types";
|
|
11
11
|
import type { AgentConfigApply, MutableDaemonConfig, MutableDaemonConfigPatch } from "@camerontaylor/paseo-protocol/messages";
|
|
@@ -30,6 +30,12 @@ export type ImportAgentInput = (ImportAgentInputBase & {
|
|
|
30
30
|
provider: AgentProvider;
|
|
31
31
|
sessionId: string;
|
|
32
32
|
});
|
|
33
|
+
export type DaemonAuthFailureReason = "password_required" | "incorrect_password";
|
|
34
|
+
export declare class DaemonAuthenticationError extends Error {
|
|
35
|
+
readonly reason: DaemonAuthFailureReason;
|
|
36
|
+
constructor(reason: DaemonAuthFailureReason);
|
|
37
|
+
}
|
|
38
|
+
export declare function getDaemonAuthFailureReason(error: unknown): DaemonAuthFailureReason | null;
|
|
33
39
|
export type { DaemonTransport, DaemonTransportFactory, WebSocketFactory, WebSocketLike, } from "./daemon-client-transport.js";
|
|
34
40
|
export type { TerminalStreamEvent };
|
|
35
41
|
export type ConnectionState = {
|
|
@@ -114,6 +120,7 @@ export interface DaemonClientConfig {
|
|
|
114
120
|
appVersion?: string;
|
|
115
121
|
runtimeGeneration?: number | null;
|
|
116
122
|
password?: string;
|
|
123
|
+
localCredential?: () => string | undefined | Promise<string | undefined>;
|
|
117
124
|
authHeader?: string;
|
|
118
125
|
suppressSendErrors?: boolean;
|
|
119
126
|
transportFactory?: DaemonTransportFactory;
|
|
@@ -211,6 +218,7 @@ type CheckoutPrStatusPayload = CheckoutPrStatusResponse["payload"];
|
|
|
211
218
|
type PullRequestTimelinePayload = PullRequestTimelineResponse["payload"];
|
|
212
219
|
type CheckoutSwitchBranchPayload = CheckoutSwitchBranchResponse["payload"];
|
|
213
220
|
export type RenameBranchResult = z.infer<typeof CheckoutRenameBranchResponseSchema>["payload"];
|
|
221
|
+
export type SetCheckoutBaseRefResult = z.infer<typeof CheckoutBaseRefSetResponseSchema>["payload"];
|
|
214
222
|
type StashSavePayload = StashSaveResponse["payload"];
|
|
215
223
|
type StashPopPayload = StashPopResponse["payload"];
|
|
216
224
|
type StashListPayload = StashListResponse["payload"];
|
|
@@ -529,6 +537,11 @@ export interface RenameBranchInput {
|
|
|
529
537
|
branch: string;
|
|
530
538
|
requestId?: string;
|
|
531
539
|
}
|
|
540
|
+
export interface SetCheckoutBaseRefInput {
|
|
541
|
+
cwd: string;
|
|
542
|
+
baseRef: string;
|
|
543
|
+
requestId?: string;
|
|
544
|
+
}
|
|
532
545
|
export interface RenameTerminalInput {
|
|
533
546
|
terminalId: string;
|
|
534
547
|
title: string;
|
|
@@ -578,6 +591,7 @@ export declare class DaemonClient {
|
|
|
578
591
|
private readonly providerSnapshotUpdates;
|
|
579
592
|
private readonly owned;
|
|
580
593
|
private transport;
|
|
594
|
+
private helloAuth;
|
|
581
595
|
private transportCleanup;
|
|
582
596
|
private rawMessageListeners;
|
|
583
597
|
private messageHandlers;
|
|
@@ -594,6 +608,7 @@ export declare class DaemonClient {
|
|
|
594
608
|
private connectResolve;
|
|
595
609
|
private connectReject;
|
|
596
610
|
private lastErrorValue;
|
|
611
|
+
private authFailureReasonValue;
|
|
597
612
|
private connectionState;
|
|
598
613
|
private readonly terminalStreams;
|
|
599
614
|
private pendingBinaryFileReads;
|
|
@@ -616,6 +631,7 @@ export declare class DaemonClient {
|
|
|
616
631
|
constructor(config: DaemonClientConfig);
|
|
617
632
|
connect(): Promise<void>;
|
|
618
633
|
private attemptConnect;
|
|
634
|
+
private assertEncryptedRelayAuth;
|
|
619
635
|
private resolveConnect;
|
|
620
636
|
private rejectConnect;
|
|
621
637
|
close(): Promise<void>;
|
|
@@ -628,6 +644,7 @@ export declare class DaemonClient {
|
|
|
628
644
|
get isConnected(): boolean;
|
|
629
645
|
get isConnecting(): boolean;
|
|
630
646
|
get lastError(): string | null;
|
|
647
|
+
get authFailureReason(): DaemonAuthFailureReason | null;
|
|
631
648
|
getLastLivenessRttMs(): number | null;
|
|
632
649
|
subscribe(handler: DaemonEventHandler): () => void;
|
|
633
650
|
subscribeRawMessages(handler: (message: SessionOutboundMessage) => void): () => void;
|
|
@@ -973,6 +990,7 @@ export declare class DaemonClient {
|
|
|
973
990
|
}, requestId?: string): Promise<PullRequestTimelinePayload>;
|
|
974
991
|
checkoutSwitchBranch(cwd: string, branch: string, requestId?: string): Promise<CheckoutSwitchBranchPayload>;
|
|
975
992
|
renameBranch(input: RenameBranchInput): Promise<RenameBranchResult>;
|
|
993
|
+
setCheckoutBaseRef(input: SetCheckoutBaseRefInput): Promise<SetCheckoutBaseRefResult>;
|
|
976
994
|
stashSave(cwd: string, options?: {
|
|
977
995
|
branch?: string;
|
|
978
996
|
}, requestId?: string): Promise<StashSavePayload>;
|
package/dist/daemon-client.js
CHANGED
|
@@ -7,7 +7,7 @@ import { AgentCreateFailedStatusPayloadSchema, AgentCreatedStatusPayloadSchema,
|
|
|
7
7
|
import { validateWSOutboundMessage } from "@camerontaylor/paseo-protocol/validation/ws-outbound";
|
|
8
8
|
import { isRelayClientWebSocketUrl } from "@camerontaylor/paseo-protocol/daemon-endpoints";
|
|
9
9
|
import { asUint8Array, decodeFileTransferFrame, encodeFileTransferFrame, decodeTerminalStreamFrame, FileTransferOpcode, TerminalStreamOpcode, } from "@camerontaylor/paseo-protocol/binary-frames/index";
|
|
10
|
-
import { createRelayE2eeTransportFactory, createWebSocketTransportFactory, decodeMessageData, defaultWebSocketFactory, describeTransportClose, describeTransportError, } from "./daemon-client-transport.js";
|
|
10
|
+
import { createRelayE2eeTransportFactory, createRelayTransportFactory, createWebSocketTransportFactory, decodeMessageData, defaultWebSocketFactory, describeTransportClose, describeTransportError, } from "./daemon-client-transport.js";
|
|
11
11
|
import { DaemonClientRuntimeMetrics } from "./daemon-client-runtime-metrics.js";
|
|
12
12
|
import { normalizeListProviderModelsPayload, normalizeProviderSnapshotUpdateMessage, normalizeProvidersSnapshotPayload, } from "./compat/normalize-provider-models.js";
|
|
13
13
|
import { TerminalStreamRouter } from "./terminal-stream-router.js";
|
|
@@ -27,6 +27,55 @@ function normalizePassword(value) {
|
|
|
27
27
|
}
|
|
28
28
|
return value.length > 0 ? value : null;
|
|
29
29
|
}
|
|
30
|
+
function compatibleBearerPassword(password) {
|
|
31
|
+
return password && /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/.test(password) ? password : null;
|
|
32
|
+
}
|
|
33
|
+
export class DaemonAuthenticationError extends Error {
|
|
34
|
+
constructor(reason) {
|
|
35
|
+
super(reason === "password_required" ? "Password required" : "Incorrect password");
|
|
36
|
+
this.name = "DaemonAuthenticationError";
|
|
37
|
+
this.reason = reason;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export function getDaemonAuthFailureReason(error) {
|
|
41
|
+
return error instanceof DaemonAuthenticationError ? error.reason : null;
|
|
42
|
+
}
|
|
43
|
+
function authFailureFromLegacyClose(event) {
|
|
44
|
+
if (!event || typeof event !== "object" || !("reason" in event))
|
|
45
|
+
return null;
|
|
46
|
+
if (event.reason === "Password required")
|
|
47
|
+
return "password_required";
|
|
48
|
+
if (event.reason === "Incorrect password")
|
|
49
|
+
return "incorrect_password";
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
function chooseConnectionAuth(config, localCredential) {
|
|
53
|
+
const password = normalizePassword(config.password);
|
|
54
|
+
let helloAuth;
|
|
55
|
+
if (localCredential)
|
|
56
|
+
helloAuth = { kind: "localCredential", token: localCredential };
|
|
57
|
+
else if (password)
|
|
58
|
+
helloAuth = { kind: "password", password };
|
|
59
|
+
const headers = {};
|
|
60
|
+
const compatibleBearer = localCredential ? null : compatibleBearerPassword(password);
|
|
61
|
+
// COMPAT(headerAuth): added in v0.9.1, remove after 2027-03-24.
|
|
62
|
+
if (compatibleBearer)
|
|
63
|
+
headers.Authorization = `Bearer ${compatibleBearer}`;
|
|
64
|
+
else if (!localCredential && config.authHeader)
|
|
65
|
+
headers.Authorization = config.authHeader;
|
|
66
|
+
return {
|
|
67
|
+
helloAuth,
|
|
68
|
+
headers,
|
|
69
|
+
...(compatibleBearer ? { protocols: [`paseo.bearer.${compatibleBearer}`] } : {}),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function resolveConnectionAuth(config) {
|
|
73
|
+
const resolution = config.localCredential?.();
|
|
74
|
+
if (resolution instanceof Promise) {
|
|
75
|
+
return resolution.then((credential) => chooseConnectionAuth(config, credential));
|
|
76
|
+
}
|
|
77
|
+
return chooseConnectionAuth(config, resolution);
|
|
78
|
+
}
|
|
30
79
|
function extractCorrelatedResponseIdentity(input) {
|
|
31
80
|
if (!input || typeof input !== "object") {
|
|
32
81
|
return null;
|
|
@@ -279,6 +328,7 @@ export class DaemonClient {
|
|
|
279
328
|
this.connectResolve = null;
|
|
280
329
|
this.connectReject = null;
|
|
281
330
|
this.lastErrorValue = null;
|
|
331
|
+
this.authFailureReasonValue = null;
|
|
282
332
|
this.connectionState = { status: "idle" };
|
|
283
333
|
this.terminalStreams = new TerminalStreamRouter();
|
|
284
334
|
this.pendingBinaryFileReads = new Map();
|
|
@@ -393,7 +443,7 @@ export class DaemonClient {
|
|
|
393
443
|
});
|
|
394
444
|
return this.connectPromise;
|
|
395
445
|
}
|
|
396
|
-
attemptConnect() {
|
|
446
|
+
async attemptConnect() {
|
|
397
447
|
if (this.connectionState.status === "disposed") {
|
|
398
448
|
this.rejectConnect(new Error("Daemon client is disposed"));
|
|
399
449
|
return;
|
|
@@ -411,30 +461,30 @@ export class DaemonClient {
|
|
|
411
461
|
clearTimeout(this.reconnectTimeout);
|
|
412
462
|
this.reconnectTimeout = null;
|
|
413
463
|
}
|
|
414
|
-
const headers = {};
|
|
415
|
-
const password = normalizePassword(this.config.password);
|
|
416
|
-
if (password) {
|
|
417
|
-
headers.Authorization = `Bearer ${password}`;
|
|
418
|
-
}
|
|
419
|
-
else if (this.config.authHeader) {
|
|
420
|
-
headers.Authorization = this.config.authHeader;
|
|
421
|
-
}
|
|
422
|
-
const protocols = password ? [`paseo.bearer.${password}`] : undefined;
|
|
423
464
|
try {
|
|
465
|
+
const resolution = resolveConnectionAuth(this.config);
|
|
466
|
+
const selected = resolution instanceof Promise ? await resolution : resolution;
|
|
467
|
+
if (!this.shouldReconnect)
|
|
468
|
+
return;
|
|
469
|
+
this.helloAuth = selected.helloAuth;
|
|
424
470
|
// Reconnect can overlap with browser close/error delivery ordering.
|
|
425
471
|
// Always dispose previous transport before constructing the next one.
|
|
426
472
|
this.disposeTransport();
|
|
427
473
|
const baseTransportFactory = this.config.transportFactory ??
|
|
428
474
|
createWebSocketTransportFactory(this.config.webSocketFactory ?? defaultWebSocketFactory);
|
|
429
|
-
const
|
|
430
|
-
|
|
475
|
+
const isRelayTransport = isRelayClientWebSocketUrl(this.config.url);
|
|
476
|
+
const shouldUseRelayE2ee = this.config.e2ee?.enabled === true && isRelayTransport;
|
|
477
|
+
this.assertEncryptedRelayAuth(selected.helloAuth, isRelayTransport);
|
|
478
|
+
let transportFactory = isRelayTransport
|
|
479
|
+
? createRelayTransportFactory(baseTransportFactory)
|
|
480
|
+
: baseTransportFactory;
|
|
431
481
|
if (shouldUseRelayE2ee) {
|
|
432
482
|
const daemonPublicKeyB64 = this.config.e2ee?.daemonPublicKeyB64;
|
|
433
483
|
if (!daemonPublicKeyB64) {
|
|
434
484
|
throw new Error("daemonPublicKeyB64 is required for relay E2EE");
|
|
435
485
|
}
|
|
436
486
|
transportFactory = createRelayE2eeTransportFactory({
|
|
437
|
-
baseFactory:
|
|
487
|
+
baseFactory: transportFactory,
|
|
438
488
|
daemonPublicKeyB64,
|
|
439
489
|
logger: this.logger,
|
|
440
490
|
});
|
|
@@ -442,11 +492,12 @@ export class DaemonClient {
|
|
|
442
492
|
const transportUrl = this.resolveTransportUrlForAttempt();
|
|
443
493
|
const transport = transportFactory({
|
|
444
494
|
url: transportUrl,
|
|
445
|
-
headers,
|
|
446
|
-
...(protocols ? { protocols } : {}),
|
|
495
|
+
headers: selected.headers,
|
|
496
|
+
...(selected.protocols ? { protocols: selected.protocols } : {}),
|
|
447
497
|
});
|
|
448
498
|
this.transport = transport;
|
|
449
499
|
this.lastServerInfoMessage = null;
|
|
500
|
+
this.authFailureReasonValue = null;
|
|
450
501
|
this.updateConnectionState({
|
|
451
502
|
status: "connecting",
|
|
452
503
|
attempt: this.reconnectAttempt,
|
|
@@ -472,7 +523,7 @@ export class DaemonClient {
|
|
|
472
523
|
this.pendingGenericTransportErrorTimeout = null;
|
|
473
524
|
}
|
|
474
525
|
this.lastErrorValue = null;
|
|
475
|
-
this.sendHelloMessage();
|
|
526
|
+
void this.sendHelloMessage();
|
|
476
527
|
}),
|
|
477
528
|
transport.onClose((event) => {
|
|
478
529
|
this.resetConnectTimeout();
|
|
@@ -480,7 +531,10 @@ export class DaemonClient {
|
|
|
480
531
|
clearTimeout(this.pendingGenericTransportErrorTimeout);
|
|
481
532
|
this.pendingGenericTransportErrorTimeout = null;
|
|
482
533
|
}
|
|
483
|
-
|
|
534
|
+
this.authFailureReasonValue ?? (this.authFailureReasonValue = authFailureFromLegacyClose(event));
|
|
535
|
+
const reason = this.authFailureReasonValue
|
|
536
|
+
? new DaemonAuthenticationError(this.authFailureReasonValue).message
|
|
537
|
+
: describeTransportClose(event);
|
|
484
538
|
if (reason) {
|
|
485
539
|
this.lastErrorValue = reason;
|
|
486
540
|
}
|
|
@@ -544,6 +598,12 @@ export class DaemonClient {
|
|
|
544
598
|
this.rejectConnect(error instanceof Error ? error : new Error(message));
|
|
545
599
|
}
|
|
546
600
|
}
|
|
601
|
+
assertEncryptedRelayAuth(helloAuth, isRelayTransport) {
|
|
602
|
+
if (!isRelayTransport || !helloAuth || this.config.e2ee?.enabled === true)
|
|
603
|
+
return;
|
|
604
|
+
this.setReconnectEnabled(false);
|
|
605
|
+
throw new Error("Relay credentials require E2EE");
|
|
606
|
+
}
|
|
547
607
|
resolveConnect() {
|
|
548
608
|
if (this.connectResolve) {
|
|
549
609
|
this.connectResolve();
|
|
@@ -653,6 +713,9 @@ export class DaemonClient {
|
|
|
653
713
|
get lastError() {
|
|
654
714
|
return this.lastErrorValue;
|
|
655
715
|
}
|
|
716
|
+
get authFailureReason() {
|
|
717
|
+
return this.authFailureReasonValue;
|
|
718
|
+
}
|
|
656
719
|
getLastLivenessRttMs() {
|
|
657
720
|
return this.lastLivenessRttMs;
|
|
658
721
|
}
|
|
@@ -2898,6 +2961,17 @@ export class DaemonClient {
|
|
|
2898
2961
|
responseType: "checkout.rename_branch.response",
|
|
2899
2962
|
});
|
|
2900
2963
|
}
|
|
2964
|
+
async setCheckoutBaseRef(input) {
|
|
2965
|
+
return this.sendCorrelatedSessionRequest({
|
|
2966
|
+
requestId: input.requestId,
|
|
2967
|
+
message: {
|
|
2968
|
+
type: "checkout.base_ref.set.request",
|
|
2969
|
+
cwd: input.cwd,
|
|
2970
|
+
baseRef: input.baseRef,
|
|
2971
|
+
},
|
|
2972
|
+
responseType: "checkout.base_ref.set.response",
|
|
2973
|
+
});
|
|
2974
|
+
}
|
|
2901
2975
|
async stashSave(cwd, options, requestId) {
|
|
2902
2976
|
return this.sendCorrelatedSessionRequest({
|
|
2903
2977
|
requestId,
|
|
@@ -4174,8 +4248,9 @@ export class DaemonClient {
|
|
|
4174
4248
|
resolveTransportUrlForAttempt() {
|
|
4175
4249
|
return this.config.url;
|
|
4176
4250
|
}
|
|
4177
|
-
sendHelloMessage() {
|
|
4178
|
-
|
|
4251
|
+
async sendHelloMessage() {
|
|
4252
|
+
const transport = this.transport;
|
|
4253
|
+
if (!transport) {
|
|
4179
4254
|
this.scheduleReconnect({
|
|
4180
4255
|
reason: "Transport unavailable before hello",
|
|
4181
4256
|
event: "HELLO_TRANSPORT_MISSING",
|
|
@@ -4184,11 +4259,15 @@ export class DaemonClient {
|
|
|
4184
4259
|
return;
|
|
4185
4260
|
}
|
|
4186
4261
|
try {
|
|
4262
|
+
if (this.transport !== transport)
|
|
4263
|
+
return;
|
|
4264
|
+
const auth = this.helloAuth;
|
|
4187
4265
|
this.sendJsonMessage("hello", "hello", {
|
|
4188
4266
|
type: "hello",
|
|
4189
4267
|
clientId: this.config.clientId,
|
|
4190
4268
|
clientType: this.config.clientType ?? "cli",
|
|
4191
4269
|
protocolVersion: 1,
|
|
4270
|
+
...(auth ? { auth } : {}),
|
|
4192
4271
|
capabilities: {
|
|
4193
4272
|
...DEFAULT_CLIENT_CAPABILITIES,
|
|
4194
4273
|
// COMPAT(sideConversations): added in 0.7.0-beta.2.fork.1, fork-only.
|
|
@@ -4322,6 +4401,17 @@ export class DaemonClient {
|
|
|
4322
4401
|
this.runtimeMetrics?.recordMessage("pong", bytes, perfNow() - startMs);
|
|
4323
4402
|
return;
|
|
4324
4403
|
}
|
|
4404
|
+
if (parsed.data.type === "hello.rejected") {
|
|
4405
|
+
const reasonMessage = {
|
|
4406
|
+
password_required: "Password required",
|
|
4407
|
+
incorrect_password: "Incorrect password",
|
|
4408
|
+
incompatible_protocol: "Incompatible protocol version",
|
|
4409
|
+
};
|
|
4410
|
+
this.lastErrorValue = reasonMessage[parsed.data.reason];
|
|
4411
|
+
this.authFailureReasonValue =
|
|
4412
|
+
parsed.data.reason === "incompatible_protocol" ? null : parsed.data.reason;
|
|
4413
|
+
return;
|
|
4414
|
+
}
|
|
4325
4415
|
this.traceInstant("paseo.ws.message.inbound", {
|
|
4326
4416
|
envelopeType: "session",
|
|
4327
4417
|
messageType: parsed.data.message.type,
|
|
@@ -4494,13 +4584,17 @@ export class DaemonClient {
|
|
|
4494
4584
|
this.rejectPingProbe(new DaemonConnectionError(reason ?? "Connection lost"));
|
|
4495
4585
|
this.terminalStreams.clearSlots();
|
|
4496
4586
|
this.lastServerInfoMessage = null;
|
|
4587
|
+
if (this.authFailureReasonValue)
|
|
4588
|
+
this.setReconnectEnabled(false);
|
|
4497
4589
|
if (wasDisposed) {
|
|
4498
4590
|
this.rejectConnect(new Error(reason ?? "Daemon client is disposed"));
|
|
4499
4591
|
return;
|
|
4500
4592
|
}
|
|
4501
4593
|
this.emitDisconnectedStateForReconnect(reason, input);
|
|
4502
4594
|
if (!this.shouldReconnect || this.config.reconnect?.enabled === false) {
|
|
4503
|
-
this.rejectConnect(
|
|
4595
|
+
this.rejectConnect(this.authFailureReasonValue
|
|
4596
|
+
? new DaemonAuthenticationError(this.authFailureReasonValue)
|
|
4597
|
+
: new Error(reason ?? "Transport disconnected before connect"));
|
|
4504
4598
|
return;
|
|
4505
4599
|
}
|
|
4506
4600
|
this.armReconnectTimer();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camerontaylor/paseo-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.2-fork.1",
|
|
4
4
|
"description": "Paseo client SDK package",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"test": "vitest run"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@camerontaylor/paseo-protocol": "0.
|
|
43
|
-
"@camerontaylor/paseo-relay": "0.
|
|
42
|
+
"@camerontaylor/paseo-protocol": "0.10.2-fork.1",
|
|
43
|
+
"@camerontaylor/paseo-relay": "0.10.2-fork.1",
|
|
44
44
|
"zod": "^4.4.3"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|