@relayfile/sdk 0.10.30 → 0.10.32
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.js +192 -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.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() {
|
|
@@ -139,7 +142,7 @@ export class RelayfileSetup {
|
|
|
139
142
|
}
|
|
140
143
|
await verifyWorkspaceProviderReady(workspace, normalized.provider, normalized.providerReadyTimeoutMs, normalized.signal);
|
|
141
144
|
}
|
|
142
|
-
|
|
145
|
+
const mountInput = {
|
|
143
146
|
workspace,
|
|
144
147
|
localDir: normalized.localDir,
|
|
145
148
|
remotePath: normalized.remotePath,
|
|
@@ -152,6 +155,19 @@ export class RelayfileSetup {
|
|
|
152
155
|
signal: normalized.signal,
|
|
153
156
|
launcher: normalized.launcher,
|
|
154
157
|
readyTimeoutMs: normalized.readyTimeoutMs
|
|
158
|
+
};
|
|
159
|
+
const mounted = await this.mountWorkspace(mountInput);
|
|
160
|
+
if (!normalized.supervise || !normalized.background) {
|
|
161
|
+
return mounted;
|
|
162
|
+
}
|
|
163
|
+
return new SupervisedMountedWorkspaceHandle({
|
|
164
|
+
mounted,
|
|
165
|
+
launch: () => this.mountWorkspace(mountInput),
|
|
166
|
+
healthCheckIntervalMs: normalized.healthCheckIntervalMs,
|
|
167
|
+
refreshRetryBaseMs: normalized.refreshRetryBaseMs,
|
|
168
|
+
refreshRetryMaxMs: normalized.refreshRetryMaxMs,
|
|
169
|
+
onEvent: normalized.onSupervisorEvent,
|
|
170
|
+
signal: normalized.signal
|
|
155
171
|
});
|
|
156
172
|
}
|
|
157
173
|
async joinWorkspaceResponse(workspaceId, options, overrides = {}) {
|
|
@@ -758,12 +774,176 @@ class MountedWorkspaceHandleImpl {
|
|
|
758
774
|
await this.stopPromise;
|
|
759
775
|
}
|
|
760
776
|
async performStop() {
|
|
777
|
+
this.readySnapshot = false;
|
|
761
778
|
if (this.probeOnly || !this.launcherInstance) {
|
|
762
779
|
return;
|
|
763
780
|
}
|
|
764
781
|
await safeStopLauncher(this.launcherInstance);
|
|
765
782
|
}
|
|
766
783
|
}
|
|
784
|
+
class SupervisedMountedWorkspaceHandle {
|
|
785
|
+
mounted;
|
|
786
|
+
launch;
|
|
787
|
+
healthCheckIntervalMs;
|
|
788
|
+
refreshRetryBaseMs;
|
|
789
|
+
refreshRetryMaxMs;
|
|
790
|
+
onEvent;
|
|
791
|
+
signal;
|
|
792
|
+
timer;
|
|
793
|
+
refreshPromise;
|
|
794
|
+
stopPromise;
|
|
795
|
+
stopped = false;
|
|
796
|
+
supervisorReady = true;
|
|
797
|
+
refreshAttempts = 0;
|
|
798
|
+
constructor(input) {
|
|
799
|
+
this.mounted = input.mounted;
|
|
800
|
+
this.launch = input.launch;
|
|
801
|
+
this.healthCheckIntervalMs = input.healthCheckIntervalMs;
|
|
802
|
+
this.refreshRetryBaseMs = input.refreshRetryBaseMs;
|
|
803
|
+
this.refreshRetryMaxMs = input.refreshRetryMaxMs;
|
|
804
|
+
this.onEvent = input.onEvent;
|
|
805
|
+
this.signal = input.signal;
|
|
806
|
+
if (this.signal?.aborted) {
|
|
807
|
+
this.handleAbort();
|
|
808
|
+
}
|
|
809
|
+
else {
|
|
810
|
+
this.signal?.addEventListener("abort", this.handleAbort, { once: true });
|
|
811
|
+
this.schedule();
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
get workspaceId() {
|
|
815
|
+
return this.mounted.workspaceId;
|
|
816
|
+
}
|
|
817
|
+
get localDir() {
|
|
818
|
+
return this.mounted.localDir;
|
|
819
|
+
}
|
|
820
|
+
get remotePath() {
|
|
821
|
+
return this.mounted.remotePath;
|
|
822
|
+
}
|
|
823
|
+
get mode() {
|
|
824
|
+
return this.mounted.mode;
|
|
825
|
+
}
|
|
826
|
+
get ready() {
|
|
827
|
+
return !this.stopped && this.supervisorReady && this.mounted.ready;
|
|
828
|
+
}
|
|
829
|
+
get expiresAt() {
|
|
830
|
+
return this.mounted.expiresAt;
|
|
831
|
+
}
|
|
832
|
+
get suggestedRefreshAt() {
|
|
833
|
+
return this.mounted.suggestedRefreshAt;
|
|
834
|
+
}
|
|
835
|
+
env() {
|
|
836
|
+
return this.mounted.env();
|
|
837
|
+
}
|
|
838
|
+
async status() {
|
|
839
|
+
const status = await this.mounted.status();
|
|
840
|
+
return {
|
|
841
|
+
...status,
|
|
842
|
+
ready: !this.stopped && this.supervisorReady && status.ready,
|
|
843
|
+
expiresAt: this.expiresAt,
|
|
844
|
+
suggestedRefreshAt: this.suggestedRefreshAt
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
async stop() {
|
|
848
|
+
if (!this.stopPromise)
|
|
849
|
+
this.stopPromise = this.performStop();
|
|
850
|
+
await this.stopPromise;
|
|
851
|
+
}
|
|
852
|
+
async performStop() {
|
|
853
|
+
this.stopped = true;
|
|
854
|
+
this.supervisorReady = false;
|
|
855
|
+
this.signal?.removeEventListener("abort", this.handleAbort);
|
|
856
|
+
if (this.timer)
|
|
857
|
+
clearTimeout(this.timer);
|
|
858
|
+
this.timer = undefined;
|
|
859
|
+
await this.refreshPromise?.catch(() => { });
|
|
860
|
+
await this.mounted.stop();
|
|
861
|
+
}
|
|
862
|
+
handleAbort = () => {
|
|
863
|
+
void this.stop();
|
|
864
|
+
};
|
|
865
|
+
schedule(delayOverrideMs) {
|
|
866
|
+
if (this.stopped || this.timer)
|
|
867
|
+
return;
|
|
868
|
+
const suggestedRefreshAtMs = Date.parse(this.mounted.suggestedRefreshAt ?? "");
|
|
869
|
+
const untilRefresh = Number.isFinite(suggestedRefreshAtMs)
|
|
870
|
+
? Math.max(0, suggestedRefreshAtMs - Date.now())
|
|
871
|
+
: this.healthCheckIntervalMs;
|
|
872
|
+
const delayMs = delayOverrideMs ?? Math.min(this.healthCheckIntervalMs, untilRefresh);
|
|
873
|
+
this.timer = setTimeout(() => {
|
|
874
|
+
this.timer = undefined;
|
|
875
|
+
this.refreshPromise = this.checkAndRefresh().finally(() => {
|
|
876
|
+
this.refreshPromise = undefined;
|
|
877
|
+
});
|
|
878
|
+
}, Math.max(1_000, delayMs));
|
|
879
|
+
this.timer.unref?.();
|
|
880
|
+
}
|
|
881
|
+
async checkAndRefresh() {
|
|
882
|
+
if (this.stopped)
|
|
883
|
+
return;
|
|
884
|
+
try {
|
|
885
|
+
const suggestedRefreshAtMs = Date.parse(this.mounted.suggestedRefreshAt ?? "");
|
|
886
|
+
const refreshDue = Number.isFinite(suggestedRefreshAtMs) && Date.now() >= suggestedRefreshAtMs;
|
|
887
|
+
if (!refreshDue) {
|
|
888
|
+
const status = await this.mounted.status();
|
|
889
|
+
if (status.ready) {
|
|
890
|
+
this.supervisorReady = true;
|
|
891
|
+
this.refreshAttempts = 0;
|
|
892
|
+
this.schedule();
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
await this.replaceMount();
|
|
897
|
+
if (this.stopped)
|
|
898
|
+
return;
|
|
899
|
+
this.supervisorReady = true;
|
|
900
|
+
this.refreshAttempts = 0;
|
|
901
|
+
this.emit({
|
|
902
|
+
type: "mount.refreshed",
|
|
903
|
+
workspaceId: this.workspaceId,
|
|
904
|
+
localDir: this.localDir,
|
|
905
|
+
attempt: 0
|
|
906
|
+
});
|
|
907
|
+
this.schedule();
|
|
908
|
+
}
|
|
909
|
+
catch (error) {
|
|
910
|
+
if (this.stopped)
|
|
911
|
+
return;
|
|
912
|
+
this.supervisorReady = false;
|
|
913
|
+
this.refreshAttempts += 1;
|
|
914
|
+
const retryInMs = Math.min(this.refreshRetryMaxMs, this.refreshRetryBaseMs * 2 ** (this.refreshAttempts - 1));
|
|
915
|
+
this.emit({
|
|
916
|
+
type: "mount.refresh_failed",
|
|
917
|
+
workspaceId: this.workspaceId,
|
|
918
|
+
localDir: this.localDir,
|
|
919
|
+
attempt: this.refreshAttempts,
|
|
920
|
+
retryInMs,
|
|
921
|
+
errorCode: setupErrorCode(error)
|
|
922
|
+
});
|
|
923
|
+
this.schedule(retryInMs);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
async replaceMount() {
|
|
927
|
+
const previous = this.mounted;
|
|
928
|
+
if (this.stopped)
|
|
929
|
+
return;
|
|
930
|
+
await previous.stop().catch(() => { });
|
|
931
|
+
if (this.stopped)
|
|
932
|
+
return;
|
|
933
|
+
const replacement = await this.launch();
|
|
934
|
+
if (this.stopped) {
|
|
935
|
+
await replacement.stop().catch(() => { });
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
this.mounted = replacement;
|
|
939
|
+
}
|
|
940
|
+
emit(event) {
|
|
941
|
+
void Promise.resolve(this.onEvent?.(event)).catch(() => { });
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
function setupErrorCode(error) {
|
|
945
|
+
return error instanceof RelayfileSetupError ? error.code : "mount_refresh_failed";
|
|
946
|
+
}
|
|
767
947
|
// The metadata + accessible-resources verbs accept `WorkspaceIntegrationProvider | string`
|
|
768
948
|
// so operators can target dynamically-discovered providers (Composio toolkit
|
|
769
949
|
// slugs, future Atlassian-family additions) without an SDK release. We still
|
|
@@ -959,9 +1139,19 @@ function normalizeEnsureMountedWorkspaceInput(input) {
|
|
|
959
1139
|
...normalized,
|
|
960
1140
|
provider: input.provider,
|
|
961
1141
|
verifyProvider: input.verifyProvider !== false,
|
|
962
|
-
providerReadyTimeoutMs: Math.max(0, Math.floor(input.providerReadyTimeoutMs ?? 0))
|
|
1142
|
+
providerReadyTimeoutMs: Math.max(0, Math.floor(input.providerReadyTimeoutMs ?? 0)),
|
|
1143
|
+
supervise: input.supervise !== false && normalized.background,
|
|
1144
|
+
healthCheckIntervalMs: positiveInterval(input.healthCheckIntervalMs, DEFAULT_MOUNT_HEALTH_INTERVAL_MS),
|
|
1145
|
+
refreshRetryBaseMs: positiveInterval(input.refreshRetryBaseMs, DEFAULT_MOUNT_REFRESH_RETRY_BASE_MS),
|
|
1146
|
+
refreshRetryMaxMs: positiveInterval(input.refreshRetryMaxMs, DEFAULT_MOUNT_REFRESH_RETRY_MAX_MS),
|
|
1147
|
+
onSupervisorEvent: input.onSupervisorEvent
|
|
963
1148
|
};
|
|
964
1149
|
}
|
|
1150
|
+
function positiveInterval(value, fallback) {
|
|
1151
|
+
if (value === undefined || !Number.isFinite(value) || value <= 0)
|
|
1152
|
+
return fallback;
|
|
1153
|
+
return Math.max(1_000, Math.floor(value));
|
|
1154
|
+
}
|
|
965
1155
|
function normalizeMountModeInput(mode) {
|
|
966
1156
|
const normalized = normalizeNonEmptyString(mode) ?? "poll";
|
|
967
1157
|
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.32",
|
|
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.32",
|
|
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.32",
|
|
68
|
+
"@relayfile/mount-darwin-x64": "0.10.32",
|
|
69
|
+
"@relayfile/mount-linux-arm64": "0.10.32",
|
|
70
|
+
"@relayfile/mount-linux-x64": "0.10.32"
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
73
|
"typescript": "^5.7.3",
|