@ouro.bot/cli 0.1.0-alpha.478 → 0.1.0-alpha.479
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/changelog.json
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
|
|
3
3
|
"versions": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.1.0-alpha.479",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Hosted Outlook mailbox reads now stay on the visible recent slice instead of requesting 500 full hosted messages, so Slugger's live mailbox can load again after the large HEY archive import.",
|
|
8
|
+
"Hosted Blob mail reads and index backfills now use bounded fan-out plus per-blob timeouts, which keeps large Azure Blob sweeps from hanging forever when one request stalls.",
|
|
9
|
+
"Ouro Outlook now treats missing old private mail keys as recovery state instead of a full mailbox outage: readable mail still renders, undecryptable counts surface in recovery, and the wrapper stays version-synced for the hosted mail stability release."
|
|
10
|
+
]
|
|
11
|
+
},
|
|
4
12
|
{
|
|
5
13
|
"version": "0.1.0-alpha.478",
|
|
6
14
|
"changes": [
|
|
@@ -7,7 +7,7 @@ const file_store_1 = require("../../../mailroom/file-store");
|
|
|
7
7
|
const reader_1 = require("../../../mailroom/reader");
|
|
8
8
|
const core_1 = require("../../../mailroom/core");
|
|
9
9
|
const OUTLOOK_MAIL_LIST_LIMIT = 50;
|
|
10
|
-
const
|
|
10
|
+
const OUTLOOK_MAIL_SUMMARY_LIMIT = OUTLOOK_MAIL_LIST_LIMIT;
|
|
11
11
|
const OUTLOOK_MAIL_BODY_LIMIT = 12_000;
|
|
12
12
|
function emptyFolders() {
|
|
13
13
|
return [
|
|
@@ -22,7 +22,7 @@ function emptyFolders() {
|
|
|
22
22
|
];
|
|
23
23
|
}
|
|
24
24
|
function emptyRecovery() {
|
|
25
|
-
return { discardedCount: 0, quarantineCount: 0 };
|
|
25
|
+
return { discardedCount: 0, quarantineCount: 0, undecryptableCount: 0, missingKeyIds: [] };
|
|
26
26
|
}
|
|
27
27
|
function unavailableMailView(agentName, status, error) {
|
|
28
28
|
return {
|
|
@@ -81,6 +81,26 @@ function mailSummary(message) {
|
|
|
81
81
|
provenance,
|
|
82
82
|
};
|
|
83
83
|
}
|
|
84
|
+
function missingPrivateMailKeyId(error) {
|
|
85
|
+
const match = /^(?:Error: )?Missing private mail key ([^\s]+)$/.exec(String(error));
|
|
86
|
+
return match?.[1] ?? null;
|
|
87
|
+
}
|
|
88
|
+
function decryptVisibleMessages(messages, privateKeys) {
|
|
89
|
+
const decrypted = [];
|
|
90
|
+
const skipped = [];
|
|
91
|
+
for (const message of messages) {
|
|
92
|
+
try {
|
|
93
|
+
decrypted.push((0, file_store_1.decryptMessages)([message], privateKeys)[0]);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
const keyId = missingPrivateMailKeyId(error);
|
|
97
|
+
if (!keyId)
|
|
98
|
+
throw error;
|
|
99
|
+
skipped.push({ messageId: message.id, keyId });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return { decrypted, skipped };
|
|
103
|
+
}
|
|
84
104
|
function buildFolders(messages, outbound) {
|
|
85
105
|
const folders = [
|
|
86
106
|
{ id: "imbox", label: "Imbox", count: messages.filter((message) => message.placement === "imbox").length },
|
|
@@ -188,10 +208,12 @@ function outboundRecord(record) {
|
|
|
188
208
|
reason: record.reason,
|
|
189
209
|
};
|
|
190
210
|
}
|
|
191
|
-
function buildRecovery(messages) {
|
|
211
|
+
function buildRecovery(messages, skipped = []) {
|
|
192
212
|
return {
|
|
193
213
|
discardedCount: messages.filter((message) => message.placement === "discarded").length,
|
|
194
214
|
quarantineCount: messages.filter((message) => message.placement === "quarantine").length,
|
|
215
|
+
undecryptableCount: skipped.length,
|
|
216
|
+
missingKeyIds: [...new Set(skipped.map((entry) => entry.keyId))].sort(),
|
|
195
217
|
};
|
|
196
218
|
}
|
|
197
219
|
function accessEntries(entries) {
|
|
@@ -240,9 +262,9 @@ async function readMailView(agentName) {
|
|
|
240
262
|
return unavailableMailView(agentName, status, resolved.error);
|
|
241
263
|
}
|
|
242
264
|
try {
|
|
243
|
-
const stored = await resolved.store.listMessages({ agentId: agentName, limit:
|
|
244
|
-
const
|
|
245
|
-
const summaries = decrypted.map(mailSummary);
|
|
265
|
+
const stored = await resolved.store.listMessages({ agentId: agentName, limit: OUTLOOK_MAIL_SUMMARY_LIMIT });
|
|
266
|
+
const result = decryptVisibleMessages(stored, resolved.config.privateKeys);
|
|
267
|
+
const summaries = result.decrypted.map(mailSummary);
|
|
246
268
|
const screener = (await resolved.store.listScreenerCandidates({ agentId: agentName, status: "pending", limit: 100 }))
|
|
247
269
|
.map(screenerCandidate);
|
|
248
270
|
const outbound = (await resolved.store.listMailOutbound(agentName)).map(outboundRecord);
|
|
@@ -266,7 +288,7 @@ async function readMailView(agentName) {
|
|
|
266
288
|
messages: summaries.slice(0, OUTLOOK_MAIL_LIST_LIMIT),
|
|
267
289
|
screener,
|
|
268
290
|
outbound,
|
|
269
|
-
recovery: buildRecovery(summaries),
|
|
291
|
+
recovery: buildRecovery(summaries, result.skipped),
|
|
270
292
|
accessLog,
|
|
271
293
|
error: null,
|
|
272
294
|
};
|
|
@@ -8,7 +8,9 @@ const MESSAGE_INDEX_PREFIX = "message-index";
|
|
|
8
8
|
const MESSAGE_INDEX_SORT_MAX_MS = 9_999_999_999_999;
|
|
9
9
|
const MESSAGE_INDEX_SORT_WIDTH = 13;
|
|
10
10
|
const MESSAGE_INDEX_NO_SOURCE = "~";
|
|
11
|
-
const
|
|
11
|
+
const DEFAULT_BLOB_OPERATION_TIMEOUT_MS = 20_000;
|
|
12
|
+
const DEFAULT_MESSAGE_FETCH_CONCURRENCY = 20;
|
|
13
|
+
const DEFAULT_MESSAGE_INDEX_BACKFILL_CONCURRENCY = 8;
|
|
12
14
|
const MESSAGE_LIST_SCAN_CONCURRENCY = 32;
|
|
13
15
|
function compareNewestFirst(left, right) {
|
|
14
16
|
return Date.parse(right.receivedAt) - Date.parse(left.receivedAt);
|
|
@@ -19,10 +21,88 @@ function compareCandidatesNewestFirst(left, right) {
|
|
|
19
21
|
function blobText(value) {
|
|
20
22
|
return Buffer.from(`${JSON.stringify(value, null, 2)}\n`, "utf-8");
|
|
21
23
|
}
|
|
22
|
-
|
|
24
|
+
function positiveInteger(value, fallback) {
|
|
25
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
26
|
+
return fallback;
|
|
27
|
+
const normalized = Math.floor(value);
|
|
28
|
+
return normalized > 0 ? normalized : fallback;
|
|
29
|
+
}
|
|
30
|
+
function blobClientName(blob) {
|
|
31
|
+
return typeof blob.name === "string" && blob.name.trim().length > 0 ? blob.name : "<unknown-blob>";
|
|
32
|
+
}
|
|
33
|
+
function timeoutSignal(timeoutMs) {
|
|
34
|
+
if (typeof AbortSignal.timeout === "function") {
|
|
35
|
+
return {
|
|
36
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
37
|
+
dispose() {
|
|
38
|
+
return undefined;
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const controller = new AbortController();
|
|
43
|
+
const timer = setTimeout(() => controller.abort(new Error(`The operation timed out after ${timeoutMs}ms`)), timeoutMs);
|
|
44
|
+
return {
|
|
45
|
+
signal: controller.signal,
|
|
46
|
+
dispose() {
|
|
47
|
+
clearTimeout(timer);
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
async function withBlobOperationTimeout(timeoutMs, operation) {
|
|
52
|
+
const timeout = timeoutSignal(timeoutMs);
|
|
53
|
+
try {
|
|
54
|
+
return await operation(timeout.signal);
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
timeout.dispose();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function normalizeBlobOperationError(action, blob, timeoutMs, error) {
|
|
61
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
62
|
+
if ((error instanceof Error && error.name === "AbortError") || message.toLowerCase().includes("aborted")) {
|
|
63
|
+
return new Error(`${action} ${blobClientName(blob)} timed out after ${timeoutMs}ms`);
|
|
64
|
+
}
|
|
65
|
+
return new Error(`${action} ${blobClientName(blob)} failed: ${message}`);
|
|
66
|
+
}
|
|
67
|
+
async function downloadJson(blob, timeoutMs) {
|
|
23
68
|
if (!await blob.exists())
|
|
24
69
|
return null;
|
|
25
|
-
|
|
70
|
+
try {
|
|
71
|
+
const buffer = await withBlobOperationTimeout(timeoutMs, (abortSignal) => {
|
|
72
|
+
return blob.downloadToBuffer(undefined, undefined, { abortSignal });
|
|
73
|
+
});
|
|
74
|
+
return JSON.parse(buffer.toString("utf-8"));
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
throw normalizeBlobOperationError("download", blob, timeoutMs, error);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async function uploadJson(blob, value, timeoutMs) {
|
|
81
|
+
try {
|
|
82
|
+
await withBlobOperationTimeout(timeoutMs, (abortSignal) => {
|
|
83
|
+
return blob.uploadData(blobText(value), { abortSignal });
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
throw normalizeBlobOperationError("upload", blob, timeoutMs, error);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async function mapWithConcurrency(items, concurrency, worker) {
|
|
91
|
+
if (items.length === 0)
|
|
92
|
+
return [];
|
|
93
|
+
const results = new Array(items.length);
|
|
94
|
+
let nextIndex = 0;
|
|
95
|
+
const workerLoop = async () => {
|
|
96
|
+
while (true) {
|
|
97
|
+
const current = nextIndex;
|
|
98
|
+
nextIndex += 1;
|
|
99
|
+
if (current >= items.length)
|
|
100
|
+
return;
|
|
101
|
+
results[current] = await worker(items[current], current);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, async () => workerLoop()));
|
|
105
|
+
return results;
|
|
26
106
|
}
|
|
27
107
|
function encodeSourceToken(source) {
|
|
28
108
|
return source ? encodeURIComponent(source.toLowerCase()) : MESSAGE_INDEX_NO_SOURCE;
|
|
@@ -94,10 +174,16 @@ function messageMatchesFilters(message, filters) {
|
|
|
94
174
|
class AzureBlobMailroomStore {
|
|
95
175
|
serviceClient;
|
|
96
176
|
containerName;
|
|
177
|
+
blobOperationTimeoutMs;
|
|
178
|
+
messageFetchConcurrency;
|
|
179
|
+
backfillConcurrency;
|
|
97
180
|
containerReady = null;
|
|
98
181
|
constructor(options) {
|
|
99
182
|
this.serviceClient = options.serviceClient;
|
|
100
183
|
this.containerName = options.containerName;
|
|
184
|
+
this.blobOperationTimeoutMs = positiveInteger(options.blobOperationTimeoutMs, DEFAULT_BLOB_OPERATION_TIMEOUT_MS);
|
|
185
|
+
this.messageFetchConcurrency = positiveInteger(options.messageFetchConcurrency, DEFAULT_MESSAGE_FETCH_CONCURRENCY);
|
|
186
|
+
this.backfillConcurrency = positiveInteger(options.backfillConcurrency, DEFAULT_MESSAGE_INDEX_BACKFILL_CONCURRENCY);
|
|
101
187
|
(0, runtime_1.emitNervesEvent)({
|
|
102
188
|
component: "senses",
|
|
103
189
|
event: "senses.mail_blob_store_init",
|
|
@@ -136,7 +222,7 @@ class AzureBlobMailroomStore {
|
|
|
136
222
|
return this.container.getBlockBlobClient(`outbound/${id}.json`);
|
|
137
223
|
}
|
|
138
224
|
async putMessageIndex(message) {
|
|
139
|
-
await this.messageIndexBlob(messageIndexBlobName(message))
|
|
225
|
+
await uploadJson(this.messageIndexBlob(messageIndexBlobName(message)), messageIndexRecord(message), this.blobOperationTimeoutMs);
|
|
140
226
|
}
|
|
141
227
|
async removeMessageIndex(message) {
|
|
142
228
|
await this.messageIndexBlob(messageIndexBlobName(message)).deleteIfExists();
|
|
@@ -153,7 +239,7 @@ class AzureBlobMailroomStore {
|
|
|
153
239
|
while (nextIndex < messageBlobNames.length) {
|
|
154
240
|
const current = messageBlobNames[nextIndex];
|
|
155
241
|
nextIndex += 1;
|
|
156
|
-
const message = await downloadJson(this.container.getBlockBlobClient(current));
|
|
242
|
+
const message = await downloadJson(this.container.getBlockBlobClient(current), this.blobOperationTimeoutMs);
|
|
157
243
|
if (!message || !messageMatchesFilters(message, filters))
|
|
158
244
|
continue;
|
|
159
245
|
matches.push(message);
|
|
@@ -179,7 +265,9 @@ class AzureBlobMailroomStore {
|
|
|
179
265
|
}
|
|
180
266
|
if (!sawIndex)
|
|
181
267
|
return null;
|
|
182
|
-
return (await
|
|
268
|
+
return (await mapWithConcurrency(messageIds, this.messageFetchConcurrency, async (id) => {
|
|
269
|
+
return downloadJson(this.messageBlob(id), this.blobOperationTimeoutMs);
|
|
270
|
+
}))
|
|
183
271
|
.filter((message) => message !== null)
|
|
184
272
|
.filter((message) => messageMatchesFilters(message, filters))
|
|
185
273
|
.sort(compareNewestFirst)
|
|
@@ -192,21 +280,31 @@ class AzureBlobMailroomStore {
|
|
|
192
280
|
messageBlobNames.push(item.name);
|
|
193
281
|
}
|
|
194
282
|
let indexed = 0;
|
|
283
|
+
const failures = [];
|
|
195
284
|
let nextIndex = 0;
|
|
196
285
|
const worker = async () => {
|
|
197
286
|
while (nextIndex < messageBlobNames.length) {
|
|
198
287
|
const current = messageBlobNames[nextIndex];
|
|
199
288
|
nextIndex += 1;
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
289
|
+
try {
|
|
290
|
+
const message = await downloadJson(this.container.getBlockBlobClient(current), this.blobOperationTimeoutMs);
|
|
291
|
+
if (!message)
|
|
292
|
+
continue;
|
|
293
|
+
if (agentId && message.agentId !== agentId)
|
|
294
|
+
continue;
|
|
295
|
+
await uploadJson(this.messageIndexBlob(messageIndexBlobName(message)), messageIndexRecord(message), this.blobOperationTimeoutMs);
|
|
296
|
+
indexed += 1;
|
|
297
|
+
}
|
|
298
|
+
catch (error) {
|
|
299
|
+
failures.push(error instanceof Error ? error.message : String(error));
|
|
300
|
+
}
|
|
207
301
|
}
|
|
208
302
|
};
|
|
209
|
-
await Promise.all(Array.from({ length: Math.min(
|
|
303
|
+
await Promise.all(Array.from({ length: Math.min(this.backfillConcurrency, Math.max(messageBlobNames.length, 1)) }, async () => worker()));
|
|
304
|
+
if (failures.length > 0) {
|
|
305
|
+
const sample = failures.slice(0, 3).join("; ");
|
|
306
|
+
throw new Error(`hosted message index backfill incomplete after indexing ${indexed} message(s); ${failures.length} blob operation(s) failed. first failure(s): ${sample}. rerun the command to retry remaining messages.`);
|
|
307
|
+
}
|
|
210
308
|
(0, runtime_1.emitNervesEvent)({
|
|
211
309
|
component: "senses",
|
|
212
310
|
event: "senses.mail_blob_index_backfilled",
|
|
@@ -218,7 +316,7 @@ class AzureBlobMailroomStore {
|
|
|
218
316
|
async putRawMessage(input) {
|
|
219
317
|
await this.ensureContainer();
|
|
220
318
|
const { message, rawPayload, candidate } = await (0, core_1.buildStoredMailMessage)(input);
|
|
221
|
-
const existing = await downloadJson(this.messageBlob(message.id));
|
|
319
|
+
const existing = await downloadJson(this.messageBlob(message.id), this.blobOperationTimeoutMs);
|
|
222
320
|
if (existing) {
|
|
223
321
|
await this.putMessageIndex(existing);
|
|
224
322
|
(0, runtime_1.emitNervesEvent)({
|
|
@@ -245,7 +343,7 @@ class AzureBlobMailroomStore {
|
|
|
245
343
|
}
|
|
246
344
|
async getMessage(id) {
|
|
247
345
|
await this.ensureContainer();
|
|
248
|
-
const message = await downloadJson(this.messageBlob(id));
|
|
346
|
+
const message = await downloadJson(this.messageBlob(id), this.blobOperationTimeoutMs);
|
|
249
347
|
(0, runtime_1.emitNervesEvent)({
|
|
250
348
|
component: "senses",
|
|
251
349
|
event: "senses.mail_blob_store_message_read",
|
|
@@ -273,7 +371,7 @@ class AzureBlobMailroomStore {
|
|
|
273
371
|
async updateMessagePlacement(id, placement) {
|
|
274
372
|
await this.ensureContainer();
|
|
275
373
|
const blob = this.messageBlob(id);
|
|
276
|
-
const message = await downloadJson(blob);
|
|
374
|
+
const message = await downloadJson(blob, this.blobOperationTimeoutMs);
|
|
277
375
|
if (!message) {
|
|
278
376
|
(0, runtime_1.emitNervesEvent)({
|
|
279
377
|
component: "senses",
|
|
@@ -297,7 +395,7 @@ class AzureBlobMailroomStore {
|
|
|
297
395
|
}
|
|
298
396
|
async readRawPayload(objectName) {
|
|
299
397
|
await this.ensureContainer();
|
|
300
|
-
const payload = await downloadJson(this.rawBlob(objectName));
|
|
398
|
+
const payload = await downloadJson(this.rawBlob(objectName), this.blobOperationTimeoutMs);
|
|
301
399
|
(0, runtime_1.emitNervesEvent)({
|
|
302
400
|
component: "senses",
|
|
303
401
|
event: "senses.mail_blob_store_raw_read",
|
|
@@ -324,7 +422,7 @@ class AzureBlobMailroomStore {
|
|
|
324
422
|
await this.ensureContainer();
|
|
325
423
|
const candidates = [];
|
|
326
424
|
for await (const item of this.container.listBlobsFlat({ prefix: "candidates/" })) {
|
|
327
|
-
const candidate = await downloadJson(this.container.getBlockBlobClient(item.name));
|
|
425
|
+
const candidate = await downloadJson(this.container.getBlockBlobClient(item.name), this.blobOperationTimeoutMs);
|
|
328
426
|
if (candidate)
|
|
329
427
|
candidates.push(candidate);
|
|
330
428
|
}
|
|
@@ -351,7 +449,7 @@ class AzureBlobMailroomStore {
|
|
|
351
449
|
createdAt: entry.createdAt ?? new Date().toISOString(),
|
|
352
450
|
};
|
|
353
451
|
const blob = this.decisionsBlob(entry.agentId);
|
|
354
|
-
const existing = await downloadJson(blob).catch(() => null);
|
|
452
|
+
const existing = await downloadJson(blob, this.blobOperationTimeoutMs).catch(() => null);
|
|
355
453
|
const entries = Array.isArray(existing) ? existing : [];
|
|
356
454
|
entries.push(complete);
|
|
357
455
|
await blob.uploadData(blobText(entries));
|
|
@@ -365,7 +463,7 @@ class AzureBlobMailroomStore {
|
|
|
365
463
|
}
|
|
366
464
|
async listMailDecisions(agentId) {
|
|
367
465
|
await this.ensureContainer();
|
|
368
|
-
const entries = await downloadJson(this.decisionsBlob(agentId));
|
|
466
|
+
const entries = await downloadJson(this.decisionsBlob(agentId), this.blobOperationTimeoutMs);
|
|
369
467
|
const safeEntries = Array.isArray(entries) ? entries : [];
|
|
370
468
|
(0, runtime_1.emitNervesEvent)({
|
|
371
469
|
component: "senses",
|
|
@@ -388,7 +486,7 @@ class AzureBlobMailroomStore {
|
|
|
388
486
|
}
|
|
389
487
|
async getMailOutbound(id) {
|
|
390
488
|
await this.ensureContainer();
|
|
391
|
-
const record = await downloadJson(this.outboundBlob(id));
|
|
489
|
+
const record = await downloadJson(this.outboundBlob(id), this.blobOperationTimeoutMs);
|
|
392
490
|
(0, runtime_1.emitNervesEvent)({
|
|
393
491
|
component: "senses",
|
|
394
492
|
event: "senses.mail_blob_outbound_record_read",
|
|
@@ -401,7 +499,7 @@ class AzureBlobMailroomStore {
|
|
|
401
499
|
await this.ensureContainer();
|
|
402
500
|
const records = [];
|
|
403
501
|
for await (const item of this.container.listBlobsFlat({ prefix: "outbound/" })) {
|
|
404
|
-
const record = await downloadJson(this.container.getBlockBlobClient(item.name));
|
|
502
|
+
const record = await downloadJson(this.container.getBlockBlobClient(item.name), this.blobOperationTimeoutMs);
|
|
405
503
|
if (record)
|
|
406
504
|
records.push(record);
|
|
407
505
|
}
|
|
@@ -424,7 +522,7 @@ class AzureBlobMailroomStore {
|
|
|
424
522
|
accessedAt: new Date().toISOString(),
|
|
425
523
|
};
|
|
426
524
|
const blob = this.accessLogBlob(entry.agentId);
|
|
427
|
-
const existing = await downloadJson(blob).catch(() => null);
|
|
525
|
+
const existing = await downloadJson(blob, this.blobOperationTimeoutMs).catch(() => null);
|
|
428
526
|
const entries = Array.isArray(existing) ? existing : [];
|
|
429
527
|
entries.push(complete);
|
|
430
528
|
await blob.uploadData(blobText(entries));
|
|
@@ -438,7 +536,7 @@ class AzureBlobMailroomStore {
|
|
|
438
536
|
}
|
|
439
537
|
async listAccessLog(agentId) {
|
|
440
538
|
await this.ensureContainer();
|
|
441
|
-
const entries = await downloadJson(this.accessLogBlob(agentId));
|
|
539
|
+
const entries = await downloadJson(this.accessLogBlob(agentId), this.blobOperationTimeoutMs);
|
|
442
540
|
const safeEntries = Array.isArray(entries) ? entries : [];
|
|
443
541
|
(0, runtime_1.emitNervesEvent)({
|
|
444
542
|
component: "senses",
|