@relayfile/sdk 0.10.32 → 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/setup.d.ts +2 -0
- package/dist/setup.js +110 -0
- package/package.json +6 -6
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
|
@@ -32,6 +32,7 @@ export class RelayfileSetup {
|
|
|
32
32
|
accessToken;
|
|
33
33
|
requestTimeoutMs;
|
|
34
34
|
retryOptions;
|
|
35
|
+
ensuredMounts = new Map();
|
|
35
36
|
static async login(options = {}) {
|
|
36
37
|
void options;
|
|
37
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");
|
|
@@ -136,6 +137,35 @@ export class RelayfileSetup {
|
|
|
136
137
|
async ensureMountedWorkspace(input) {
|
|
137
138
|
const normalized = normalizeEnsureMountedWorkspaceInput(input);
|
|
138
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) {
|
|
139
169
|
if (normalized.verifyProvider) {
|
|
140
170
|
if (!normalized.provider) {
|
|
141
171
|
throw new MountSessionInputError("provider required when verifyProvider=true");
|
|
@@ -781,6 +811,55 @@ class MountedWorkspaceHandleImpl {
|
|
|
781
811
|
await safeStopLauncher(this.launcherInstance);
|
|
782
812
|
}
|
|
783
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
|
+
}
|
|
784
863
|
class SupervisedMountedWorkspaceHandle {
|
|
785
864
|
mounted;
|
|
786
865
|
launch;
|
|
@@ -941,6 +1020,37 @@ class SupervisedMountedWorkspaceHandle {
|
|
|
941
1020
|
void Promise.resolve(this.onEvent?.(event)).catch(() => { });
|
|
942
1021
|
}
|
|
943
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
|
+
}
|
|
944
1054
|
function setupErrorCode(error) {
|
|
945
1055
|
return error instanceof RelayfileSetupError ? error.code : "mount_refresh_failed";
|
|
946
1056
|
}
|
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",
|