@relayfile/sdk 0.9.6 → 0.10.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/client.d.ts +7 -1
- package/dist/client.js +110 -4
- package/dist/index.d.ts +1 -0
- package/dist/types.d.ts +6 -0
- package/package.json +6 -6
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AdminIngressStatusResponse, type AdminSyncStatusResponse, type BulkWriteInput, type BulkWriteResponse, type BackendStatusResponse, type AckResponse, type CommitForkInput, type CommitForkResponse, type CreateForkInput, type DeleteFileInput, type DeadLetterItem, type DeadLetterFeedResponse, type DeleteWebhookOptions, type DiscardForkInput, type EventFeedResponse, type ExportJsonResponse, type ExportOptions, type FileQueryResponse, type FileReadResponse, type FilesystemEvent, type GetEventsOptions, type GetAdminIngressStatusOptions, type GetAdminSyncStatusOptions, type GetOperationsOptions, type GetSyncDeadLettersOptions, type GetSyncIngressStatusOptions, type GetSyncStatusOptions, type GetWebhookDeadLettersOptions, type ListWebhooksOptions, type ListTreeOptions, type OperationFeedResponse, type OperationStatusResponse, type QueuedResponse, type ResourceAtEventResult, type ReadFileInput, type QueryFilesOptions, type RegisterWebhookInput, type RegisterWebhookResponse, type Subscription, type SyncIngressStatusResponse, type SyncStatusResponse, type TreeResponse, type WriteFileInput, type WriteQueuedResponse, type IngestWebhookInput, type WritebackItem, type WebhookDeliveryDeadLetterFeedResponse, type WebhookSubscription, type AckWritebackInput, type AckWritebackResponse, type SweepWritebackDraftsInput, type SweepWritebackDraftsResponse, type ChangeEvent, type ChangeLogQueryResult, type ChangeStreamConnection, type ChangeStreamConnectionOptions, type SubscribeOptions } from "./types.js";
|
|
1
|
+
import { type AdminIngressStatusResponse, type AdminSyncStatusResponse, type BulkWriteInput, type BulkWriteResponse, type BackendStatusResponse, type AckResponse, type CommitForkInput, type CommitForkResponse, type CreateForkInput, type DeleteFileInput, type DeadLetterItem, type DeadLetterFeedResponse, type DeleteWebhookOptions, type DiscardForkInput, type EventFeedResponse, type ExportJsonResponse, type ExportOptions, type FileQueryResponse, type FileReadResponse, type FilesystemEvent, type GetEventsOptions, type GetAdminIngressStatusOptions, type GetAdminSyncStatusOptions, type GetOperationsOptions, type GetSyncDeadLettersOptions, type GetSyncIngressStatusOptions, type GetSyncStatusOptions, type GetWebhookDeadLettersOptions, type ListWebhooksOptions, type ListTreeOptions, type OperationFeedResponse, type OperationStatusResponse, type QueuedResponse, type ResourceAtEventResult, type ReadFileInput, type QueryFilesOptions, type RegisterWebhookInput, type RegisterWebhookResponse, type RelayFileReadCacheOptions, type Subscription, type SyncIngressStatusResponse, type SyncStatusResponse, type TreeResponse, type WriteFileInput, type WriteQueuedResponse, type IngestWebhookInput, type WritebackItem, type WebhookDeliveryDeadLetterFeedResponse, type WebhookSubscription, type AckWritebackInput, type AckWritebackResponse, type SweepWritebackDraftsInput, type SweepWritebackDraftsResponse, type ChangeEvent, type ChangeLogQueryResult, type ChangeStreamConnection, type ChangeStreamConnectionOptions, type SubscribeOptions } from "./types.js";
|
|
2
2
|
import type { ForkHandle } from "@relayfile/core";
|
|
3
3
|
/**
|
|
4
4
|
* Bearer token or token factory used for Relayfile API requests.
|
|
@@ -41,6 +41,12 @@ export interface RelayFileClientOptions {
|
|
|
41
41
|
userAgent?: string;
|
|
42
42
|
retry?: RelayFileRetryOptions;
|
|
43
43
|
changeLog?: RelayFileChangeLogOptions;
|
|
44
|
+
/**
|
|
45
|
+
* Client-side file read cache with in-flight deduplication.
|
|
46
|
+
* Enabled by default. Set to `false` to disable.
|
|
47
|
+
* Active change streams automatically evict paths on remote mutations.
|
|
48
|
+
*/
|
|
49
|
+
readCache?: false | RelayFileReadCacheOptions;
|
|
44
50
|
}
|
|
45
51
|
type WebSocketEventName = "event" | "error" | "open" | "close";
|
|
46
52
|
type WebSocketHandlerMap = {
|
package/dist/client.js
CHANGED
|
@@ -17,6 +17,72 @@ const changeStreamManagers = new WeakMap();
|
|
|
17
17
|
const changeLogCaches = new WeakMap();
|
|
18
18
|
const changeLogSettings = new WeakMap();
|
|
19
19
|
const pendingChangeHydrations = new WeakMap();
|
|
20
|
+
const fileReadCaches = new WeakMap();
|
|
21
|
+
const DEFAULT_READ_CACHE_TTL_MS = 5_000;
|
|
22
|
+
const DEFAULT_READ_CACHE_MAX_ENTRIES = 500;
|
|
23
|
+
class FileReadCache {
|
|
24
|
+
ttlMs;
|
|
25
|
+
maxEntries;
|
|
26
|
+
entries = new Map();
|
|
27
|
+
inFlight = new Map();
|
|
28
|
+
constructor(options) {
|
|
29
|
+
this.ttlMs = options?.ttlMs ?? DEFAULT_READ_CACHE_TTL_MS;
|
|
30
|
+
this.maxEntries = options?.maxEntries ?? DEFAULT_READ_CACHE_MAX_ENTRIES;
|
|
31
|
+
}
|
|
32
|
+
get(key) {
|
|
33
|
+
const entry = this.entries.get(key);
|
|
34
|
+
if (!entry)
|
|
35
|
+
return undefined;
|
|
36
|
+
if (Date.now() > entry.expiresAt) {
|
|
37
|
+
this.entries.delete(key);
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
return entry.value;
|
|
41
|
+
}
|
|
42
|
+
set(key, value) {
|
|
43
|
+
if (this.entries.size >= this.maxEntries && !this.entries.has(key)) {
|
|
44
|
+
const oldest = this.entries.keys().next().value;
|
|
45
|
+
if (oldest !== undefined) {
|
|
46
|
+
this.entries.delete(oldest);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
this.entries.set(key, { value, expiresAt: Date.now() + this.ttlMs });
|
|
50
|
+
}
|
|
51
|
+
evict(workspaceId, path) {
|
|
52
|
+
this.entries.delete(`${workspaceId}:${path}`);
|
|
53
|
+
this.inFlight.delete(`${workspaceId}:${path}`);
|
|
54
|
+
}
|
|
55
|
+
getInFlight(key) {
|
|
56
|
+
return this.inFlight.get(key);
|
|
57
|
+
}
|
|
58
|
+
setInFlight(key, promise) {
|
|
59
|
+
this.inFlight.set(key, promise);
|
|
60
|
+
promise.then((result) => {
|
|
61
|
+
if (this.inFlight.get(key) === promise) {
|
|
62
|
+
this.inFlight.delete(key);
|
|
63
|
+
this.set(key, result);
|
|
64
|
+
}
|
|
65
|
+
}, () => {
|
|
66
|
+
if (this.inFlight.get(key) === promise) {
|
|
67
|
+
this.inFlight.delete(key);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function getFileReadCache(client) {
|
|
73
|
+
const cached = fileReadCaches.get(client);
|
|
74
|
+
if (cached !== undefined)
|
|
75
|
+
return cached;
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
function initFileReadCache(client, options) {
|
|
79
|
+
if (options.readCache === false) {
|
|
80
|
+
fileReadCaches.set(client, false);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
fileReadCaches.set(client, new FileReadCache(options.readCache));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
20
86
|
function createM2NotImplementedError(feature) {
|
|
21
87
|
const error = new Error(`M2_NOT_IMPLEMENTED: ${feature} is reserved for proactive runtime M2.`);
|
|
22
88
|
error.name = "M2NotImplementedError";
|
|
@@ -473,6 +539,14 @@ class RelayFileChangeStreamManager {
|
|
|
473
539
|
}
|
|
474
540
|
});
|
|
475
541
|
sync.on("event", (event) => {
|
|
542
|
+
// Evict the cached read when the server signals a mutation so stale
|
|
543
|
+
// content is never returned after a change event arrives.
|
|
544
|
+
if (event.type === "file.updated" || event.type === "file.created" || event.type === "file.deleted") {
|
|
545
|
+
const cacheOrFalse = getFileReadCache(this.client);
|
|
546
|
+
if (cacheOrFalse !== false) {
|
|
547
|
+
cacheOrFalse.evict(this.workspaceId, event.path);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
476
550
|
for (const subscription of this.subscriptions) {
|
|
477
551
|
subscription.push(event);
|
|
478
552
|
}
|
|
@@ -1037,6 +1111,7 @@ export class RelayFileClient {
|
|
|
1037
1111
|
this.userAgent = options.userAgent;
|
|
1038
1112
|
this.retryOptions = normalizeRetryOptions(options.retry);
|
|
1039
1113
|
changeLogSettings.set(this, normalizeChangeLogOptions(options.changeLog));
|
|
1114
|
+
initFileReadCache(this, options);
|
|
1040
1115
|
}
|
|
1041
1116
|
/**
|
|
1042
1117
|
* Resolve the current access token via the configured token provider.
|
|
@@ -1085,14 +1160,30 @@ export class RelayFileClient {
|
|
|
1085
1160
|
signal
|
|
1086
1161
|
}
|
|
1087
1162
|
: workspaceOrInput;
|
|
1163
|
+
const cacheRaw = getFileReadCache(this);
|
|
1164
|
+
// Skip cache for fork-scoped reads (isolated state) and when cache is disabled.
|
|
1165
|
+
const cache = cacheRaw !== false ? cacheRaw : undefined;
|
|
1166
|
+
const cacheKey = (cache && !input.forkId) ? `${input.workspaceId}:${input.path}` : undefined;
|
|
1167
|
+
if (cache && cacheKey) {
|
|
1168
|
+
const hit = cache.get(cacheKey);
|
|
1169
|
+
if (hit)
|
|
1170
|
+
return hit;
|
|
1171
|
+
const pending = cache.getInFlight(cacheKey);
|
|
1172
|
+
if (pending)
|
|
1173
|
+
return pending;
|
|
1174
|
+
}
|
|
1088
1175
|
const query = buildQuery({ path: input.path, forkId: input.forkId });
|
|
1089
|
-
|
|
1176
|
+
const fetch = this.request({
|
|
1090
1177
|
method: "GET",
|
|
1091
1178
|
path: `/v1/workspaces/${encodeURIComponent(input.workspaceId)}/fs/file${query}`,
|
|
1092
1179
|
correlationId: input.correlationId,
|
|
1093
1180
|
signal: input.signal,
|
|
1094
1181
|
tokenOverride: input.token
|
|
1095
1182
|
});
|
|
1183
|
+
if (cache && cacheKey) {
|
|
1184
|
+
cache.setInFlight(cacheKey, fetch);
|
|
1185
|
+
}
|
|
1186
|
+
return fetch;
|
|
1096
1187
|
}
|
|
1097
1188
|
async queryFiles(workspaceId, options = {}) {
|
|
1098
1189
|
const params = new URLSearchParams();
|
|
@@ -1131,7 +1222,7 @@ export class RelayFileClient {
|
|
|
1131
1222
|
async writeFile(input) {
|
|
1132
1223
|
const { workspaceId, path, correlationId, baseRevision, content, contentType, encoding, contentIdentity, signal } = input;
|
|
1133
1224
|
const query = buildQuery({ path, forkId: input.forkId });
|
|
1134
|
-
|
|
1225
|
+
const result = await this.request({
|
|
1135
1226
|
method: "PUT",
|
|
1136
1227
|
path: `/v1/workspaces/${encodeURIComponent(workspaceId)}/fs/file${query}`,
|
|
1137
1228
|
correlationId,
|
|
@@ -1148,6 +1239,10 @@ export class RelayFileClient {
|
|
|
1148
1239
|
},
|
|
1149
1240
|
signal
|
|
1150
1241
|
});
|
|
1242
|
+
const cache = getFileReadCache(this);
|
|
1243
|
+
if (cache !== false)
|
|
1244
|
+
cache.evict(workspaceId, path);
|
|
1245
|
+
return result;
|
|
1151
1246
|
}
|
|
1152
1247
|
async bulkWrite(input) {
|
|
1153
1248
|
const query = buildQuery({ forkId: input.forkId });
|
|
@@ -1160,11 +1255,18 @@ export class RelayFileClient {
|
|
|
1160
1255
|
},
|
|
1161
1256
|
signal: input.signal
|
|
1162
1257
|
});
|
|
1163
|
-
|
|
1258
|
+
const result = await this.readPayload(response);
|
|
1259
|
+
const cache = getFileReadCache(this);
|
|
1260
|
+
if (cache !== false) {
|
|
1261
|
+
for (const file of input.files) {
|
|
1262
|
+
cache.evict(input.workspaceId, file.path);
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
return result;
|
|
1164
1266
|
}
|
|
1165
1267
|
async deleteFile(input) {
|
|
1166
1268
|
const query = buildQuery({ path: input.path, forkId: input.forkId });
|
|
1167
|
-
|
|
1269
|
+
const result = await this.request({
|
|
1168
1270
|
method: "DELETE",
|
|
1169
1271
|
path: `/v1/workspaces/${encodeURIComponent(input.workspaceId)}/fs/file${query}`,
|
|
1170
1272
|
correlationId: input.correlationId,
|
|
@@ -1173,6 +1275,10 @@ export class RelayFileClient {
|
|
|
1173
1275
|
},
|
|
1174
1276
|
signal: input.signal
|
|
1175
1277
|
});
|
|
1278
|
+
const cache = getFileReadCache(this);
|
|
1279
|
+
if (cache !== false)
|
|
1280
|
+
cache.evict(input.workspaceId, input.path);
|
|
1281
|
+
return result;
|
|
1176
1282
|
}
|
|
1177
1283
|
async createFork(input) {
|
|
1178
1284
|
const body = {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { RelayFileClient, DEFAULT_RELAYFILE_BASE_URL, type AccessTokenProvider, type RelayFileChangeLogOptions, type ConnectWebSocketOptions, type RelayFileClientOptions, type RelayFileRetryOptions, type WebSocketConnection } from "./client.js";
|
|
2
|
+
export type { RelayFileReadCacheOptions } from "./types.js";
|
|
2
3
|
export { RelayfileSetup, RELAYFILE_SDK_VERSION, WorkspaceHandle } from "./setup.js";
|
|
3
4
|
export { type RelayfileCloudLoginOptions, type RelayfileCloudTokenSet, type RelayfileCloudTokenSetupOptions } from "./cloud-login.js";
|
|
4
5
|
export { CloudAbortError, CloudApiError, CloudTimeoutError, InvalidLocalDirError, InvalidMountModeError, InvalidRemotePathError, IntegrationConnectionTimeoutError, MalformedCloudResponseError, MissingConnectionIdError, MountModeUnavailableError, MountReadyTimeoutError, MountSessionInputError, ProviderNotConnectedError, ProviderNotReadyError, RelayfileSetupError, UnknownProviderError } from "./setup-errors.js";
|
package/dist/types.d.ts
CHANGED
|
@@ -56,6 +56,12 @@ export interface ContentIdentity {
|
|
|
56
56
|
key: string;
|
|
57
57
|
ttlSeconds?: number;
|
|
58
58
|
}
|
|
59
|
+
export interface RelayFileReadCacheOptions {
|
|
60
|
+
/** Cache TTL in ms. Default: 5000. */
|
|
61
|
+
ttlMs?: number;
|
|
62
|
+
/** Max cached entries before LRU eviction. Default: 500. */
|
|
63
|
+
maxEntries?: number;
|
|
64
|
+
}
|
|
59
65
|
export interface FileReadResponse {
|
|
60
66
|
path: string;
|
|
61
67
|
revision: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@relayfile/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1",
|
|
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.
|
|
62
|
+
"@relayfile/core": "0.10.1",
|
|
63
63
|
"ignore": "^7.0.5",
|
|
64
64
|
"tar": "^7.5.10"
|
|
65
65
|
},
|
|
66
66
|
"optionalDependencies": {
|
|
67
|
-
"@relayfile/mount-darwin-arm64": "0.
|
|
68
|
-
"@relayfile/mount-darwin-x64": "0.
|
|
69
|
-
"@relayfile/mount-linux-arm64": "0.
|
|
70
|
-
"@relayfile/mount-linux-x64": "0.
|
|
67
|
+
"@relayfile/mount-darwin-arm64": "0.10.1",
|
|
68
|
+
"@relayfile/mount-darwin-x64": "0.10.1",
|
|
69
|
+
"@relayfile/mount-linux-arm64": "0.10.1",
|
|
70
|
+
"@relayfile/mount-linux-x64": "0.10.1"
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
73
|
"typescript": "^5.7.3",
|