nexus-agentd 0.1.0 → 0.1.6
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/LICENSE +22 -0
- package/README.md +351 -179
- package/dist/a2a/runtime.d.ts +30 -0
- package/dist/a2a/runtime.js +374 -0
- package/dist/acp/runtime.d.ts +12 -3
- package/dist/acp/runtime.js +248 -17
- package/dist/artifact-store.d.ts +41 -0
- package/dist/artifact-store.js +340 -0
- package/dist/auth.d.ts +13 -0
- package/dist/auth.js +77 -0
- package/dist/cli.js +58 -1
- package/dist/config.d.ts +10 -0
- package/dist/config.js +281 -53
- package/dist/control-plane.d.ts +91 -0
- package/dist/control-plane.js +629 -0
- package/dist/drivers/hermes.d.ts +2 -0
- package/dist/drivers/hermes.js +10 -0
- package/dist/drivers/index.js +6 -0
- package/dist/events.js +13 -2
- package/dist/index.d.ts +6 -0
- package/dist/index.js +15 -3
- package/dist/run-store.d.ts +49 -0
- package/dist/run-store.js +291 -0
- package/dist/server.d.ts +3 -2
- package/dist/server.js +911 -41
- package/dist/session-contract.d.ts +16 -4
- package/dist/session.d.ts +74 -8
- package/dist/session.js +433 -38
- package/dist/types.d.ts +193 -6
- package/dist/types.js +2 -1
- package/dist/webui/app.d.ts +1 -0
- package/dist/webui/app.js +1072 -0
- package/dist/webui/icons.d.ts +9 -0
- package/dist/webui/icons.js +10 -0
- package/dist/webui/index.d.ts +3 -0
- package/dist/webui/index.js +32 -0
- package/dist/webui/markup.d.ts +1 -0
- package/dist/webui/markup.js +68 -0
- package/dist/webui/styles.d.ts +1 -0
- package/dist/webui/styles.js +269 -0
- package/dist/workspace-files.d.ts +48 -0
- package/dist/workspace-files.js +269 -0
- package/nexus-agentd.example.json +30 -27
- package/package.json +6 -6
package/dist/acp/runtime.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { mkdir, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
2
4
|
import { Readable, Writable } from 'node:stream';
|
|
5
|
+
import { pathToFileURL } from 'node:url';
|
|
3
6
|
import * as acp from '@agentclientprotocol/sdk';
|
|
4
7
|
export class AcpProcessRuntime {
|
|
5
8
|
driver;
|
|
@@ -10,13 +13,23 @@ export class AcpProcessRuntime {
|
|
|
10
13
|
pendingInput;
|
|
11
14
|
disposed = false;
|
|
12
15
|
prompting = false;
|
|
13
|
-
|
|
16
|
+
maxStderrChunkChars;
|
|
17
|
+
promptTimeoutMs;
|
|
18
|
+
promptCapabilities = {};
|
|
19
|
+
inputDirectory;
|
|
20
|
+
constructor(driver, sink, maxStderrChunkChars = 16 * 1024, promptTimeoutMs = 30 * 60 * 1000) {
|
|
14
21
|
this.driver = driver;
|
|
15
22
|
this.sink = sink;
|
|
23
|
+
const limit = Number.isFinite(maxStderrChunkChars)
|
|
24
|
+
? Math.floor(maxStderrChunkChars)
|
|
25
|
+
: 16 * 1024;
|
|
26
|
+
this.maxStderrChunkChars = Math.max(1, Math.min(16 * 1024, limit));
|
|
27
|
+
this.promptTimeoutMs = Math.max(10_000, Math.trunc(promptTimeoutMs));
|
|
16
28
|
}
|
|
17
29
|
async start(workspace) {
|
|
18
30
|
if (this.process)
|
|
19
31
|
throw new Error('ACP runtime is already started');
|
|
32
|
+
this.inputDirectory = path.join(workspace, '.nexus-inputs', this.sink.id);
|
|
20
33
|
const child = this.driver.spawn(workspace);
|
|
21
34
|
this.process = child;
|
|
22
35
|
this.captureStderr(child);
|
|
@@ -47,7 +60,7 @@ export class AcpProcessRuntime {
|
|
|
47
60
|
},
|
|
48
61
|
clientInfo: {
|
|
49
62
|
name: 'nexus-agentd',
|
|
50
|
-
version: '0.1.
|
|
63
|
+
version: '0.1.4'
|
|
51
64
|
}
|
|
52
65
|
});
|
|
53
66
|
if (initialize.protocolVersion !== acp.PROTOCOL_VERSION) {
|
|
@@ -56,6 +69,7 @@ export class AcpProcessRuntime {
|
|
|
56
69
|
text: `ACP negotiated protocol ${initialize.protocolVersion}`
|
|
57
70
|
});
|
|
58
71
|
}
|
|
72
|
+
this.promptCapabilities = initialize.agentCapabilities?.promptCapabilities || {};
|
|
59
73
|
const session = await this.connection.agent.request(acp.methods.agent.session.new, {
|
|
60
74
|
cwd: workspace,
|
|
61
75
|
mcpServers: []
|
|
@@ -63,7 +77,7 @@ export class AcpProcessRuntime {
|
|
|
63
77
|
this.sink.setAcpSessionId(String(session.sessionId));
|
|
64
78
|
this.sink.setState('created');
|
|
65
79
|
}
|
|
66
|
-
async prompt(message) {
|
|
80
|
+
async prompt(message, attachments = []) {
|
|
67
81
|
if (!this.connection)
|
|
68
82
|
throw new Error('ACP runtime is not connected');
|
|
69
83
|
if (this.prompting)
|
|
@@ -73,12 +87,13 @@ export class AcpProcessRuntime {
|
|
|
73
87
|
this.sink.clearPending();
|
|
74
88
|
this.sink.setState('running');
|
|
75
89
|
try {
|
|
76
|
-
const response = await this.connection.agent.request(acp.methods.agent.session.prompt, {
|
|
90
|
+
const response = await withTimeout(this.connection.agent.request(acp.methods.agent.session.prompt, {
|
|
77
91
|
sessionId,
|
|
78
|
-
prompt:
|
|
79
|
-
});
|
|
80
|
-
if (this.sink.state === 'canceled')
|
|
92
|
+
prompt: await this.promptBlocks(message, attachments)
|
|
93
|
+
}), this.promptTimeoutMs, 'ACP prompt timed out');
|
|
94
|
+
if (this.sink.state === 'canceled' || this.sink.state === 'failed') {
|
|
81
95
|
return;
|
|
96
|
+
}
|
|
82
97
|
if (response.stopReason === 'cancelled') {
|
|
83
98
|
this.sink.setState('canceled');
|
|
84
99
|
}
|
|
@@ -93,12 +108,14 @@ export class AcpProcessRuntime {
|
|
|
93
108
|
if (this.sink.state !== 'canceled') {
|
|
94
109
|
this.sink.setState('failed', error instanceof Error ? error.message : String(error));
|
|
95
110
|
}
|
|
111
|
+
if (error instanceof PromptTimeoutError)
|
|
112
|
+
await this.dispose();
|
|
96
113
|
}
|
|
97
114
|
finally {
|
|
98
115
|
this.prompting = false;
|
|
99
116
|
}
|
|
100
117
|
}
|
|
101
|
-
async respondPending(message) {
|
|
118
|
+
async respondPending(message, _attachments = []) {
|
|
102
119
|
if (this.pendingInput) {
|
|
103
120
|
this.finishInput(message);
|
|
104
121
|
return;
|
|
@@ -168,6 +185,10 @@ export class AcpProcessRuntime {
|
|
|
168
185
|
}
|
|
169
186
|
this.connection?.close();
|
|
170
187
|
this.connection = undefined;
|
|
188
|
+
if (this.inputDirectory) {
|
|
189
|
+
await rm(this.inputDirectory, { recursive: true, force: true }).catch(() => undefined);
|
|
190
|
+
this.inputDirectory = undefined;
|
|
191
|
+
}
|
|
171
192
|
const child = this.process;
|
|
172
193
|
this.process = undefined;
|
|
173
194
|
if (child && child.exitCode === null && child.signalCode === null) {
|
|
@@ -286,11 +307,15 @@ export class AcpProcessRuntime {
|
|
|
286
307
|
content: update.content
|
|
287
308
|
});
|
|
288
309
|
}
|
|
310
|
+
else {
|
|
311
|
+
this.captureArtifact(update.content, `message:${String(update.messageId || 'assistant')}:0`);
|
|
312
|
+
}
|
|
289
313
|
break;
|
|
290
314
|
case 'agent_thought_chunk':
|
|
291
315
|
this.sink.emit('thought_chunk', update);
|
|
292
316
|
break;
|
|
293
317
|
case 'tool_call':
|
|
318
|
+
this.captureToolArtifacts(String(update.toolCallId), update.content, update.title);
|
|
294
319
|
this.sink.emit('tool_call', update);
|
|
295
320
|
if (update.locations?.length) {
|
|
296
321
|
this.sink.emit('file_activity', {
|
|
@@ -300,6 +325,7 @@ export class AcpProcessRuntime {
|
|
|
300
325
|
}
|
|
301
326
|
break;
|
|
302
327
|
case 'tool_call_update':
|
|
328
|
+
this.captureToolArtifacts(String(update.toolCallId), update.content, update.title || update.name);
|
|
303
329
|
this.sink.emit('tool_update', update);
|
|
304
330
|
if (update.locations?.length) {
|
|
305
331
|
this.sink.emit('file_activity', {
|
|
@@ -317,21 +343,57 @@ export class AcpProcessRuntime {
|
|
|
317
343
|
break;
|
|
318
344
|
}
|
|
319
345
|
}
|
|
346
|
+
captureToolArtifacts(toolCallId, content, hint) {
|
|
347
|
+
content?.forEach((item, index) => {
|
|
348
|
+
if (item.type !== 'content')
|
|
349
|
+
return;
|
|
350
|
+
this.captureArtifact(item.content, `tool:${toolCallId}:${index}`, hint || undefined);
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
captureArtifact(content, id, hint) {
|
|
354
|
+
const artifact = artifactFromContent(content, id, hint);
|
|
355
|
+
if (artifact)
|
|
356
|
+
this.sink.addArtifact(artifact);
|
|
357
|
+
}
|
|
320
358
|
captureStderr(child) {
|
|
321
359
|
let buffer = '';
|
|
322
|
-
|
|
323
|
-
|
|
360
|
+
let flushed = false;
|
|
361
|
+
const emit = (text) => {
|
|
362
|
+
if (!text)
|
|
363
|
+
return;
|
|
364
|
+
for (let offset = 0; offset < text.length; offset += this.maxStderrChunkChars) {
|
|
365
|
+
this.sink.emit('terminal_output', {
|
|
366
|
+
stream: 'stderr',
|
|
367
|
+
text: text.slice(offset, offset + this.maxStderrChunkChars)
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
const drain = (flush = false) => {
|
|
324
372
|
const lines = buffer.split(/\r?\n/);
|
|
325
373
|
buffer = lines.pop() || '';
|
|
326
|
-
for (const line of lines)
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
});
|
|
332
|
-
}
|
|
374
|
+
for (const line of lines)
|
|
375
|
+
emit(line);
|
|
376
|
+
while (buffer.length >= this.maxStderrChunkChars) {
|
|
377
|
+
emit(buffer.slice(0, this.maxStderrChunkChars));
|
|
378
|
+
buffer = buffer.slice(this.maxStderrChunkChars);
|
|
333
379
|
}
|
|
380
|
+
if (flush && buffer) {
|
|
381
|
+
emit(buffer);
|
|
382
|
+
buffer = '';
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
const flush = () => {
|
|
386
|
+
if (flushed)
|
|
387
|
+
return;
|
|
388
|
+
flushed = true;
|
|
389
|
+
drain(true);
|
|
390
|
+
};
|
|
391
|
+
child.stderr.on('data', (chunk) => {
|
|
392
|
+
buffer += String(chunk);
|
|
393
|
+
drain();
|
|
334
394
|
});
|
|
395
|
+
child.stderr.once('end', flush);
|
|
396
|
+
child.stderr.once('close', flush);
|
|
335
397
|
}
|
|
336
398
|
onProcessFailure(error) {
|
|
337
399
|
if (this.disposed)
|
|
@@ -345,6 +407,175 @@ export class AcpProcessRuntime {
|
|
|
345
407
|
}
|
|
346
408
|
return value;
|
|
347
409
|
}
|
|
410
|
+
async promptBlocks(message, attachments) {
|
|
411
|
+
const blocks = [{ type: 'text', text: message }];
|
|
412
|
+
for (const attachment of attachments) {
|
|
413
|
+
const mediaType = attachment.mediaType || 'application/octet-stream';
|
|
414
|
+
const data = attachment.bytes.toString('base64');
|
|
415
|
+
if (mediaType.startsWith('image/') && this.promptCapabilities.image) {
|
|
416
|
+
blocks.push({ type: 'image', data, mimeType: mediaType });
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
if (mediaType.startsWith('audio/') && this.promptCapabilities.audio) {
|
|
420
|
+
blocks.push({ type: 'audio', data, mimeType: mediaType });
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
if (this.promptCapabilities.embeddedContext) {
|
|
424
|
+
blocks.push({
|
|
425
|
+
type: 'resource',
|
|
426
|
+
resource: {
|
|
427
|
+
uri: `nexus-input://${this.sink.id}/${encodeURIComponent(attachment.name)}`,
|
|
428
|
+
blob: data,
|
|
429
|
+
mimeType: mediaType
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
blocks.push(await this.writeResourceLink(attachment, mediaType));
|
|
435
|
+
}
|
|
436
|
+
return blocks;
|
|
437
|
+
}
|
|
438
|
+
async writeResourceLink(attachment, mediaType) {
|
|
439
|
+
const directory = this.inputDirectory || path.join(process.cwd(), '.nexus-inputs', this.sink.id);
|
|
440
|
+
this.inputDirectory = directory;
|
|
441
|
+
await mkdir(directory, { recursive: true });
|
|
442
|
+
const filename = `${attachment.id}-${safeFilename(attachment.name) || 'attachment'}`;
|
|
443
|
+
const filePath = path.join(directory, filename);
|
|
444
|
+
await writeFile(filePath, attachment.bytes, { mode: 0o600 });
|
|
445
|
+
return {
|
|
446
|
+
type: 'resource_link',
|
|
447
|
+
name: attachment.name,
|
|
448
|
+
uri: pathToFileURL(filePath).toString(),
|
|
449
|
+
mimeType: mediaType,
|
|
450
|
+
size: attachment.bytes.length
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
class PromptTimeoutError extends Error {
|
|
455
|
+
}
|
|
456
|
+
function safeFilename(value) {
|
|
457
|
+
return String(value || '')
|
|
458
|
+
.replace(/[<>:"/\\|?*\u0000-\u001f]/g, '_')
|
|
459
|
+
.trim()
|
|
460
|
+
.slice(0, 180);
|
|
461
|
+
}
|
|
462
|
+
function withTimeout(promise, timeoutMs, message) {
|
|
463
|
+
let timer;
|
|
464
|
+
const timeout = new Promise((_, reject) => {
|
|
465
|
+
timer = setTimeout(() => reject(new PromptTimeoutError(message)), timeoutMs);
|
|
466
|
+
timer.unref?.();
|
|
467
|
+
});
|
|
468
|
+
return Promise.race([promise, timeout]).finally(() => {
|
|
469
|
+
if (timer)
|
|
470
|
+
clearTimeout(timer);
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
function artifactFromContent(content, id, hint) {
|
|
474
|
+
switch (content.type) {
|
|
475
|
+
case 'image': {
|
|
476
|
+
const filename = artifactFilename(content.uri, hint, `image-${artifactIndex(id)}`, content.mimeType);
|
|
477
|
+
return {
|
|
478
|
+
id,
|
|
479
|
+
name: filename,
|
|
480
|
+
filename,
|
|
481
|
+
mediaType: content.mimeType,
|
|
482
|
+
bytesBase64: content.data,
|
|
483
|
+
url: usableUrl(content.uri),
|
|
484
|
+
metadata: artifactMetadata(id, content.uri, content.annotations)
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
case 'audio': {
|
|
488
|
+
const filename = artifactFilename(undefined, hint, `audio-${artifactIndex(id)}`, content.mimeType);
|
|
489
|
+
return {
|
|
490
|
+
id,
|
|
491
|
+
name: filename,
|
|
492
|
+
filename,
|
|
493
|
+
mediaType: content.mimeType,
|
|
494
|
+
bytesBase64: content.data,
|
|
495
|
+
metadata: artifactMetadata(id, undefined, content.annotations)
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
case 'resource_link': {
|
|
499
|
+
const filename = artifactFilename(content.uri, content.name || hint, `resource-${artifactIndex(id)}`, content.mimeType || undefined);
|
|
500
|
+
return {
|
|
501
|
+
id,
|
|
502
|
+
name: content.title || content.name || filename,
|
|
503
|
+
description: content.description || undefined,
|
|
504
|
+
filename,
|
|
505
|
+
mediaType: content.mimeType || undefined,
|
|
506
|
+
url: content.uri,
|
|
507
|
+
metadata: artifactMetadata(id, content.uri, content.annotations, content.size ?? undefined)
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
case 'resource': {
|
|
511
|
+
const resource = content.resource;
|
|
512
|
+
const filename = artifactFilename(resource.uri, hint, `resource-${artifactIndex(id)}`, resource.mimeType || undefined);
|
|
513
|
+
return {
|
|
514
|
+
id,
|
|
515
|
+
name: filename,
|
|
516
|
+
filename,
|
|
517
|
+
mediaType: resource.mimeType || undefined,
|
|
518
|
+
text: 'text' in resource ? resource.text : undefined,
|
|
519
|
+
bytesBase64: 'blob' in resource ? resource.blob : undefined,
|
|
520
|
+
url: usableUrl(resource.uri),
|
|
521
|
+
metadata: artifactMetadata(id, resource.uri, content.annotations)
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
default:
|
|
525
|
+
return undefined;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
function artifactMetadata(sourceId, uri, annotations, size) {
|
|
529
|
+
return {
|
|
530
|
+
sourceId,
|
|
531
|
+
...(uri ? { uri } : {}),
|
|
532
|
+
...(size !== undefined ? { size } : {}),
|
|
533
|
+
...(annotations ? { annotations } : {})
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
function artifactFilename(uri, hint, fallback, mediaType) {
|
|
537
|
+
return (filenameFromValue(uri) ||
|
|
538
|
+
filenameFromValue(hint) ||
|
|
539
|
+
`${fallback}${extensionForMediaType(mediaType)}`);
|
|
540
|
+
}
|
|
541
|
+
function filenameFromValue(value) {
|
|
542
|
+
if (!value)
|
|
543
|
+
return undefined;
|
|
544
|
+
let candidate = value;
|
|
545
|
+
try {
|
|
546
|
+
candidate = new URL(value).pathname;
|
|
547
|
+
}
|
|
548
|
+
catch { }
|
|
549
|
+
candidate = candidate.split(/[\\/]/).pop() || candidate;
|
|
550
|
+
candidate = candidate.split(/[?#]/, 1)[0].trim();
|
|
551
|
+
const filename = candidate.match(/([^\s]+\.[A-Za-z0-9]{1,16})$/)?.[1];
|
|
552
|
+
if (!filename)
|
|
553
|
+
return undefined;
|
|
554
|
+
try {
|
|
555
|
+
return decodeURIComponent(filename);
|
|
556
|
+
}
|
|
557
|
+
catch {
|
|
558
|
+
return filename;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
function usableUrl(value) {
|
|
562
|
+
return value && /^(?:https?|file):/i.test(value) ? value : undefined;
|
|
563
|
+
}
|
|
564
|
+
function artifactIndex(id) {
|
|
565
|
+
return id.split(':').pop() || 'output';
|
|
566
|
+
}
|
|
567
|
+
function extensionForMediaType(mediaType) {
|
|
568
|
+
const extensions = {
|
|
569
|
+
'image/png': '.png',
|
|
570
|
+
'image/jpeg': '.jpg',
|
|
571
|
+
'image/gif': '.gif',
|
|
572
|
+
'image/webp': '.webp',
|
|
573
|
+
'audio/mpeg': '.mp3',
|
|
574
|
+
'audio/wav': '.wav',
|
|
575
|
+
'audio/ogg': '.ogg',
|
|
576
|
+
'application/pdf': '.pdf'
|
|
577
|
+
};
|
|
578
|
+
return mediaType ? extensions[mediaType.toLowerCase()] || '' : '';
|
|
348
579
|
}
|
|
349
580
|
function elicitationOptions(params) {
|
|
350
581
|
if (!isFormElicitation(params))
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type FileHandle } from 'node:fs/promises';
|
|
2
|
+
import { type Readable } from 'node:stream';
|
|
3
|
+
import type { AgentdPublishedFile } from './types.js';
|
|
4
|
+
interface StoredArtifact extends AgentdPublishedFile {
|
|
5
|
+
filePath: string;
|
|
6
|
+
handle?: FileHandle;
|
|
7
|
+
}
|
|
8
|
+
export declare class ArtifactStoreError extends Error {
|
|
9
|
+
readonly status: number;
|
|
10
|
+
constructor(status: number, message: string);
|
|
11
|
+
}
|
|
12
|
+
export declare class GatewayArtifactStore {
|
|
13
|
+
private readonly directory;
|
|
14
|
+
private readonly ttlMs;
|
|
15
|
+
private readonly maxBytes;
|
|
16
|
+
private readonly maxStorageBytes;
|
|
17
|
+
private readonly maxFiles;
|
|
18
|
+
private readonly maxConcurrentPublishes;
|
|
19
|
+
private readonly byCacheKey;
|
|
20
|
+
private cleanupTimer?;
|
|
21
|
+
private capacityQueue;
|
|
22
|
+
private activePublishes;
|
|
23
|
+
private reservedBytes;
|
|
24
|
+
private reservedFiles;
|
|
25
|
+
constructor(directory: string, ttlMs: number, maxBytes: number, maxStorageBytes?: number, maxFiles?: number, maxConcurrentPublishes?: number);
|
|
26
|
+
startCleanup(intervalMs?: number): void;
|
|
27
|
+
stopCleanup(): void;
|
|
28
|
+
publishFile(filePath: string, preferredName?: string, mediaType?: string): Promise<AgentdPublishedFile>;
|
|
29
|
+
publishHandle(handle: FileHandle, preferredName: string, mediaType?: string): Promise<AgentdPublishedFile>;
|
|
30
|
+
publishBytes(bytes: Uint8Array, preferredName: string, mediaType?: string, cacheKey?: string): Promise<AgentdPublishedFile>;
|
|
31
|
+
publishStream(input: Readable, preferredName: string, mediaType?: string, declaredSize?: number, cacheKey?: string): Promise<AgentdPublishedFile>;
|
|
32
|
+
open(id: string, expiresInput: string, requestedName: string): Promise<StoredArtifact>;
|
|
33
|
+
cleanup(): Promise<void>;
|
|
34
|
+
private ensureDirectory;
|
|
35
|
+
private isAvailable;
|
|
36
|
+
private reserveCapacity;
|
|
37
|
+
private storageUsage;
|
|
38
|
+
}
|
|
39
|
+
export declare function contentDisposition(name: string): string;
|
|
40
|
+
export declare function mediaTypeForName(name: string): string;
|
|
41
|
+
export {};
|