@roamcode.ai/server 1.0.11 → 1.0.12
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.js +74 -31
- package/dist/start.js +74 -31
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2429,7 +2429,7 @@ async function installManagedRelease(opts) {
|
|
|
2429
2429
|
}
|
|
2430
2430
|
|
|
2431
2431
|
// src/updater.ts
|
|
2432
|
-
var RUNNING_VERSION = "1.0.
|
|
2432
|
+
var RUNNING_VERSION = "1.0.12" ? "1.0.12".replace(/^v/, "") : packageVersion();
|
|
2433
2433
|
var RUNNING_BUILD = RUNNING_VERSION;
|
|
2434
2434
|
var RELEASES_API = "https://api.github.com/repos/burakgon/roamcode/releases?per_page=100";
|
|
2435
2435
|
var RELEASE_MANIFEST_ASSET = "roamcode-release.json";
|
|
@@ -4908,6 +4908,24 @@ var IMAGE_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
4908
4908
|
"heic",
|
|
4909
4909
|
"heif"
|
|
4910
4910
|
]);
|
|
4911
|
+
var FILE_HISTORY_BACKFILL_BUDGET_MS = 150;
|
|
4912
|
+
var FILE_HISTORY_AVAILABILITY_BUDGET_MS = 150;
|
|
4913
|
+
function completionWithin(task, timeoutMs) {
|
|
4914
|
+
return new Promise((resolve7) => {
|
|
4915
|
+
let settled = false;
|
|
4916
|
+
const finish = (completed) => {
|
|
4917
|
+
if (settled) return;
|
|
4918
|
+
settled = true;
|
|
4919
|
+
clearTimeout(timer);
|
|
4920
|
+
resolve7(completed);
|
|
4921
|
+
};
|
|
4922
|
+
const timer = setTimeout(() => finish(false), timeoutMs);
|
|
4923
|
+
void task.then(
|
|
4924
|
+
() => finish(true),
|
|
4925
|
+
() => finish(false)
|
|
4926
|
+
);
|
|
4927
|
+
});
|
|
4928
|
+
}
|
|
4911
4929
|
function attachmentMedia(filename, declared = "application/octet-stream") {
|
|
4912
4930
|
const ext = filename.includes(".") ? filename.slice(filename.lastIndexOf(".") + 1).toLowerCase() : "";
|
|
4913
4931
|
if (declared.startsWith("image/") || IMAGE_FILE_EXTENSIONS.has(ext)) {
|
|
@@ -4979,34 +4997,59 @@ function createServer(config, deps = {}) {
|
|
|
4979
4997
|
const fsService = new FsService({ root: config.fsRoot });
|
|
4980
4998
|
const terminalSharedRoot = terminalSharedBase({ dataDir: config.dataDir, fsRoot: config.fsRoot });
|
|
4981
4999
|
const backfilledFileSessions = /* @__PURE__ */ new Set();
|
|
4982
|
-
const
|
|
4983
|
-
|
|
4984
|
-
backfilledFileSessions.
|
|
4985
|
-
const
|
|
4986
|
-
|
|
4987
|
-
const
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
const
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5000
|
+
const fileBackfillsInFlight = /* @__PURE__ */ new Map();
|
|
5001
|
+
const backfillManagedFiles = (sessionId) => {
|
|
5002
|
+
if (backfilledFileSessions.has(sessionId)) return Promise.resolve();
|
|
5003
|
+
const existing = fileBackfillsInFlight.get(sessionId);
|
|
5004
|
+
if (existing) return existing;
|
|
5005
|
+
const task = (async () => {
|
|
5006
|
+
const sessionDir = terminalSharedDir({ dataDir: config.dataDir, fsRoot: config.fsRoot, sessionId });
|
|
5007
|
+
const discovered = await fsService.discoverManagedFiles(sessionDir);
|
|
5008
|
+
const knownPaths = new Set(store.listFiles(sessionId, true).map((file) => file.path));
|
|
5009
|
+
for (const file of discovered) {
|
|
5010
|
+
if (knownPaths.has(file.path)) continue;
|
|
5011
|
+
const expiresAt = file.mtimeMs + TERMINAL_FILE_TTL_MS;
|
|
5012
|
+
if (expiresAt <= Date.now()) continue;
|
|
5013
|
+
const now = Date.now();
|
|
5014
|
+
const media = attachmentMedia(file.filename);
|
|
5015
|
+
store.putFile({
|
|
5016
|
+
id: randomUUID4(),
|
|
5017
|
+
sessionId,
|
|
5018
|
+
direction: "sent",
|
|
5019
|
+
storage: "managed",
|
|
5020
|
+
name: file.filename,
|
|
5021
|
+
path: file.path,
|
|
5022
|
+
mimeType: media.mimeType,
|
|
5023
|
+
size: file.size,
|
|
5024
|
+
kind: media.kind,
|
|
5025
|
+
createdAt: file.mtimeMs,
|
|
5026
|
+
updatedAt: now,
|
|
5027
|
+
expiresAt
|
|
5028
|
+
});
|
|
5029
|
+
knownPaths.add(file.path);
|
|
5030
|
+
}
|
|
5031
|
+
backfilledFileSessions.add(sessionId);
|
|
5032
|
+
})();
|
|
5033
|
+
fileBackfillsInFlight.set(sessionId, task);
|
|
5034
|
+
void task.catch(() => void 0).finally(() => fileBackfillsInFlight.delete(sessionId));
|
|
5035
|
+
return task;
|
|
5036
|
+
};
|
|
5037
|
+
const fileAvailableWithinBudget = async (file) => {
|
|
5038
|
+
if (file.expiresAt <= Date.now()) return false;
|
|
5039
|
+
return new Promise((resolve7) => {
|
|
5040
|
+
let settled = false;
|
|
5041
|
+
const finish = (available) => {
|
|
5042
|
+
if (settled) return;
|
|
5043
|
+
settled = true;
|
|
5044
|
+
clearTimeout(timer);
|
|
5045
|
+
resolve7(available);
|
|
5046
|
+
};
|
|
5047
|
+
const timer = setTimeout(() => finish(true), FILE_HISTORY_AVAILABILITY_BUDGET_MS);
|
|
5048
|
+
void fsService.describeFile(file.path).then(
|
|
5049
|
+
() => finish(true),
|
|
5050
|
+
() => finish(false)
|
|
5051
|
+
);
|
|
5052
|
+
});
|
|
5010
5053
|
};
|
|
5011
5054
|
const sweepSharedFiles = () => {
|
|
5012
5055
|
void (async () => {
|
|
@@ -6054,10 +6097,10 @@ function createServer(config, deps = {}) {
|
|
|
6054
6097
|
reply.code(404).send({ error: "terminal session not found" });
|
|
6055
6098
|
return;
|
|
6056
6099
|
}
|
|
6057
|
-
await backfillManagedFiles(request.params.id);
|
|
6100
|
+
await completionWithin(backfillManagedFiles(request.params.id), FILE_HISTORY_BACKFILL_BUDGET_MS);
|
|
6058
6101
|
const files = await Promise.all(
|
|
6059
6102
|
store.listFiles(request.params.id).map(async (file) => {
|
|
6060
|
-
const available =
|
|
6103
|
+
const available = await fileAvailableWithinBudget(file);
|
|
6061
6104
|
return publicSessionFile(file, available);
|
|
6062
6105
|
})
|
|
6063
6106
|
);
|
package/dist/start.js
CHANGED
|
@@ -871,7 +871,7 @@ function readPreviousVersion(root) {
|
|
|
871
871
|
}
|
|
872
872
|
|
|
873
873
|
// src/updater.ts
|
|
874
|
-
var RUNNING_VERSION = "1.0.
|
|
874
|
+
var RUNNING_VERSION = "1.0.12" ? "1.0.12".replace(/^v/, "") : packageVersion();
|
|
875
875
|
var RELEASES_API = "https://api.github.com/repos/burakgon/roamcode/releases?per_page=100";
|
|
876
876
|
var RELEASE_MANIFEST_ASSET = "roamcode-release.json";
|
|
877
877
|
var CHECK_CACHE_MS = 15 * 6e4;
|
|
@@ -4295,6 +4295,24 @@ var IMAGE_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
4295
4295
|
"heic",
|
|
4296
4296
|
"heif"
|
|
4297
4297
|
]);
|
|
4298
|
+
var FILE_HISTORY_BACKFILL_BUDGET_MS = 150;
|
|
4299
|
+
var FILE_HISTORY_AVAILABILITY_BUDGET_MS = 150;
|
|
4300
|
+
function completionWithin(task, timeoutMs) {
|
|
4301
|
+
return new Promise((resolve7) => {
|
|
4302
|
+
let settled = false;
|
|
4303
|
+
const finish = (completed) => {
|
|
4304
|
+
if (settled) return;
|
|
4305
|
+
settled = true;
|
|
4306
|
+
clearTimeout(timer);
|
|
4307
|
+
resolve7(completed);
|
|
4308
|
+
};
|
|
4309
|
+
const timer = setTimeout(() => finish(false), timeoutMs);
|
|
4310
|
+
void task.then(
|
|
4311
|
+
() => finish(true),
|
|
4312
|
+
() => finish(false)
|
|
4313
|
+
);
|
|
4314
|
+
});
|
|
4315
|
+
}
|
|
4298
4316
|
function attachmentMedia(filename, declared = "application/octet-stream") {
|
|
4299
4317
|
const ext = filename.includes(".") ? filename.slice(filename.lastIndexOf(".") + 1).toLowerCase() : "";
|
|
4300
4318
|
if (declared.startsWith("image/") || IMAGE_FILE_EXTENSIONS.has(ext)) {
|
|
@@ -4366,34 +4384,59 @@ function createServer(config, deps = {}) {
|
|
|
4366
4384
|
const fsService = new FsService({ root: config.fsRoot });
|
|
4367
4385
|
const terminalSharedRoot = terminalSharedBase({ dataDir: config.dataDir, fsRoot: config.fsRoot });
|
|
4368
4386
|
const backfilledFileSessions = /* @__PURE__ */ new Set();
|
|
4369
|
-
const
|
|
4370
|
-
|
|
4371
|
-
backfilledFileSessions.
|
|
4372
|
-
const
|
|
4373
|
-
|
|
4374
|
-
const
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
const
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4387
|
+
const fileBackfillsInFlight = /* @__PURE__ */ new Map();
|
|
4388
|
+
const backfillManagedFiles = (sessionId) => {
|
|
4389
|
+
if (backfilledFileSessions.has(sessionId)) return Promise.resolve();
|
|
4390
|
+
const existing = fileBackfillsInFlight.get(sessionId);
|
|
4391
|
+
if (existing) return existing;
|
|
4392
|
+
const task = (async () => {
|
|
4393
|
+
const sessionDir = terminalSharedDir({ dataDir: config.dataDir, fsRoot: config.fsRoot, sessionId });
|
|
4394
|
+
const discovered = await fsService.discoverManagedFiles(sessionDir);
|
|
4395
|
+
const knownPaths = new Set(store.listFiles(sessionId, true).map((file) => file.path));
|
|
4396
|
+
for (const file of discovered) {
|
|
4397
|
+
if (knownPaths.has(file.path)) continue;
|
|
4398
|
+
const expiresAt = file.mtimeMs + TERMINAL_FILE_TTL_MS;
|
|
4399
|
+
if (expiresAt <= Date.now()) continue;
|
|
4400
|
+
const now = Date.now();
|
|
4401
|
+
const media = attachmentMedia(file.filename);
|
|
4402
|
+
store.putFile({
|
|
4403
|
+
id: randomUUID4(),
|
|
4404
|
+
sessionId,
|
|
4405
|
+
direction: "sent",
|
|
4406
|
+
storage: "managed",
|
|
4407
|
+
name: file.filename,
|
|
4408
|
+
path: file.path,
|
|
4409
|
+
mimeType: media.mimeType,
|
|
4410
|
+
size: file.size,
|
|
4411
|
+
kind: media.kind,
|
|
4412
|
+
createdAt: file.mtimeMs,
|
|
4413
|
+
updatedAt: now,
|
|
4414
|
+
expiresAt
|
|
4415
|
+
});
|
|
4416
|
+
knownPaths.add(file.path);
|
|
4417
|
+
}
|
|
4418
|
+
backfilledFileSessions.add(sessionId);
|
|
4419
|
+
})();
|
|
4420
|
+
fileBackfillsInFlight.set(sessionId, task);
|
|
4421
|
+
void task.catch(() => void 0).finally(() => fileBackfillsInFlight.delete(sessionId));
|
|
4422
|
+
return task;
|
|
4423
|
+
};
|
|
4424
|
+
const fileAvailableWithinBudget = async (file) => {
|
|
4425
|
+
if (file.expiresAt <= Date.now()) return false;
|
|
4426
|
+
return new Promise((resolve7) => {
|
|
4427
|
+
let settled = false;
|
|
4428
|
+
const finish = (available) => {
|
|
4429
|
+
if (settled) return;
|
|
4430
|
+
settled = true;
|
|
4431
|
+
clearTimeout(timer);
|
|
4432
|
+
resolve7(available);
|
|
4433
|
+
};
|
|
4434
|
+
const timer = setTimeout(() => finish(true), FILE_HISTORY_AVAILABILITY_BUDGET_MS);
|
|
4435
|
+
void fsService.describeFile(file.path).then(
|
|
4436
|
+
() => finish(true),
|
|
4437
|
+
() => finish(false)
|
|
4438
|
+
);
|
|
4439
|
+
});
|
|
4397
4440
|
};
|
|
4398
4441
|
const sweepSharedFiles = () => {
|
|
4399
4442
|
void (async () => {
|
|
@@ -5441,10 +5484,10 @@ function createServer(config, deps = {}) {
|
|
|
5441
5484
|
reply.code(404).send({ error: "terminal session not found" });
|
|
5442
5485
|
return;
|
|
5443
5486
|
}
|
|
5444
|
-
await backfillManagedFiles(request.params.id);
|
|
5487
|
+
await completionWithin(backfillManagedFiles(request.params.id), FILE_HISTORY_BACKFILL_BUDGET_MS);
|
|
5445
5488
|
const files = await Promise.all(
|
|
5446
5489
|
store.listFiles(request.params.id).map(async (file) => {
|
|
5447
|
-
const available =
|
|
5490
|
+
const available = await fileAvailableWithinBudget(file);
|
|
5448
5491
|
return publicSessionFile(file, available);
|
|
5449
5492
|
})
|
|
5450
5493
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@roamcode.ai/server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.12",
|
|
4
4
|
"description": "Host-native server for RoamCode",
|
|
5
5
|
"homepage": "https://roamcode.ai",
|
|
6
6
|
"bugs": "https://github.com/burakgon/roamcode/issues",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"node-pty": "1.1.0",
|
|
41
41
|
"web-push": "^3.6.7",
|
|
42
42
|
"zod": "^4.4.3",
|
|
43
|
-
"@roamcode.ai/web": "1.0.
|
|
43
|
+
"@roamcode.ai/web": "1.0.12"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/better-sqlite3": "^7.6.13",
|