@relayfile/sdk 0.10.31 → 0.10.33
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/index.d.ts +1 -1
- package/dist/mount-launcher.js +2 -1
- package/dist/setup-types.d.ts +17 -0
- package/dist/setup.d.ts +2 -0
- package/dist/setup.js +302 -2
- package/package.json +6 -6
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export type { RelayFileReadCacheOptions } from "./types.js";
|
|
|
3
3
|
export { RelayfileSetup, RELAYFILE_SDK_VERSION, WorkspaceHandle } from "./setup.js";
|
|
4
4
|
export { type RelayfileCloudLoginOptions, type RelayfileCloudTokenSet, type RelayfileCloudTokenSetupOptions } from "./cloud-login.js";
|
|
5
5
|
export { CloudAbortError, CloudApiError, CloudTimeoutError, InvalidLocalDirError, InvalidMountModeError, InvalidRemotePathError, IntegrationConnectionTimeoutError, MalformedCloudResponseError, MissingConnectionIdError, MountModeUnavailableError, MountReadyTimeoutError, MountSessionInputError, ProviderNotConnectedError, ProviderNotReadyError, RelayfileSetupError, UnknownProviderError } from "./setup-errors.js";
|
|
6
|
-
export { type EnsureMountedWorkspaceInput, WORKSPACE_INTEGRATION_PROVIDERS, type AgentWorkspaceInvite, type AgentWorkspaceInviteOptions, type AgentWorkspaceScopedInviteOptions, type ConnectIntegrationOptions, type ConnectIntegrationResult, type CreateWorkspaceOptions, type JoinWorkspaceOptions, type MountLauncher, type MountLauncherEvent, type MountLauncherInstance, type MountLauncherStart, type MountLocalLayout, type MountMode, type MountSessionRequest, type MountSessionResponse, type MountSessionResult, type MountSyncMode, type MountedWorkspaceHandle, type MountedWorkspaceStatus, type MountWorkspaceInput, type ReadMountedWorkspaceStatusInput, type RelayfileSetupOptions, type RelayfileSetupRetryOptions, type WaitForConnectionOptions, type WorkspaceInfo, type WorkspaceIntegrationProvider, type WorkspaceMountEnv, type WorkspaceMountEnvOptions, type WorkspacePermissions } from "./setup-types.js";
|
|
6
|
+
export { type EnsureMountedWorkspaceInput, WORKSPACE_INTEGRATION_PROVIDERS, type AgentWorkspaceInvite, type AgentWorkspaceInviteOptions, type AgentWorkspaceScopedInviteOptions, type ConnectIntegrationOptions, type ConnectIntegrationResult, type CreateWorkspaceOptions, type JoinWorkspaceOptions, type MountLauncher, type MountLauncherEvent, type MountLauncherInstance, type MountLauncherStart, type MountLocalLayout, type MountMode, type MountSessionRequest, type MountSessionResponse, type MountSessionResult, type MountSyncMode, type MountSupervisorEvent, type MountedWorkspaceHandle, type MountedWorkspaceStatus, type MountWorkspaceInput, type ReadMountedWorkspaceStatusInput, type RelayfileSetupOptions, type RelayfileSetupRetryOptions, type WaitForConnectionOptions, type WorkspaceInfo, type WorkspaceIntegrationProvider, type WorkspaceMountEnv, type WorkspaceMountEnvOptions, type WorkspacePermissions } from "./setup-types.js";
|
|
7
7
|
export { RelayFileSync, type RelayFileSyncOptions, type RelayFileSyncPong, type RelayFileSyncReconnectOptions, type RelayFileSyncSocket, type RelayFileSyncStart, type RelayFileSyncState, type RelayFileSyncTokenProvider } from "./sync.js";
|
|
8
8
|
export { onWrite, pathMatches, type OnWriteClient, type OnWriteHandler, type OnWriteHandlerError, type OnWriteOptions } from "./onWrite.js";
|
|
9
9
|
export { InvalidStateError, PayloadTooLargeError, QueueFullError, RelayFileApiError, RevisionConflictError } from "./errors.js";
|
package/dist/mount-launcher.js
CHANGED
|
@@ -109,7 +109,7 @@ class RelayfileMountProcessInstance {
|
|
|
109
109
|
this.ready = this.waitForReady();
|
|
110
110
|
}
|
|
111
111
|
async status() {
|
|
112
|
-
|
|
112
|
+
const status = await readMountedWorkspaceStatus({
|
|
113
113
|
localDir: this.localDir,
|
|
114
114
|
workspaceId: this.input.env.RELAYFILE_WORKSPACE ?? "",
|
|
115
115
|
remotePath: this.input.env.RELAYFILE_REMOTE_PATH ?? "/",
|
|
@@ -122,6 +122,7 @@ class RelayfileMountProcessInstance {
|
|
|
122
122
|
suggestedRefreshAt: null,
|
|
123
123
|
pid: this.pid
|
|
124
124
|
});
|
|
125
|
+
return this.exited ? { ...status, ready: false } : status;
|
|
125
126
|
}
|
|
126
127
|
async stop() {
|
|
127
128
|
if (!this.stopping) {
|
package/dist/setup-types.d.ts
CHANGED
|
@@ -146,6 +146,14 @@ export interface MountedWorkspaceHandle {
|
|
|
146
146
|
status(): Promise<MountedWorkspaceStatus>;
|
|
147
147
|
stop(): Promise<void>;
|
|
148
148
|
}
|
|
149
|
+
export interface MountSupervisorEvent {
|
|
150
|
+
type: "mount.refreshed" | "mount.refresh_failed";
|
|
151
|
+
workspaceId: string;
|
|
152
|
+
localDir: string;
|
|
153
|
+
attempt: number;
|
|
154
|
+
retryInMs?: number;
|
|
155
|
+
errorCode?: string;
|
|
156
|
+
}
|
|
149
157
|
export interface MountLauncherEvent {
|
|
150
158
|
type: string;
|
|
151
159
|
[key: string]: unknown;
|
|
@@ -186,6 +194,15 @@ export interface EnsureMountedWorkspaceInput extends MountWorkspaceInput {
|
|
|
186
194
|
provider?: WorkspaceIntegrationProvider;
|
|
187
195
|
verifyProvider?: boolean;
|
|
188
196
|
providerReadyTimeoutMs?: number;
|
|
197
|
+
/** Keep a background mount healthy and renew its short-lived session. Defaults to true. */
|
|
198
|
+
supervise?: boolean;
|
|
199
|
+
/** Health-check cadence for supervised background mounts. */
|
|
200
|
+
healthCheckIntervalMs?: number;
|
|
201
|
+
/** Initial retry delay after a supervised refresh failure. */
|
|
202
|
+
refreshRetryBaseMs?: number;
|
|
203
|
+
/** Maximum retry delay after repeated supervised refresh failures. */
|
|
204
|
+
refreshRetryMaxMs?: number;
|
|
205
|
+
onSupervisorEvent?: (event: MountSupervisorEvent) => void | Promise<void>;
|
|
189
206
|
}
|
|
190
207
|
export interface AgentWorkspaceInviteOptions {
|
|
191
208
|
agentName?: string;
|
package/dist/setup.d.ts
CHANGED
|
@@ -42,6 +42,7 @@ export declare class RelayfileSetup {
|
|
|
42
42
|
private readonly accessToken?;
|
|
43
43
|
private readonly requestTimeoutMs;
|
|
44
44
|
private readonly retryOptions;
|
|
45
|
+
private readonly ensuredMounts;
|
|
45
46
|
static login(options?: RelayfileCloudLoginOptions): Promise<RelayfileSetup>;
|
|
46
47
|
static fromCloudTokens(tokens: RelayfileCloudTokenSet, options?: RelayfileCloudTokenSetupOptions): RelayfileSetup;
|
|
47
48
|
constructor(options?: RelayfileSetupOptions);
|
|
@@ -49,6 +50,7 @@ export declare class RelayfileSetup {
|
|
|
49
50
|
joinWorkspace(workspaceId: string, options?: JoinWorkspaceOptions): Promise<WorkspaceHandle>;
|
|
50
51
|
mountWorkspace(input: MountWorkspaceInput): Promise<MountedWorkspaceHandle>;
|
|
51
52
|
ensureMountedWorkspace(input: EnsureMountedWorkspaceInput): Promise<MountedWorkspaceHandle>;
|
|
53
|
+
private startEnsuredMount;
|
|
52
54
|
joinWorkspaceResponse(workspaceId: string, options: NormalizedJoinWorkspaceOptions, overrides?: {
|
|
53
55
|
tokenProvider?: AccessTokenProvider;
|
|
54
56
|
}): Promise<ValidatedJoinWorkspaceResponse>;
|
package/dist/setup.js
CHANGED
|
@@ -18,6 +18,9 @@ const DEFAULT_MOUNT_READY_TIMEOUT_MS = 60_000;
|
|
|
18
18
|
const DEFAULT_MOUNT_AGENT_NAME = "relayfile-mount";
|
|
19
19
|
const DEFAULT_MOUNT_LOCAL_LAYOUT = "exact";
|
|
20
20
|
const DEFAULT_MOUNT_SYNC_MODE = "mirror";
|
|
21
|
+
const DEFAULT_MOUNT_HEALTH_INTERVAL_MS = 30_000;
|
|
22
|
+
const DEFAULT_MOUNT_REFRESH_RETRY_BASE_MS = 1_000;
|
|
23
|
+
const DEFAULT_MOUNT_REFRESH_RETRY_MAX_MS = 60_000;
|
|
21
24
|
const TOKEN_REFRESH_AGE_MS = 55 * 60 * 1000;
|
|
22
25
|
const nodeOnlyMountLauncher = {
|
|
23
26
|
async start() {
|
|
@@ -29,6 +32,7 @@ export class RelayfileSetup {
|
|
|
29
32
|
accessToken;
|
|
30
33
|
requestTimeoutMs;
|
|
31
34
|
retryOptions;
|
|
35
|
+
ensuredMounts = new Map();
|
|
32
36
|
static async login(options = {}) {
|
|
33
37
|
void options;
|
|
34
38
|
throw new RelayfileSetupError("RelayfileSetup.login() starts a local HTTP callback server and is only available from @relayfile/sdk/cli. Import RelayfileSetup from @relayfile/sdk/cli for interactive Cloud login.", "node_only_sdk_feature");
|
|
@@ -133,13 +137,42 @@ export class RelayfileSetup {
|
|
|
133
137
|
async ensureMountedWorkspace(input) {
|
|
134
138
|
const normalized = normalizeEnsureMountedWorkspaceInput(input);
|
|
135
139
|
const workspace = await this.resolveWorkspaceForMount(normalized);
|
|
140
|
+
throwIfAborted(normalized.signal, "ensureMountedWorkspace");
|
|
141
|
+
const mountKey = ensuredMountKey(workspace, normalized);
|
|
142
|
+
const existing = this.ensuredMounts.get(mountKey);
|
|
143
|
+
if (existing) {
|
|
144
|
+
return waitForEnsuredMount(existing, normalized.signal);
|
|
145
|
+
}
|
|
146
|
+
let shared;
|
|
147
|
+
// The physical mount belongs to the logical target, not the first caller.
|
|
148
|
+
// Individual abort signals only cancel that caller's wait below.
|
|
149
|
+
shared = this.startEnsuredMount(workspace, {
|
|
150
|
+
...normalized,
|
|
151
|
+
signal: undefined
|
|
152
|
+
}).then((mounted) => new SharedMountedWorkspaceHandle({
|
|
153
|
+
mounted,
|
|
154
|
+
onStopped: () => {
|
|
155
|
+
if (this.ensuredMounts.get(mountKey) === shared) {
|
|
156
|
+
this.ensuredMounts.delete(mountKey);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}));
|
|
160
|
+
this.ensuredMounts.set(mountKey, shared);
|
|
161
|
+
void shared.catch(() => {
|
|
162
|
+
if (this.ensuredMounts.get(mountKey) === shared) {
|
|
163
|
+
this.ensuredMounts.delete(mountKey);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
return waitForEnsuredMount(shared, normalized.signal);
|
|
167
|
+
}
|
|
168
|
+
async startEnsuredMount(workspace, normalized) {
|
|
136
169
|
if (normalized.verifyProvider) {
|
|
137
170
|
if (!normalized.provider) {
|
|
138
171
|
throw new MountSessionInputError("provider required when verifyProvider=true");
|
|
139
172
|
}
|
|
140
173
|
await verifyWorkspaceProviderReady(workspace, normalized.provider, normalized.providerReadyTimeoutMs, normalized.signal);
|
|
141
174
|
}
|
|
142
|
-
|
|
175
|
+
const mountInput = {
|
|
143
176
|
workspace,
|
|
144
177
|
localDir: normalized.localDir,
|
|
145
178
|
remotePath: normalized.remotePath,
|
|
@@ -152,6 +185,19 @@ export class RelayfileSetup {
|
|
|
152
185
|
signal: normalized.signal,
|
|
153
186
|
launcher: normalized.launcher,
|
|
154
187
|
readyTimeoutMs: normalized.readyTimeoutMs
|
|
188
|
+
};
|
|
189
|
+
const mounted = await this.mountWorkspace(mountInput);
|
|
190
|
+
if (!normalized.supervise || !normalized.background) {
|
|
191
|
+
return mounted;
|
|
192
|
+
}
|
|
193
|
+
return new SupervisedMountedWorkspaceHandle({
|
|
194
|
+
mounted,
|
|
195
|
+
launch: () => this.mountWorkspace(mountInput),
|
|
196
|
+
healthCheckIntervalMs: normalized.healthCheckIntervalMs,
|
|
197
|
+
refreshRetryBaseMs: normalized.refreshRetryBaseMs,
|
|
198
|
+
refreshRetryMaxMs: normalized.refreshRetryMaxMs,
|
|
199
|
+
onEvent: normalized.onSupervisorEvent,
|
|
200
|
+
signal: normalized.signal
|
|
155
201
|
});
|
|
156
202
|
}
|
|
157
203
|
async joinWorkspaceResponse(workspaceId, options, overrides = {}) {
|
|
@@ -758,12 +804,256 @@ class MountedWorkspaceHandleImpl {
|
|
|
758
804
|
await this.stopPromise;
|
|
759
805
|
}
|
|
760
806
|
async performStop() {
|
|
807
|
+
this.readySnapshot = false;
|
|
761
808
|
if (this.probeOnly || !this.launcherInstance) {
|
|
762
809
|
return;
|
|
763
810
|
}
|
|
764
811
|
await safeStopLauncher(this.launcherInstance);
|
|
765
812
|
}
|
|
766
813
|
}
|
|
814
|
+
class SharedMountedWorkspaceHandle {
|
|
815
|
+
mounted;
|
|
816
|
+
onStopped;
|
|
817
|
+
stopPromise;
|
|
818
|
+
constructor(input) {
|
|
819
|
+
this.mounted = input.mounted;
|
|
820
|
+
this.onStopped = input.onStopped;
|
|
821
|
+
}
|
|
822
|
+
get workspaceId() {
|
|
823
|
+
return this.mounted.workspaceId;
|
|
824
|
+
}
|
|
825
|
+
get localDir() {
|
|
826
|
+
return this.mounted.localDir;
|
|
827
|
+
}
|
|
828
|
+
get remotePath() {
|
|
829
|
+
return this.mounted.remotePath;
|
|
830
|
+
}
|
|
831
|
+
get mode() {
|
|
832
|
+
return this.mounted.mode;
|
|
833
|
+
}
|
|
834
|
+
get ready() {
|
|
835
|
+
return this.mounted.ready;
|
|
836
|
+
}
|
|
837
|
+
get expiresAt() {
|
|
838
|
+
return this.mounted.expiresAt;
|
|
839
|
+
}
|
|
840
|
+
get suggestedRefreshAt() {
|
|
841
|
+
return this.mounted.suggestedRefreshAt;
|
|
842
|
+
}
|
|
843
|
+
env() {
|
|
844
|
+
return this.mounted.env();
|
|
845
|
+
}
|
|
846
|
+
status() {
|
|
847
|
+
return this.mounted.status();
|
|
848
|
+
}
|
|
849
|
+
async stop() {
|
|
850
|
+
if (!this.stopPromise)
|
|
851
|
+
this.stopPromise = this.performStop();
|
|
852
|
+
await this.stopPromise;
|
|
853
|
+
}
|
|
854
|
+
async performStop() {
|
|
855
|
+
try {
|
|
856
|
+
await this.mounted.stop();
|
|
857
|
+
}
|
|
858
|
+
finally {
|
|
859
|
+
this.onStopped();
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
class SupervisedMountedWorkspaceHandle {
|
|
864
|
+
mounted;
|
|
865
|
+
launch;
|
|
866
|
+
healthCheckIntervalMs;
|
|
867
|
+
refreshRetryBaseMs;
|
|
868
|
+
refreshRetryMaxMs;
|
|
869
|
+
onEvent;
|
|
870
|
+
signal;
|
|
871
|
+
timer;
|
|
872
|
+
refreshPromise;
|
|
873
|
+
stopPromise;
|
|
874
|
+
stopped = false;
|
|
875
|
+
supervisorReady = true;
|
|
876
|
+
refreshAttempts = 0;
|
|
877
|
+
constructor(input) {
|
|
878
|
+
this.mounted = input.mounted;
|
|
879
|
+
this.launch = input.launch;
|
|
880
|
+
this.healthCheckIntervalMs = input.healthCheckIntervalMs;
|
|
881
|
+
this.refreshRetryBaseMs = input.refreshRetryBaseMs;
|
|
882
|
+
this.refreshRetryMaxMs = input.refreshRetryMaxMs;
|
|
883
|
+
this.onEvent = input.onEvent;
|
|
884
|
+
this.signal = input.signal;
|
|
885
|
+
if (this.signal?.aborted) {
|
|
886
|
+
this.handleAbort();
|
|
887
|
+
}
|
|
888
|
+
else {
|
|
889
|
+
this.signal?.addEventListener("abort", this.handleAbort, { once: true });
|
|
890
|
+
this.schedule();
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
get workspaceId() {
|
|
894
|
+
return this.mounted.workspaceId;
|
|
895
|
+
}
|
|
896
|
+
get localDir() {
|
|
897
|
+
return this.mounted.localDir;
|
|
898
|
+
}
|
|
899
|
+
get remotePath() {
|
|
900
|
+
return this.mounted.remotePath;
|
|
901
|
+
}
|
|
902
|
+
get mode() {
|
|
903
|
+
return this.mounted.mode;
|
|
904
|
+
}
|
|
905
|
+
get ready() {
|
|
906
|
+
return !this.stopped && this.supervisorReady && this.mounted.ready;
|
|
907
|
+
}
|
|
908
|
+
get expiresAt() {
|
|
909
|
+
return this.mounted.expiresAt;
|
|
910
|
+
}
|
|
911
|
+
get suggestedRefreshAt() {
|
|
912
|
+
return this.mounted.suggestedRefreshAt;
|
|
913
|
+
}
|
|
914
|
+
env() {
|
|
915
|
+
return this.mounted.env();
|
|
916
|
+
}
|
|
917
|
+
async status() {
|
|
918
|
+
const status = await this.mounted.status();
|
|
919
|
+
return {
|
|
920
|
+
...status,
|
|
921
|
+
ready: !this.stopped && this.supervisorReady && status.ready,
|
|
922
|
+
expiresAt: this.expiresAt,
|
|
923
|
+
suggestedRefreshAt: this.suggestedRefreshAt
|
|
924
|
+
};
|
|
925
|
+
}
|
|
926
|
+
async stop() {
|
|
927
|
+
if (!this.stopPromise)
|
|
928
|
+
this.stopPromise = this.performStop();
|
|
929
|
+
await this.stopPromise;
|
|
930
|
+
}
|
|
931
|
+
async performStop() {
|
|
932
|
+
this.stopped = true;
|
|
933
|
+
this.supervisorReady = false;
|
|
934
|
+
this.signal?.removeEventListener("abort", this.handleAbort);
|
|
935
|
+
if (this.timer)
|
|
936
|
+
clearTimeout(this.timer);
|
|
937
|
+
this.timer = undefined;
|
|
938
|
+
await this.refreshPromise?.catch(() => { });
|
|
939
|
+
await this.mounted.stop();
|
|
940
|
+
}
|
|
941
|
+
handleAbort = () => {
|
|
942
|
+
void this.stop();
|
|
943
|
+
};
|
|
944
|
+
schedule(delayOverrideMs) {
|
|
945
|
+
if (this.stopped || this.timer)
|
|
946
|
+
return;
|
|
947
|
+
const suggestedRefreshAtMs = Date.parse(this.mounted.suggestedRefreshAt ?? "");
|
|
948
|
+
const untilRefresh = Number.isFinite(suggestedRefreshAtMs)
|
|
949
|
+
? Math.max(0, suggestedRefreshAtMs - Date.now())
|
|
950
|
+
: this.healthCheckIntervalMs;
|
|
951
|
+
const delayMs = delayOverrideMs ?? Math.min(this.healthCheckIntervalMs, untilRefresh);
|
|
952
|
+
this.timer = setTimeout(() => {
|
|
953
|
+
this.timer = undefined;
|
|
954
|
+
this.refreshPromise = this.checkAndRefresh().finally(() => {
|
|
955
|
+
this.refreshPromise = undefined;
|
|
956
|
+
});
|
|
957
|
+
}, Math.max(1_000, delayMs));
|
|
958
|
+
this.timer.unref?.();
|
|
959
|
+
}
|
|
960
|
+
async checkAndRefresh() {
|
|
961
|
+
if (this.stopped)
|
|
962
|
+
return;
|
|
963
|
+
try {
|
|
964
|
+
const suggestedRefreshAtMs = Date.parse(this.mounted.suggestedRefreshAt ?? "");
|
|
965
|
+
const refreshDue = Number.isFinite(suggestedRefreshAtMs) && Date.now() >= suggestedRefreshAtMs;
|
|
966
|
+
if (!refreshDue) {
|
|
967
|
+
const status = await this.mounted.status();
|
|
968
|
+
if (status.ready) {
|
|
969
|
+
this.supervisorReady = true;
|
|
970
|
+
this.refreshAttempts = 0;
|
|
971
|
+
this.schedule();
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
await this.replaceMount();
|
|
976
|
+
if (this.stopped)
|
|
977
|
+
return;
|
|
978
|
+
this.supervisorReady = true;
|
|
979
|
+
this.refreshAttempts = 0;
|
|
980
|
+
this.emit({
|
|
981
|
+
type: "mount.refreshed",
|
|
982
|
+
workspaceId: this.workspaceId,
|
|
983
|
+
localDir: this.localDir,
|
|
984
|
+
attempt: 0
|
|
985
|
+
});
|
|
986
|
+
this.schedule();
|
|
987
|
+
}
|
|
988
|
+
catch (error) {
|
|
989
|
+
if (this.stopped)
|
|
990
|
+
return;
|
|
991
|
+
this.supervisorReady = false;
|
|
992
|
+
this.refreshAttempts += 1;
|
|
993
|
+
const retryInMs = Math.min(this.refreshRetryMaxMs, this.refreshRetryBaseMs * 2 ** (this.refreshAttempts - 1));
|
|
994
|
+
this.emit({
|
|
995
|
+
type: "mount.refresh_failed",
|
|
996
|
+
workspaceId: this.workspaceId,
|
|
997
|
+
localDir: this.localDir,
|
|
998
|
+
attempt: this.refreshAttempts,
|
|
999
|
+
retryInMs,
|
|
1000
|
+
errorCode: setupErrorCode(error)
|
|
1001
|
+
});
|
|
1002
|
+
this.schedule(retryInMs);
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
async replaceMount() {
|
|
1006
|
+
const previous = this.mounted;
|
|
1007
|
+
if (this.stopped)
|
|
1008
|
+
return;
|
|
1009
|
+
await previous.stop().catch(() => { });
|
|
1010
|
+
if (this.stopped)
|
|
1011
|
+
return;
|
|
1012
|
+
const replacement = await this.launch();
|
|
1013
|
+
if (this.stopped) {
|
|
1014
|
+
await replacement.stop().catch(() => { });
|
|
1015
|
+
return;
|
|
1016
|
+
}
|
|
1017
|
+
this.mounted = replacement;
|
|
1018
|
+
}
|
|
1019
|
+
emit(event) {
|
|
1020
|
+
void Promise.resolve(this.onEvent?.(event)).catch(() => { });
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
function ensuredMountKey(workspace, input) {
|
|
1024
|
+
return JSON.stringify([
|
|
1025
|
+
workspace.workspaceId,
|
|
1026
|
+
input.localDir,
|
|
1027
|
+
input.remotePath,
|
|
1028
|
+
input.mode,
|
|
1029
|
+
input.localLayout,
|
|
1030
|
+
input.syncMode,
|
|
1031
|
+
input.background
|
|
1032
|
+
]);
|
|
1033
|
+
}
|
|
1034
|
+
async function waitForEnsuredMount(mounted, signal) {
|
|
1035
|
+
if (!signal)
|
|
1036
|
+
return mounted;
|
|
1037
|
+
if (signal.aborted)
|
|
1038
|
+
throw new CloudAbortError("ensureMountedWorkspace");
|
|
1039
|
+
let onAbort;
|
|
1040
|
+
try {
|
|
1041
|
+
return await Promise.race([
|
|
1042
|
+
mounted,
|
|
1043
|
+
new Promise((_, reject) => {
|
|
1044
|
+
onAbort = () => reject(new CloudAbortError("ensureMountedWorkspace"));
|
|
1045
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
1046
|
+
})
|
|
1047
|
+
]);
|
|
1048
|
+
}
|
|
1049
|
+
finally {
|
|
1050
|
+
if (onAbort)
|
|
1051
|
+
signal.removeEventListener("abort", onAbort);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
function setupErrorCode(error) {
|
|
1055
|
+
return error instanceof RelayfileSetupError ? error.code : "mount_refresh_failed";
|
|
1056
|
+
}
|
|
767
1057
|
// The metadata + accessible-resources verbs accept `WorkspaceIntegrationProvider | string`
|
|
768
1058
|
// so operators can target dynamically-discovered providers (Composio toolkit
|
|
769
1059
|
// slugs, future Atlassian-family additions) without an SDK release. We still
|
|
@@ -959,9 +1249,19 @@ function normalizeEnsureMountedWorkspaceInput(input) {
|
|
|
959
1249
|
...normalized,
|
|
960
1250
|
provider: input.provider,
|
|
961
1251
|
verifyProvider: input.verifyProvider !== false,
|
|
962
|
-
providerReadyTimeoutMs: Math.max(0, Math.floor(input.providerReadyTimeoutMs ?? 0))
|
|
1252
|
+
providerReadyTimeoutMs: Math.max(0, Math.floor(input.providerReadyTimeoutMs ?? 0)),
|
|
1253
|
+
supervise: input.supervise !== false && normalized.background,
|
|
1254
|
+
healthCheckIntervalMs: positiveInterval(input.healthCheckIntervalMs, DEFAULT_MOUNT_HEALTH_INTERVAL_MS),
|
|
1255
|
+
refreshRetryBaseMs: positiveInterval(input.refreshRetryBaseMs, DEFAULT_MOUNT_REFRESH_RETRY_BASE_MS),
|
|
1256
|
+
refreshRetryMaxMs: positiveInterval(input.refreshRetryMaxMs, DEFAULT_MOUNT_REFRESH_RETRY_MAX_MS),
|
|
1257
|
+
onSupervisorEvent: input.onSupervisorEvent
|
|
963
1258
|
};
|
|
964
1259
|
}
|
|
1260
|
+
function positiveInterval(value, fallback) {
|
|
1261
|
+
if (value === undefined || !Number.isFinite(value) || value <= 0)
|
|
1262
|
+
return fallback;
|
|
1263
|
+
return Math.max(1_000, Math.floor(value));
|
|
1264
|
+
}
|
|
965
1265
|
function normalizeMountModeInput(mode) {
|
|
966
1266
|
const normalized = normalizeNonEmptyString(mode) ?? "poll";
|
|
967
1267
|
if (normalized !== "poll" && normalized !== "fuse") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@relayfile/sdk",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.33",
|
|
4
4
|
"description": "TypeScript SDK for relayfile — real-time filesystem for humans and agents",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -59,15 +59,15 @@
|
|
|
59
59
|
"prepublishOnly": "npm run build"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@relayfile/core": "0.10.
|
|
62
|
+
"@relayfile/core": "0.10.33",
|
|
63
63
|
"ignore": "^7.0.5",
|
|
64
64
|
"tar": "^7.5.10"
|
|
65
65
|
},
|
|
66
66
|
"optionalDependencies": {
|
|
67
|
-
"@relayfile/mount-darwin-arm64": "0.10.
|
|
68
|
-
"@relayfile/mount-darwin-x64": "0.10.
|
|
69
|
-
"@relayfile/mount-linux-arm64": "0.10.
|
|
70
|
-
"@relayfile/mount-linux-x64": "0.10.
|
|
67
|
+
"@relayfile/mount-darwin-arm64": "0.10.33",
|
|
68
|
+
"@relayfile/mount-darwin-x64": "0.10.33",
|
|
69
|
+
"@relayfile/mount-linux-arm64": "0.10.33",
|
|
70
|
+
"@relayfile/mount-linux-x64": "0.10.33"
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
73
|
"typescript": "^5.7.3",
|