mnemospark 0.4.0 → 0.6.0
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/cli.js +579 -39
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +27 -2
- package/dist/index.js +579 -39
- package/dist/index.js.map +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -332,6 +332,34 @@ function normalizePaymentRequired(headers) {
|
|
|
332
332
|
function normalizePaymentResponse(headers) {
|
|
333
333
|
return headers.get("PAYMENT-RESPONSE") ?? headers.get("x-payment-response") ?? void 0;
|
|
334
334
|
}
|
|
335
|
+
var BYTE_SI_UNITS = ["B", "KB", "MB", "GB", "TB"];
|
|
336
|
+
var BYTE_SI_BASE = 1e3;
|
|
337
|
+
function formatBytesForDisplay(bytes) {
|
|
338
|
+
if (!Number.isInteger(bytes) || bytes < 0 || !Number.isFinite(bytes)) {
|
|
339
|
+
throw new Error("formatBytesForDisplay expects a non-negative integer");
|
|
340
|
+
}
|
|
341
|
+
if (bytes === 0) {
|
|
342
|
+
return "0 B";
|
|
343
|
+
}
|
|
344
|
+
let value = bytes;
|
|
345
|
+
let unitIndex = 0;
|
|
346
|
+
while (value >= BYTE_SI_BASE && unitIndex < BYTE_SI_UNITS.length - 1) {
|
|
347
|
+
value /= BYTE_SI_BASE;
|
|
348
|
+
unitIndex += 1;
|
|
349
|
+
}
|
|
350
|
+
if (unitIndex === 0) {
|
|
351
|
+
return `${bytes} B`;
|
|
352
|
+
}
|
|
353
|
+
const nearestInt = Math.round(value);
|
|
354
|
+
const pickInt = nearestInt > 0 && Math.abs(value - nearestInt) / Math.max(value, 1e-9) <= 0.01;
|
|
355
|
+
let rounded = pickInt ? nearestInt : Math.round(value * 10) / 10;
|
|
356
|
+
if (rounded >= BYTE_SI_BASE && unitIndex < BYTE_SI_UNITS.length - 1) {
|
|
357
|
+
rounded = Math.round(rounded / BYTE_SI_BASE * 10) / 10;
|
|
358
|
+
unitIndex += 1;
|
|
359
|
+
}
|
|
360
|
+
const text = Number.isInteger(rounded) ? String(rounded) : String(rounded).replace(/\.0$/, "");
|
|
361
|
+
return `${text} ${BYTE_SI_UNITS[unitIndex]}`;
|
|
362
|
+
}
|
|
335
363
|
|
|
336
364
|
// src/wallet-signature.ts
|
|
337
365
|
function normalizeWalletSignature(value) {
|
|
@@ -1148,6 +1176,9 @@ function parseStoredAes256Key(raw, errorMessage = "Invalid key file format") {
|
|
|
1148
1176
|
var STORAGE_LS_PROXY_PATH = "/mnemospark/storage/ls";
|
|
1149
1177
|
var STORAGE_DOWNLOAD_PROXY_PATH = "/mnemospark/storage/download";
|
|
1150
1178
|
var STORAGE_DELETE_PROXY_PATH = "/mnemospark/storage/delete";
|
|
1179
|
+
function isStorageLsListResponse(r) {
|
|
1180
|
+
return r.mode === "list";
|
|
1181
|
+
}
|
|
1151
1182
|
var AES_GCM_TAG_BYTES = 16;
|
|
1152
1183
|
function asBooleanOrDefault(value, defaultValue) {
|
|
1153
1184
|
if (typeof value === "boolean") {
|
|
@@ -1235,7 +1266,7 @@ async function decryptDownloadBytes(encryptedBytes, wrappedDekBase64, walletAddr
|
|
|
1235
1266
|
}
|
|
1236
1267
|
return decryptAesGcm(encryptedBytes, dek);
|
|
1237
1268
|
}
|
|
1238
|
-
async function requestJsonViaProxy(proxyPath,
|
|
1269
|
+
async function requestJsonViaProxy(proxyPath, jsonBody, parser, options = {}) {
|
|
1239
1270
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
1240
1271
|
const baseUrl = normalizeBaseUrl(
|
|
1241
1272
|
options.proxyBaseUrl ?? `http://127.0.0.1:${PROXY_PORT.toString()}`
|
|
@@ -1248,7 +1279,7 @@ async function requestJsonViaProxy(proxyPath, request, parser, options = {}) {
|
|
|
1248
1279
|
},
|
|
1249
1280
|
options.correlation
|
|
1250
1281
|
),
|
|
1251
|
-
body: JSON.stringify(
|
|
1282
|
+
body: JSON.stringify(jsonBody)
|
|
1252
1283
|
});
|
|
1253
1284
|
const bodyText = await response.text();
|
|
1254
1285
|
if (!response.ok) {
|
|
@@ -1262,7 +1293,7 @@ async function requestJsonViaProxy(proxyPath, request, parser, options = {}) {
|
|
|
1262
1293
|
}
|
|
1263
1294
|
return parser(payload);
|
|
1264
1295
|
}
|
|
1265
|
-
async function forwardStorageToBackend(path, method,
|
|
1296
|
+
async function forwardStorageToBackend(path, method, jsonBody, options = {}) {
|
|
1266
1297
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
1267
1298
|
const backendBaseUrl = (options.backendBaseUrl ?? "").trim();
|
|
1268
1299
|
const walletSignature = normalizeWalletSignature(options.walletSignature);
|
|
@@ -1281,7 +1312,7 @@ async function forwardStorageToBackend(path, method, request, options = {}) {
|
|
|
1281
1312
|
"Content-Type": "application/json",
|
|
1282
1313
|
"X-Wallet-Signature": walletSignature
|
|
1283
1314
|
},
|
|
1284
|
-
body: JSON.stringify(
|
|
1315
|
+
body: JSON.stringify(jsonBody)
|
|
1285
1316
|
});
|
|
1286
1317
|
const bodyBuffer = Buffer.from(await response.arrayBuffer());
|
|
1287
1318
|
return {
|
|
@@ -1311,11 +1342,97 @@ function parseStorageObjectRequest(payload) {
|
|
|
1311
1342
|
location
|
|
1312
1343
|
};
|
|
1313
1344
|
}
|
|
1345
|
+
function jsonBodyForObjectRequest(request) {
|
|
1346
|
+
const o = {
|
|
1347
|
+
wallet_address: request.wallet_address,
|
|
1348
|
+
object_key: request.object_key
|
|
1349
|
+
};
|
|
1350
|
+
if (request.location) {
|
|
1351
|
+
o.location = request.location;
|
|
1352
|
+
}
|
|
1353
|
+
return o;
|
|
1354
|
+
}
|
|
1355
|
+
function jsonBodyForLsRequest(request) {
|
|
1356
|
+
const o = { wallet_address: request.wallet_address };
|
|
1357
|
+
if (request.object_key) {
|
|
1358
|
+
o.object_key = request.object_key;
|
|
1359
|
+
}
|
|
1360
|
+
if (request.location) {
|
|
1361
|
+
o.location = request.location;
|
|
1362
|
+
}
|
|
1363
|
+
if (request.continuation_token) {
|
|
1364
|
+
o.continuation_token = request.continuation_token;
|
|
1365
|
+
}
|
|
1366
|
+
if (typeof request.max_keys === "number") {
|
|
1367
|
+
o.max_keys = request.max_keys;
|
|
1368
|
+
}
|
|
1369
|
+
if (request.prefix) {
|
|
1370
|
+
o.prefix = request.prefix;
|
|
1371
|
+
}
|
|
1372
|
+
return o;
|
|
1373
|
+
}
|
|
1374
|
+
function parseStorageLsRequestPayload(payload) {
|
|
1375
|
+
const record = asRecord(payload);
|
|
1376
|
+
if (!record) {
|
|
1377
|
+
return null;
|
|
1378
|
+
}
|
|
1379
|
+
const walletAddress = asNonEmptyString(record.wallet_address);
|
|
1380
|
+
if (!walletAddress) {
|
|
1381
|
+
return null;
|
|
1382
|
+
}
|
|
1383
|
+
const objectKey = asNonEmptyString(record.object_key) ?? void 0;
|
|
1384
|
+
const location = asNonEmptyString(record.location) ?? void 0;
|
|
1385
|
+
const continuation_token = asNonEmptyString(record.continuation_token) ?? void 0;
|
|
1386
|
+
const maxRaw = asNumber(record.max_keys);
|
|
1387
|
+
const max_keys = maxRaw !== null && Number.isInteger(maxRaw) && maxRaw >= 1 ? maxRaw : void 0;
|
|
1388
|
+
const prefix = asNonEmptyString(record.prefix) ?? void 0;
|
|
1389
|
+
return {
|
|
1390
|
+
wallet_address: walletAddress,
|
|
1391
|
+
...objectKey ? { object_key: objectKey } : {},
|
|
1392
|
+
...location ? { location } : {},
|
|
1393
|
+
...continuation_token ? { continuation_token } : {},
|
|
1394
|
+
...typeof max_keys === "number" ? { max_keys } : {},
|
|
1395
|
+
...prefix ? { prefix } : {}
|
|
1396
|
+
};
|
|
1397
|
+
}
|
|
1314
1398
|
function parseStorageLsResponse(payload) {
|
|
1315
1399
|
const record = asRecord(payload);
|
|
1316
1400
|
if (!record) {
|
|
1317
1401
|
throw new Error("Invalid ls response payload");
|
|
1318
1402
|
}
|
|
1403
|
+
if (record.list_mode === true) {
|
|
1404
|
+
const bucket2 = asNonEmptyString(record.bucket) ?? asNonEmptyString(record.bucket_name);
|
|
1405
|
+
const rawObjects = record.objects;
|
|
1406
|
+
if (!bucket2 || !Array.isArray(rawObjects)) {
|
|
1407
|
+
throw new Error("ls list response is missing required fields");
|
|
1408
|
+
}
|
|
1409
|
+
const objects = [];
|
|
1410
|
+
for (const item of rawObjects) {
|
|
1411
|
+
const row = asRecord(item);
|
|
1412
|
+
if (!row) {
|
|
1413
|
+
continue;
|
|
1414
|
+
}
|
|
1415
|
+
const key2 = asNonEmptyString(row.key);
|
|
1416
|
+
const sizeBytes2 = asNumber(row.size_bytes);
|
|
1417
|
+
if (!key2 || sizeBytes2 === null || !Number.isInteger(sizeBytes2) || sizeBytes2 < 0) {
|
|
1418
|
+
continue;
|
|
1419
|
+
}
|
|
1420
|
+
const last_modified = asNonEmptyString(row.last_modified) ?? void 0;
|
|
1421
|
+
objects.push({ key: key2, size_bytes: sizeBytes2, last_modified });
|
|
1422
|
+
}
|
|
1423
|
+
const is_truncated = asBooleanOrDefault(record.is_truncated, false);
|
|
1424
|
+
const nextRaw = record.next_continuation_token;
|
|
1425
|
+
const next_continuation_token = nextRaw === void 0 || nextRaw === null ? null : String(nextRaw);
|
|
1426
|
+
return {
|
|
1427
|
+
mode: "list",
|
|
1428
|
+
success: asBooleanOrDefault(record.success, true),
|
|
1429
|
+
list_mode: true,
|
|
1430
|
+
bucket: bucket2,
|
|
1431
|
+
objects,
|
|
1432
|
+
is_truncated,
|
|
1433
|
+
next_continuation_token
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1319
1436
|
const key = asNonEmptyString(record.key) ?? asNonEmptyString(record.object_key);
|
|
1320
1437
|
const sizeBytes = asNumber(record.size_bytes);
|
|
1321
1438
|
const bucket = asNonEmptyString(record.bucket) ?? asNonEmptyString(record.bucket_name);
|
|
@@ -1323,7 +1440,11 @@ function parseStorageLsResponse(payload) {
|
|
|
1323
1440
|
if (!key || sizeBytes === null || !bucket) {
|
|
1324
1441
|
throw new Error("ls response is missing required fields");
|
|
1325
1442
|
}
|
|
1443
|
+
if (!Number.isInteger(sizeBytes) || sizeBytes < 0) {
|
|
1444
|
+
throw new Error("ls response has invalid size_bytes; expected non-negative integer");
|
|
1445
|
+
}
|
|
1326
1446
|
return {
|
|
1447
|
+
mode: "stat",
|
|
1327
1448
|
success: asBooleanOrDefault(record.success, true),
|
|
1328
1449
|
key,
|
|
1329
1450
|
size_bytes: sizeBytes,
|
|
@@ -1366,12 +1487,17 @@ function parseStorageDownloadProxyResponse(payload) {
|
|
|
1366
1487
|
};
|
|
1367
1488
|
}
|
|
1368
1489
|
async function requestStorageLsViaProxy(request, options = {}) {
|
|
1369
|
-
return requestJsonViaProxy(
|
|
1490
|
+
return requestJsonViaProxy(
|
|
1491
|
+
STORAGE_LS_PROXY_PATH,
|
|
1492
|
+
jsonBodyForLsRequest(request),
|
|
1493
|
+
parseStorageLsResponse,
|
|
1494
|
+
options
|
|
1495
|
+
);
|
|
1370
1496
|
}
|
|
1371
1497
|
async function requestStorageDownloadViaProxy(request, options = {}) {
|
|
1372
1498
|
return requestJsonViaProxy(
|
|
1373
1499
|
STORAGE_DOWNLOAD_PROXY_PATH,
|
|
1374
|
-
request,
|
|
1500
|
+
jsonBodyForObjectRequest(request),
|
|
1375
1501
|
parseStorageDownloadProxyResponse,
|
|
1376
1502
|
options
|
|
1377
1503
|
);
|
|
@@ -1379,19 +1505,29 @@ async function requestStorageDownloadViaProxy(request, options = {}) {
|
|
|
1379
1505
|
async function requestStorageDeleteViaProxy(request, options = {}) {
|
|
1380
1506
|
return requestJsonViaProxy(
|
|
1381
1507
|
STORAGE_DELETE_PROXY_PATH,
|
|
1382
|
-
request,
|
|
1508
|
+
jsonBodyForObjectRequest(request),
|
|
1383
1509
|
parseStorageDeleteResponse,
|
|
1384
1510
|
options
|
|
1385
1511
|
);
|
|
1386
1512
|
}
|
|
1387
1513
|
async function forwardStorageLsToBackend(request, options = {}) {
|
|
1388
|
-
return forwardStorageToBackend("/storage/ls", "POST", request, options);
|
|
1514
|
+
return forwardStorageToBackend("/storage/ls", "POST", jsonBodyForLsRequest(request), options);
|
|
1389
1515
|
}
|
|
1390
1516
|
async function forwardStorageDownloadToBackend(request, options = {}) {
|
|
1391
|
-
return forwardStorageToBackend(
|
|
1517
|
+
return forwardStorageToBackend(
|
|
1518
|
+
"/storage/download",
|
|
1519
|
+
"POST",
|
|
1520
|
+
jsonBodyForObjectRequest(request),
|
|
1521
|
+
options
|
|
1522
|
+
);
|
|
1392
1523
|
}
|
|
1393
1524
|
async function forwardStorageDeleteToBackend(request, options = {}) {
|
|
1394
|
-
return forwardStorageToBackend(
|
|
1525
|
+
return forwardStorageToBackend(
|
|
1526
|
+
"/storage/delete",
|
|
1527
|
+
"POST",
|
|
1528
|
+
jsonBodyForObjectRequest(request),
|
|
1529
|
+
options
|
|
1530
|
+
);
|
|
1395
1531
|
}
|
|
1396
1532
|
async function downloadStorageToDisk(request, backendResponse, options = {}) {
|
|
1397
1533
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
@@ -2227,13 +2363,13 @@ async function startProxy(options) {
|
|
|
2227
2363
|
});
|
|
2228
2364
|
return;
|
|
2229
2365
|
}
|
|
2230
|
-
const requestPayload =
|
|
2366
|
+
const requestPayload = parseStorageLsRequestPayload(payload);
|
|
2231
2367
|
if (!requestPayload) {
|
|
2232
2368
|
logProxyEvent("warn", "proxy_ls_missing_fields");
|
|
2233
2369
|
emitProxyTerminalFromStatus(correlation, 400, { reason: "missing_fields" });
|
|
2234
2370
|
sendJson(res, 400, {
|
|
2235
2371
|
error: "Bad request",
|
|
2236
|
-
message: "Missing required
|
|
2372
|
+
message: "Missing required field: wallet_address"
|
|
2237
2373
|
});
|
|
2238
2374
|
return;
|
|
2239
2375
|
}
|
|
@@ -2749,6 +2885,254 @@ import { homedir as homedir6 } from "os";
|
|
|
2749
2885
|
import { basename as basename2, dirname as dirname5, join as join8, resolve as resolve2 } from "path";
|
|
2750
2886
|
import { privateKeyToAccount as privateKeyToAccount5 } from "viem/accounts";
|
|
2751
2887
|
|
|
2888
|
+
// src/cloud-ls-format.ts
|
|
2889
|
+
import { CronExpressionParser } from "cron-parser";
|
|
2890
|
+
var LS_NAME_DISPLAY_MAX = 72;
|
|
2891
|
+
var LS_PAY_DISPLAY_MAX = 28;
|
|
2892
|
+
var LS_CRON_ID_MAX = 14;
|
|
2893
|
+
var LS_S3_COL_WIDTH = 12;
|
|
2894
|
+
var LS_NEXT_COL_WIDTH = Math.max(LS_S3_COL_WIDTH, "NEXT PAYMENT DATE".length);
|
|
2895
|
+
var HDR_SIZE = "SIZE";
|
|
2896
|
+
var HDR_S3_TIME = "S3_TIME";
|
|
2897
|
+
var HDR_CRON_JOB = "CRON JOB";
|
|
2898
|
+
var HDR_NEXT_PAYMENT = "NEXT PAYMENT DATE";
|
|
2899
|
+
var HDR_AMOUNT_DUE = "AMOUNT DUE";
|
|
2900
|
+
var HDR_FILE_OR_KEY = "FILE NAME OR OBJECT-KEY";
|
|
2901
|
+
var MONTHS_SHORT = [
|
|
2902
|
+
"Jan",
|
|
2903
|
+
"Feb",
|
|
2904
|
+
"Mar",
|
|
2905
|
+
"Apr",
|
|
2906
|
+
"May",
|
|
2907
|
+
"Jun",
|
|
2908
|
+
"Jul",
|
|
2909
|
+
"Aug",
|
|
2910
|
+
"Sep",
|
|
2911
|
+
"Oct",
|
|
2912
|
+
"Nov",
|
|
2913
|
+
"Dec"
|
|
2914
|
+
];
|
|
2915
|
+
function formatLsTimeFieldUtc(iso, now, fieldWidth = LS_S3_COL_WIDTH) {
|
|
2916
|
+
const placeholder = " - ".slice(0, fieldWidth);
|
|
2917
|
+
if (!iso) {
|
|
2918
|
+
return placeholder.padEnd(fieldWidth, " ");
|
|
2919
|
+
}
|
|
2920
|
+
const d = new Date(iso);
|
|
2921
|
+
if (Number.isNaN(d.getTime())) {
|
|
2922
|
+
return placeholder.padEnd(fieldWidth, " ");
|
|
2923
|
+
}
|
|
2924
|
+
const mon = MONTHS_SHORT[d.getUTCMonth()] ?? "???";
|
|
2925
|
+
const day = String(d.getUTCDate()).padStart(2, " ");
|
|
2926
|
+
const y = d.getUTCFullYear();
|
|
2927
|
+
const nowY = now.getUTCFullYear();
|
|
2928
|
+
let core;
|
|
2929
|
+
if (y === nowY) {
|
|
2930
|
+
const hh = String(d.getUTCHours()).padStart(2, "0");
|
|
2931
|
+
const mm = String(d.getUTCMinutes()).padStart(2, "0");
|
|
2932
|
+
core = `${mon} ${day} ${hh}:${mm}`;
|
|
2933
|
+
} else {
|
|
2934
|
+
core = `${mon} ${day} ${y}`;
|
|
2935
|
+
}
|
|
2936
|
+
return core.padEnd(fieldWidth, " ");
|
|
2937
|
+
}
|
|
2938
|
+
function truncateEnd(value, max) {
|
|
2939
|
+
if (value.length <= max) {
|
|
2940
|
+
return value;
|
|
2941
|
+
}
|
|
2942
|
+
if (max <= 1) {
|
|
2943
|
+
return "\u2026";
|
|
2944
|
+
}
|
|
2945
|
+
return `${value.slice(0, max - 1)}\u2026`;
|
|
2946
|
+
}
|
|
2947
|
+
function truncateMiddle(value, max, suffixMin) {
|
|
2948
|
+
if (value.length <= max) {
|
|
2949
|
+
return value;
|
|
2950
|
+
}
|
|
2951
|
+
if (max < suffixMin + 5) {
|
|
2952
|
+
return truncateEnd(value, max);
|
|
2953
|
+
}
|
|
2954
|
+
const suffixLen = Math.min(suffixMin, max - 5);
|
|
2955
|
+
const prefixLen = max - 3 - suffixLen;
|
|
2956
|
+
return `${value.slice(0, prefixLen)} \u2026 ${value.slice(-suffixLen)}`;
|
|
2957
|
+
}
|
|
2958
|
+
function formatCronIdCell(cronId, width) {
|
|
2959
|
+
if (!cronId) {
|
|
2960
|
+
return " - ".slice(0, width).padStart(width, " ");
|
|
2961
|
+
}
|
|
2962
|
+
const t = truncateEnd(cronId, width);
|
|
2963
|
+
return t.padStart(width, " ");
|
|
2964
|
+
}
|
|
2965
|
+
function formatPaymentCell(amount, network, maxWidth) {
|
|
2966
|
+
if (amount === null) {
|
|
2967
|
+
return " - ".slice(0, maxWidth).padStart(maxWidth, " ");
|
|
2968
|
+
}
|
|
2969
|
+
let s = amount.toFixed(6).replace(/\.?0+$/, "");
|
|
2970
|
+
if (network && network.trim()) {
|
|
2971
|
+
s = `${s} (${network.trim()})`;
|
|
2972
|
+
}
|
|
2973
|
+
return truncateEnd(s, maxWidth).padStart(maxWidth, " ");
|
|
2974
|
+
}
|
|
2975
|
+
function formatNextCronUtc(schedule, cronStatus, now) {
|
|
2976
|
+
const blank = " - ".slice(0, LS_NEXT_COL_WIDTH).padEnd(LS_NEXT_COL_WIDTH, " ");
|
|
2977
|
+
if (cronStatus !== "active") {
|
|
2978
|
+
return blank;
|
|
2979
|
+
}
|
|
2980
|
+
try {
|
|
2981
|
+
const expr = CronExpressionParser.parse(schedule, { tz: "UTC", currentDate: now });
|
|
2982
|
+
const next = expr.next().toDate();
|
|
2983
|
+
return formatLsTimeFieldUtc(next.toISOString(), now, LS_NEXT_COL_WIDTH);
|
|
2984
|
+
} catch {
|
|
2985
|
+
return "?".padEnd(LS_NEXT_COL_WIDTH, " ");
|
|
2986
|
+
}
|
|
2987
|
+
}
|
|
2988
|
+
function buildLsProseIntro(bucket) {
|
|
2989
|
+
return [
|
|
2990
|
+
"\u2601\uFE0F mnemospark cloud files",
|
|
2991
|
+
`S3 bucket: ${bucket}`,
|
|
2992
|
+
"The columns: CRON JOB, NEXT PAYMENT DATE, AMOUNT DUE, FILE NAME are from this host's mnemospark SQLite catalog",
|
|
2993
|
+
"mnemospark cloud only stores the OBJECT-KEY for privacy"
|
|
2994
|
+
];
|
|
2995
|
+
}
|
|
2996
|
+
async function prepareRows(objects, walletAddress, datastore, now) {
|
|
2997
|
+
const sorted = [...objects].sort((a, b) => {
|
|
2998
|
+
const ta = a.last_modified ? Date.parse(a.last_modified) : Number.NaN;
|
|
2999
|
+
const tb = b.last_modified ? Date.parse(b.last_modified) : Number.NaN;
|
|
3000
|
+
const aOk = Number.isFinite(ta);
|
|
3001
|
+
const bOk = Number.isFinite(tb);
|
|
3002
|
+
if (aOk && bOk && tb !== ta) {
|
|
3003
|
+
return tb - ta;
|
|
3004
|
+
}
|
|
3005
|
+
if (aOk && !bOk) {
|
|
3006
|
+
return -1;
|
|
3007
|
+
}
|
|
3008
|
+
if (!aOk && bOk) {
|
|
3009
|
+
return 1;
|
|
3010
|
+
}
|
|
3011
|
+
return a.key.localeCompare(b.key);
|
|
3012
|
+
});
|
|
3013
|
+
const rows = [];
|
|
3014
|
+
for (const obj of sorted) {
|
|
3015
|
+
const friendly = await datastore.findLatestFriendlyNameForObjectKey(walletAddress, obj.key);
|
|
3016
|
+
const cp = await datastore.findCronAndPaymentForObjectKey(walletAddress, obj.key);
|
|
3017
|
+
const sizeStr = formatBytesForDisplay(obj.size_bytes);
|
|
3018
|
+
const s3time = formatLsTimeFieldUtc(obj.last_modified, now, LS_S3_COL_WIDTH);
|
|
3019
|
+
let cronIdDisp = null;
|
|
3020
|
+
let nextRun = " - ".slice(0, LS_NEXT_COL_WIDTH).padEnd(LS_NEXT_COL_WIDTH, " ");
|
|
3021
|
+
let payCell = "";
|
|
3022
|
+
if (cp) {
|
|
3023
|
+
cronIdDisp = cp.cronId;
|
|
3024
|
+
nextRun = formatNextCronUtc(cp.schedule, cp.cronStatus, now);
|
|
3025
|
+
payCell = formatPaymentCell(cp.amount, cp.network, LS_PAY_DISPLAY_MAX);
|
|
3026
|
+
} else {
|
|
3027
|
+
payCell = formatPaymentCell(null, null, LS_PAY_DISPLAY_MAX);
|
|
3028
|
+
}
|
|
3029
|
+
const nameRaw = friendly ? `${friendly} (${obj.key})` : obj.key;
|
|
3030
|
+
rows.push({
|
|
3031
|
+
sizeStr,
|
|
3032
|
+
s3time,
|
|
3033
|
+
cronIdRaw: cronIdDisp,
|
|
3034
|
+
nextRun,
|
|
3035
|
+
payRaw: payCell,
|
|
3036
|
+
nameRaw: truncateMiddle(nameRaw, LS_NAME_DISPLAY_MAX, 8)
|
|
3037
|
+
});
|
|
3038
|
+
}
|
|
3039
|
+
return rows;
|
|
3040
|
+
}
|
|
3041
|
+
function columnWidths(rows) {
|
|
3042
|
+
let sizeW = HDR_SIZE.length;
|
|
3043
|
+
let s3W = Math.max(LS_S3_COL_WIDTH, HDR_S3_TIME.length);
|
|
3044
|
+
let nextW = LS_NEXT_COL_WIDTH;
|
|
3045
|
+
let cronW = HDR_CRON_JOB.length;
|
|
3046
|
+
let payW = HDR_AMOUNT_DUE.length;
|
|
3047
|
+
for (const r of rows) {
|
|
3048
|
+
sizeW = Math.max(sizeW, r.sizeStr.length);
|
|
3049
|
+
s3W = Math.max(s3W, r.s3time.length);
|
|
3050
|
+
nextW = Math.max(nextW, r.nextRun.length);
|
|
3051
|
+
const cid = r.cronIdRaw ? truncateEnd(r.cronIdRaw, LS_CRON_ID_MAX) : "";
|
|
3052
|
+
cronW = Math.max(cronW, cid.length || 1);
|
|
3053
|
+
payW = Math.max(payW, r.payRaw.length);
|
|
3054
|
+
}
|
|
3055
|
+
cronW = Math.min(Math.max(cronW, HDR_CRON_JOB.length), LS_CRON_ID_MAX);
|
|
3056
|
+
payW = Math.min(Math.max(payW, HDR_AMOUNT_DUE.length), LS_PAY_DISPLAY_MAX);
|
|
3057
|
+
return { sizeW, s3W, cronW, nextW, payW };
|
|
3058
|
+
}
|
|
3059
|
+
function renderRow(r, w) {
|
|
3060
|
+
const cronPadded = formatCronIdCell(r.cronIdRaw, w.cronW);
|
|
3061
|
+
return [
|
|
3062
|
+
r.sizeStr.padStart(w.sizeW, " "),
|
|
3063
|
+
r.s3time.padEnd(w.s3W, " "),
|
|
3064
|
+
cronPadded,
|
|
3065
|
+
r.nextRun.padEnd(w.nextW, " "),
|
|
3066
|
+
r.payRaw.padStart(w.payW, " "),
|
|
3067
|
+
r.nameRaw
|
|
3068
|
+
].join(" ");
|
|
3069
|
+
}
|
|
3070
|
+
function renderHeader(w) {
|
|
3071
|
+
return [
|
|
3072
|
+
HDR_SIZE.padStart(w.sizeW, " "),
|
|
3073
|
+
HDR_S3_TIME.padEnd(w.s3W, " "),
|
|
3074
|
+
HDR_CRON_JOB.padStart(w.cronW, " "),
|
|
3075
|
+
HDR_NEXT_PAYMENT.padEnd(w.nextW, " "),
|
|
3076
|
+
HDR_AMOUNT_DUE.padStart(w.payW, " "),
|
|
3077
|
+
HDR_FILE_OR_KEY
|
|
3078
|
+
].join(" ");
|
|
3079
|
+
}
|
|
3080
|
+
async function buildMnemosparkLsMessage(result, ctx) {
|
|
3081
|
+
const now = ctx.now ?? /* @__PURE__ */ new Date();
|
|
3082
|
+
if (isStorageLsListResponse(result)) {
|
|
3083
|
+
const intro = buildLsProseIntro(result.bucket);
|
|
3084
|
+
if (result.objects.length === 0) {
|
|
3085
|
+
return [...intro, "", "No objects in this bucket."].join("\n");
|
|
3086
|
+
}
|
|
3087
|
+
const rows = await prepareRows(result.objects, ctx.walletAddress, ctx.datastore, now);
|
|
3088
|
+
const w2 = columnWidths(rows);
|
|
3089
|
+
const header2 = renderHeader(w2);
|
|
3090
|
+
const bodyLines = rows.map((r) => renderRow(r, w2));
|
|
3091
|
+
const truncLine = result.is_truncated ? "List truncated; more objects in bucket." : null;
|
|
3092
|
+
const prose2 = [...intro, ...truncLine ? [truncLine] : []].join("\n");
|
|
3093
|
+
const fence2 = ["```", [header2, ...bodyLines].join("\n"), "```"].join("\n");
|
|
3094
|
+
return `${prose2}
|
|
3095
|
+
|
|
3096
|
+
${fence2}`;
|
|
3097
|
+
}
|
|
3098
|
+
const friendly = await ctx.datastore.findLatestFriendlyNameForObjectKey(
|
|
3099
|
+
ctx.walletAddress,
|
|
3100
|
+
result.key
|
|
3101
|
+
);
|
|
3102
|
+
const cp = await ctx.datastore.findCronAndPaymentForObjectKey(ctx.walletAddress, result.key);
|
|
3103
|
+
const sizeStr = formatBytesForDisplay(result.size_bytes);
|
|
3104
|
+
const s3time = formatLsTimeFieldUtc(void 0, now, LS_S3_COL_WIDTH);
|
|
3105
|
+
let payCell = formatPaymentCell(null, null, LS_PAY_DISPLAY_MAX);
|
|
3106
|
+
let cronIdDisp = null;
|
|
3107
|
+
let nextRun = " - ".slice(0, LS_NEXT_COL_WIDTH).padEnd(LS_NEXT_COL_WIDTH, " ");
|
|
3108
|
+
if (cp) {
|
|
3109
|
+
cronIdDisp = cp.cronId;
|
|
3110
|
+
nextRun = formatNextCronUtc(cp.schedule, cp.cronStatus, now);
|
|
3111
|
+
payCell = formatPaymentCell(cp.amount, cp.network, LS_PAY_DISPLAY_MAX);
|
|
3112
|
+
}
|
|
3113
|
+
const nameShown = truncateMiddle(
|
|
3114
|
+
friendly ? `${friendly} (${result.key})` : result.key,
|
|
3115
|
+
LS_NAME_DISPLAY_MAX,
|
|
3116
|
+
8
|
|
3117
|
+
);
|
|
3118
|
+
const prep = {
|
|
3119
|
+
sizeStr,
|
|
3120
|
+
s3time,
|
|
3121
|
+
cronIdRaw: cronIdDisp,
|
|
3122
|
+
nextRun,
|
|
3123
|
+
payRaw: payCell,
|
|
3124
|
+
nameRaw: nameShown
|
|
3125
|
+
};
|
|
3126
|
+
const w = columnWidths([prep]);
|
|
3127
|
+
const header = renderHeader(w);
|
|
3128
|
+
const line = renderRow(prep, w);
|
|
3129
|
+
const prose = buildLsProseIntro(result.bucket).join("\n");
|
|
3130
|
+
const fence = ["```", [header, line].join("\n"), "```"].join("\n");
|
|
3131
|
+
return `${prose}
|
|
3132
|
+
|
|
3133
|
+
${fence}`;
|
|
3134
|
+
}
|
|
3135
|
+
|
|
2752
3136
|
// src/cloud-datastore.ts
|
|
2753
3137
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
2754
3138
|
import { mkdir as mkdir4 } from "fs/promises";
|
|
@@ -3192,7 +3576,63 @@ async function createCloudDatastore(homeDir) {
|
|
|
3192
3576
|
WHERE wallet_address = ? AND friendly_name = ? AND is_active = 1`
|
|
3193
3577
|
).get(normalizedWalletAddress, friendlyName);
|
|
3194
3578
|
return Number(row?.cnt ?? 0);
|
|
3195
|
-
}, 0)
|
|
3579
|
+
}, 0),
|
|
3580
|
+
findLatestFriendlyNameForObjectKey: async (walletAddress, objectKey) => safe(() => {
|
|
3581
|
+
const w = normalizeWalletAddress(walletAddress);
|
|
3582
|
+
const byKey = db.prepare(
|
|
3583
|
+
`SELECT friendly_name
|
|
3584
|
+
FROM friendly_names
|
|
3585
|
+
WHERE wallet_address = ? AND object_key = ? AND is_active = 1
|
|
3586
|
+
ORDER BY created_at DESC
|
|
3587
|
+
LIMIT 1`
|
|
3588
|
+
).get(w, objectKey);
|
|
3589
|
+
if (byKey) {
|
|
3590
|
+
return byKey.friendly_name;
|
|
3591
|
+
}
|
|
3592
|
+
const obj = db.prepare(
|
|
3593
|
+
`SELECT object_id FROM objects WHERE wallet_address = ? AND object_key = ? LIMIT 1`
|
|
3594
|
+
).get(w, objectKey);
|
|
3595
|
+
if (!obj) {
|
|
3596
|
+
return null;
|
|
3597
|
+
}
|
|
3598
|
+
const byObj = db.prepare(
|
|
3599
|
+
`SELECT friendly_name
|
|
3600
|
+
FROM friendly_names
|
|
3601
|
+
WHERE wallet_address = ? AND object_id = ? AND is_active = 1
|
|
3602
|
+
ORDER BY created_at DESC
|
|
3603
|
+
LIMIT 1`
|
|
3604
|
+
).get(w, obj.object_id);
|
|
3605
|
+
return byObj?.friendly_name ?? null;
|
|
3606
|
+
}, null),
|
|
3607
|
+
findCronAndPaymentForObjectKey: async (walletAddress, objectKey) => safe(() => {
|
|
3608
|
+
const w = normalizeWalletAddress(walletAddress);
|
|
3609
|
+
const cron = db.prepare(
|
|
3610
|
+
`SELECT c.cron_id, c.quote_id, c.schedule, c.status
|
|
3611
|
+
FROM cron_jobs c
|
|
3612
|
+
INNER JOIN objects o ON o.object_id = c.object_id
|
|
3613
|
+
WHERE c.object_key = ? AND o.wallet_address = ?
|
|
3614
|
+
ORDER BY c.updated_at DESC
|
|
3615
|
+
LIMIT 1`
|
|
3616
|
+
).get(objectKey, w);
|
|
3617
|
+
if (!cron) {
|
|
3618
|
+
return null;
|
|
3619
|
+
}
|
|
3620
|
+
const pay = db.prepare(
|
|
3621
|
+
`SELECT amount, network, status
|
|
3622
|
+
FROM payments
|
|
3623
|
+
WHERE quote_id = ? AND wallet_address = ?
|
|
3624
|
+
LIMIT 1`
|
|
3625
|
+
).get(cron.quote_id, w);
|
|
3626
|
+
return {
|
|
3627
|
+
cronId: cron.cron_id,
|
|
3628
|
+
schedule: cron.schedule,
|
|
3629
|
+
quoteId: cron.quote_id,
|
|
3630
|
+
cronStatus: cron.status,
|
|
3631
|
+
amount: pay?.amount ?? null,
|
|
3632
|
+
network: pay?.network ?? null,
|
|
3633
|
+
paymentStatus: pay?.status ?? null
|
|
3634
|
+
};
|
|
3635
|
+
}, null)
|
|
3196
3636
|
};
|
|
3197
3637
|
}
|
|
3198
3638
|
|
|
@@ -3214,6 +3654,7 @@ var REQUIRED_PRICE_STORAGE = "--wallet-address, --object-id, --object-id-hash, -
|
|
|
3214
3654
|
var REQUIRED_UPLOAD = "--quote-id, --wallet-address, --object-id, --object-id-hash";
|
|
3215
3655
|
var REQUIRED_PAYMENT_SETTLE = "--quote-id and --wallet-address";
|
|
3216
3656
|
var REQUIRED_STORAGE_OBJECT = "--wallet-address and one of (--object-key | --name [--latest|--at])";
|
|
3657
|
+
var REQUIRED_LS = "--wallet-address (for one object add --object-key or --name [--latest|--at]; omit both to list the bucket)";
|
|
3217
3658
|
var PAYMENT_SETTLE_FLAG_NAMES = /* @__PURE__ */ new Set([
|
|
3218
3659
|
"quote-id",
|
|
3219
3660
|
"wallet-address",
|
|
@@ -3257,9 +3698,9 @@ var CLOUD_HELP_TEXT = [
|
|
|
3257
3698
|
" Purpose: settle storage payment for a quote (e.g. monthly cron). Uses the same proxy + x402 path as upload pre-settlement.",
|
|
3258
3699
|
" Required: --quote-id, --wallet-address (wallet private key must match the address).",
|
|
3259
3700
|
"",
|
|
3260
|
-
"\u2022 `/mnemospark_cloud ls --wallet-address <addr> [--object-key <
|
|
3261
|
-
" Purpose:
|
|
3262
|
-
" Required: " +
|
|
3701
|
+
"\u2022 `/mnemospark_cloud ls --wallet-address <addr> [--object-key <key> | --name <friendly-name> | omit both to list bucket] [--latest|--at <timestamp>]`",
|
|
3702
|
+
" Purpose: stat one object or list all keys in the wallet bucket (S3).",
|
|
3703
|
+
" Required: " + REQUIRED_LS,
|
|
3263
3704
|
"",
|
|
3264
3705
|
"\u2022 `/mnemospark_cloud download --wallet-address <addr> [--object-key <object-key> | --name <friendly-name>] [--latest|--at <timestamp>] [--async] [--orchestrator <inline|subagent>] [--timeout-seconds <n>]`",
|
|
3265
3706
|
" Purpose: fetch an object to local disk.",
|
|
@@ -3362,6 +3803,18 @@ function parseObjectSelector(flags) {
|
|
|
3362
3803
|
if (objectKey) return { objectKey };
|
|
3363
3804
|
return { nameSelector: { name, latest, at } };
|
|
3364
3805
|
}
|
|
3806
|
+
function parseLsObjectSelector(flags) {
|
|
3807
|
+
const objectKey = flags["object-key"]?.trim();
|
|
3808
|
+
const name = flags.name?.trim();
|
|
3809
|
+
const latest = flags.latest === "true";
|
|
3810
|
+
const at = flags.at?.trim();
|
|
3811
|
+
if (objectKey && name) return null;
|
|
3812
|
+
if (latest && at) return null;
|
|
3813
|
+
if (!objectKey && !name && (latest || at)) return null;
|
|
3814
|
+
if (objectKey) return { objectKey };
|
|
3815
|
+
if (name) return { nameSelector: { name, latest, at } };
|
|
3816
|
+
return {};
|
|
3817
|
+
}
|
|
3365
3818
|
function parseStorageObjectRequestInput(flags, selector) {
|
|
3366
3819
|
const walletAddress = flags["wallet-address"]?.trim();
|
|
3367
3820
|
if (!walletAddress) {
|
|
@@ -3572,15 +4025,36 @@ function parseCloudArgs(args) {
|
|
|
3572
4025
|
if (!flags) {
|
|
3573
4026
|
return { mode: "ls-invalid" };
|
|
3574
4027
|
}
|
|
3575
|
-
const
|
|
3576
|
-
if (!
|
|
4028
|
+
const walletAddress = flags["wallet-address"]?.trim() ?? flags["wallet_address"]?.trim() ?? "";
|
|
4029
|
+
if (!walletAddress) {
|
|
3577
4030
|
return { mode: "ls-invalid" };
|
|
3578
4031
|
}
|
|
3579
|
-
const
|
|
3580
|
-
if (!
|
|
4032
|
+
const selector = parseLsObjectSelector(flags);
|
|
4033
|
+
if (!selector) {
|
|
3581
4034
|
return { mode: "ls-invalid" };
|
|
3582
4035
|
}
|
|
3583
|
-
|
|
4036
|
+
const location = flags.location?.trim() || flags.region?.trim() || void 0;
|
|
4037
|
+
if (selector.nameSelector) {
|
|
4038
|
+
return {
|
|
4039
|
+
mode: "ls",
|
|
4040
|
+
storageObjectRequest: { wallet_address: walletAddress, location },
|
|
4041
|
+
nameSelector: selector.nameSelector
|
|
4042
|
+
};
|
|
4043
|
+
}
|
|
4044
|
+
if (selector.objectKey) {
|
|
4045
|
+
return {
|
|
4046
|
+
mode: "ls",
|
|
4047
|
+
storageObjectRequest: {
|
|
4048
|
+
wallet_address: walletAddress,
|
|
4049
|
+
object_key: selector.objectKey,
|
|
4050
|
+
location
|
|
4051
|
+
}
|
|
4052
|
+
};
|
|
4053
|
+
}
|
|
4054
|
+
return {
|
|
4055
|
+
mode: "ls",
|
|
4056
|
+
storageObjectRequest: { wallet_address: walletAddress, location }
|
|
4057
|
+
};
|
|
3584
4058
|
}
|
|
3585
4059
|
if (subcommand === "download") {
|
|
3586
4060
|
const flags = parseNamedFlags(rest, BOOLEAN_SELECTOR_AND_ASYNC_FLAGS);
|
|
@@ -4217,16 +4691,28 @@ function extractUploadErrorMessage(error) {
|
|
|
4217
4691
|
}
|
|
4218
4692
|
return message;
|
|
4219
4693
|
}
|
|
4694
|
+
function extractLsErrorMessage(error) {
|
|
4695
|
+
if (!(error instanceof Error)) {
|
|
4696
|
+
return null;
|
|
4697
|
+
}
|
|
4698
|
+
const message = error.message.trim();
|
|
4699
|
+
if (!message) {
|
|
4700
|
+
return null;
|
|
4701
|
+
}
|
|
4702
|
+
if (message.startsWith("ls response") || message.startsWith("ls list response") || message.startsWith("Invalid ls response payload")) {
|
|
4703
|
+
return `Cannot list storage object: ${message}`;
|
|
4704
|
+
}
|
|
4705
|
+
if (message === "formatBytesForDisplay expects a non-negative integer") {
|
|
4706
|
+
return "Cannot list storage object: ls response has invalid size_bytes; expected non-negative integer";
|
|
4707
|
+
}
|
|
4708
|
+
return null;
|
|
4709
|
+
}
|
|
4220
4710
|
function formatPriceStorageUserMessage(quote) {
|
|
4221
4711
|
return [
|
|
4222
4712
|
`Your storage quote \`${quote.quote_id}\` is valid for 1 hour, the storage price is \`${quote.storage_price}\` for \`${quote.object_id}\` with file size of \`${quote.object_size_gb}\` in \`${quote.provider}\` \`${quote.location}\``,
|
|
4223
4713
|
`If you accept this quote run the command /mnemospark_cloud upload --quote-id \`${quote.quote_id}\` --wallet-address \`${quote.addr}\` --object-id \`${quote.object_id}\` --object-id-hash \`${quote.object_id_hash}\``
|
|
4224
4714
|
].join("\n");
|
|
4225
4715
|
}
|
|
4226
|
-
function formatStorageLsUserMessage(result, requestedObjectKey) {
|
|
4227
|
-
const objectId = result.object_id ?? result.key;
|
|
4228
|
-
return `${objectId} with ${requestedObjectKey} is ${result.size_bytes} in ${result.bucket}`;
|
|
4229
|
-
}
|
|
4230
4716
|
function createInProcessSubagentOrchestrator() {
|
|
4231
4717
|
const sessions = /* @__PURE__ */ new Map();
|
|
4232
4718
|
const completeSession = async (sessionId, handler) => {
|
|
@@ -4404,7 +4890,23 @@ async function resolveFriendlyNameFromManifest(params, homeDir) {
|
|
|
4404
4890
|
}
|
|
4405
4891
|
async function resolveNameSelectorIfNeeded(datastore, request, selector, homeDir) {
|
|
4406
4892
|
if (!selector) {
|
|
4407
|
-
const
|
|
4893
|
+
const walletAddress = request.wallet_address?.trim();
|
|
4894
|
+
if (!walletAddress) {
|
|
4895
|
+
return { error: "Cannot resolve storage object request." };
|
|
4896
|
+
}
|
|
4897
|
+
const objectKey = request.object_key?.trim();
|
|
4898
|
+
if (!objectKey) {
|
|
4899
|
+
const listRequest = { wallet_address: walletAddress };
|
|
4900
|
+
if (request.location) {
|
|
4901
|
+
listRequest.location = request.location;
|
|
4902
|
+
}
|
|
4903
|
+
return { request: listRequest };
|
|
4904
|
+
}
|
|
4905
|
+
const parsedRequest2 = parseStorageObjectRequest({
|
|
4906
|
+
wallet_address: walletAddress,
|
|
4907
|
+
object_key: objectKey,
|
|
4908
|
+
location: request.location
|
|
4909
|
+
});
|
|
4408
4910
|
if (!parsedRequest2) {
|
|
4409
4911
|
return { error: "Cannot resolve storage object request." };
|
|
4410
4912
|
}
|
|
@@ -4465,6 +4967,21 @@ async function resolveNameSelectorIfNeeded(datastore, request, selector, homeDir
|
|
|
4465
4967
|
degradedWarning
|
|
4466
4968
|
};
|
|
4467
4969
|
}
|
|
4970
|
+
function toStorageObjectRequestOrError(request, missingKeyMessage) {
|
|
4971
|
+
const key = request.object_key?.trim();
|
|
4972
|
+
if (!key) {
|
|
4973
|
+
return { ok: false, error: missingKeyMessage };
|
|
4974
|
+
}
|
|
4975
|
+
const parsed = parseStorageObjectRequest({
|
|
4976
|
+
wallet_address: request.wallet_address,
|
|
4977
|
+
object_key: key,
|
|
4978
|
+
location: request.location
|
|
4979
|
+
});
|
|
4980
|
+
if (!parsed) {
|
|
4981
|
+
return { ok: false, error: "Cannot resolve storage object request." };
|
|
4982
|
+
}
|
|
4983
|
+
return { ok: true, request: parsed };
|
|
4984
|
+
}
|
|
4468
4985
|
async function emitCloudEvent(eventType, details, homeDir) {
|
|
4469
4986
|
await appendJsonlEvent(
|
|
4470
4987
|
"events.jsonl",
|
|
@@ -4691,7 +5208,7 @@ async function runCloudCommandHandler(ctx, options, executionContext = {}) {
|
|
|
4691
5208
|
}
|
|
4692
5209
|
if (parsed.mode === "ls-invalid") {
|
|
4693
5210
|
return {
|
|
4694
|
-
text: `Cannot list storage object: required arguments are ${
|
|
5211
|
+
text: `Cannot list storage object: required arguments are ${REQUIRED_LS}.`,
|
|
4695
5212
|
isError: true
|
|
4696
5213
|
};
|
|
4697
5214
|
}
|
|
@@ -5686,15 +6203,17 @@ operation-id: ${operationId}`,
|
|
|
5686
6203
|
"name_resolution.degraded",
|
|
5687
6204
|
{
|
|
5688
6205
|
wallet_address: resolvedRequest.wallet_address,
|
|
5689
|
-
object_key: resolvedRequest.object_key,
|
|
6206
|
+
object_key: resolvedRequest.object_key ?? null,
|
|
5690
6207
|
warning: resolved.degradedWarning
|
|
5691
6208
|
},
|
|
5692
6209
|
objectLogHomeDir
|
|
5693
6210
|
);
|
|
5694
6211
|
}
|
|
6212
|
+
const objectKeyForLs = resolvedRequest.object_key?.trim();
|
|
6213
|
+
const isBucketList = !objectKeyForLs;
|
|
5695
6214
|
const correlation = buildRequestCorrelation();
|
|
5696
6215
|
const operationId = correlation.operationId;
|
|
5697
|
-
const knownObject = await datastore.findObjectByObjectKey(
|
|
6216
|
+
const knownObject = isBucketList ? null : await datastore.findObjectByObjectKey(objectKeyForLs);
|
|
5698
6217
|
const operationObjectId = knownObject?.object_id ?? null;
|
|
5699
6218
|
await datastore.upsertOperation({
|
|
5700
6219
|
operation_id: operationId,
|
|
@@ -5728,17 +6247,23 @@ operation-id: ${operationId}`,
|
|
|
5728
6247
|
operation_id: operationId,
|
|
5729
6248
|
trace_id: correlation.traceId,
|
|
5730
6249
|
wallet_address: resolvedRequest.wallet_address,
|
|
5731
|
-
object_key: resolvedRequest.object_key,
|
|
5732
|
-
status: "succeeded"
|
|
6250
|
+
object_key: resolvedRequest.object_key ?? null,
|
|
6251
|
+
status: "succeeded",
|
|
6252
|
+
list_mode: isBucketList
|
|
5733
6253
|
},
|
|
5734
6254
|
objectLogHomeDir
|
|
5735
6255
|
);
|
|
5736
|
-
const lsText =
|
|
6256
|
+
const lsText = await buildMnemosparkLsMessage(lsResult, {
|
|
6257
|
+
walletAddress: resolvedRequest.wallet_address,
|
|
6258
|
+
datastore
|
|
6259
|
+
});
|
|
5737
6260
|
return {
|
|
5738
6261
|
text: resolved.degradedWarning ? `${resolved.degradedWarning}
|
|
6262
|
+
|
|
5739
6263
|
${lsText}` : lsText
|
|
5740
6264
|
};
|
|
5741
|
-
} catch {
|
|
6265
|
+
} catch (error) {
|
|
6266
|
+
const lsErrorMessage = extractLsErrorMessage(error) ?? "Cannot list storage object";
|
|
5742
6267
|
await datastore.upsertOperation({
|
|
5743
6268
|
operation_id: operationId,
|
|
5744
6269
|
type: "ls",
|
|
@@ -5746,7 +6271,7 @@ ${lsText}` : lsText
|
|
|
5746
6271
|
quote_id: null,
|
|
5747
6272
|
status: "failed",
|
|
5748
6273
|
error_code: "LS_FAILED",
|
|
5749
|
-
error_message:
|
|
6274
|
+
error_message: lsErrorMessage
|
|
5750
6275
|
});
|
|
5751
6276
|
await emitCloudEventBestEffort(
|
|
5752
6277
|
"ls.completed",
|
|
@@ -5754,13 +6279,14 @@ ${lsText}` : lsText
|
|
|
5754
6279
|
operation_id: operationId,
|
|
5755
6280
|
trace_id: correlation.traceId,
|
|
5756
6281
|
wallet_address: resolvedRequest.wallet_address,
|
|
5757
|
-
object_key: resolvedRequest.object_key,
|
|
5758
|
-
status: "failed"
|
|
6282
|
+
object_key: resolvedRequest.object_key ?? null,
|
|
6283
|
+
status: "failed",
|
|
6284
|
+
list_mode: isBucketList
|
|
5759
6285
|
},
|
|
5760
6286
|
objectLogHomeDir
|
|
5761
6287
|
);
|
|
5762
6288
|
return {
|
|
5763
|
-
text:
|
|
6289
|
+
text: lsErrorMessage,
|
|
5764
6290
|
isError: true
|
|
5765
6291
|
};
|
|
5766
6292
|
}
|
|
@@ -5775,7 +6301,14 @@ ${lsText}` : lsText
|
|
|
5775
6301
|
if (resolved.error || !resolved.request) {
|
|
5776
6302
|
return { text: resolved.error ?? "Cannot resolve storage object request.", isError: true };
|
|
5777
6303
|
}
|
|
5778
|
-
const
|
|
6304
|
+
const narrowed = toStorageObjectRequestOrError(
|
|
6305
|
+
resolved.request,
|
|
6306
|
+
`Cannot download file: required arguments are ${REQUIRED_STORAGE_OBJECT}.`
|
|
6307
|
+
);
|
|
6308
|
+
if (!narrowed.ok) {
|
|
6309
|
+
return { text: narrowed.error, isError: true };
|
|
6310
|
+
}
|
|
6311
|
+
const resolvedRequest = narrowed.request;
|
|
5779
6312
|
if (resolved.degradedWarning) {
|
|
5780
6313
|
await emitCloudEventBestEffort(
|
|
5781
6314
|
"name_resolution.degraded",
|
|
@@ -5873,7 +6406,14 @@ ${downloadText}` : downloadText
|
|
|
5873
6406
|
if (resolved.error || !resolved.request) {
|
|
5874
6407
|
return { text: resolved.error ?? "Cannot resolve storage object request.", isError: true };
|
|
5875
6408
|
}
|
|
5876
|
-
const
|
|
6409
|
+
const narrowedDelete = toStorageObjectRequestOrError(
|
|
6410
|
+
resolved.request,
|
|
6411
|
+
`Cannot delete file: required arguments are ${REQUIRED_STORAGE_OBJECT}.`
|
|
6412
|
+
);
|
|
6413
|
+
if (!narrowedDelete.ok) {
|
|
6414
|
+
return { text: narrowedDelete.error, isError: true };
|
|
6415
|
+
}
|
|
6416
|
+
const resolvedRequest = narrowedDelete.request;
|
|
5877
6417
|
if (resolved.degradedWarning) {
|
|
5878
6418
|
await emitCloudEventBestEffort(
|
|
5879
6419
|
"name_resolution.degraded",
|