@covia/covia-sdk 1.6.0 → 1.7.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/README.md +61 -2
- package/dist/index.d.mts +221 -9
- package/dist/index.d.ts +221 -9
- package/dist/index.js +360 -50
- package/dist/index.mjs +349 -51
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -8,18 +8,18 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
|
|
|
8
8
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
9
9
|
|
|
10
10
|
// src/types.ts
|
|
11
|
-
var RunStatus = /* @__PURE__ */ ((
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return
|
|
11
|
+
var RunStatus = /* @__PURE__ */ ((RunStatus3) => {
|
|
12
|
+
RunStatus3["COMPLETE"] = "COMPLETE";
|
|
13
|
+
RunStatus3["FAILED"] = "FAILED";
|
|
14
|
+
RunStatus3["PENDING"] = "PENDING";
|
|
15
|
+
RunStatus3["STARTED"] = "STARTED";
|
|
16
|
+
RunStatus3["CANCELLED"] = "CANCELLED";
|
|
17
|
+
RunStatus3["TIMEOUT"] = "TIMEOUT";
|
|
18
|
+
RunStatus3["REJECTED"] = "REJECTED";
|
|
19
|
+
RunStatus3["INPUT_REQUIRED"] = "INPUT_REQUIRED";
|
|
20
|
+
RunStatus3["AUTH_REQUIRED"] = "AUTH_REQUIRED";
|
|
21
|
+
RunStatus3["PAUSED"] = "PAUSED";
|
|
22
|
+
return RunStatus3;
|
|
23
23
|
})(RunStatus || {});
|
|
24
24
|
var JobStatus = RunStatus;
|
|
25
25
|
var AgentStatus = /* @__PURE__ */ ((AgentStatus2) => {
|
|
@@ -72,6 +72,13 @@ var JobFailedError = class extends CoviaError {
|
|
|
72
72
|
this.jobData = jobData;
|
|
73
73
|
}
|
|
74
74
|
};
|
|
75
|
+
var RateLimitError = class extends GridError {
|
|
76
|
+
constructor(message, retryAfterSeconds, body) {
|
|
77
|
+
super(429, message, body);
|
|
78
|
+
this.retryAfterSeconds = retryAfterSeconds;
|
|
79
|
+
this.name = "RateLimitError";
|
|
80
|
+
}
|
|
81
|
+
};
|
|
75
82
|
var NotFoundError = class extends GridError {
|
|
76
83
|
constructor(message) {
|
|
77
84
|
super(404, message);
|
|
@@ -1309,22 +1316,55 @@ function wrapError(error) {
|
|
|
1309
1316
|
}
|
|
1310
1317
|
return new CoviaError(`Request failed: ${msg}`);
|
|
1311
1318
|
}
|
|
1319
|
+
var RETRY_MAX_ATTEMPTS = 4;
|
|
1320
|
+
var RETRY_BASE_MS = 200;
|
|
1321
|
+
var RETRY_MAX_DELAY_MS = 1e4;
|
|
1322
|
+
var RETRY_BUDGET_MS = 3e4;
|
|
1323
|
+
function parseRetryAfterMs(header, nowMs) {
|
|
1324
|
+
if (!header) return 0;
|
|
1325
|
+
const secs = Number(header);
|
|
1326
|
+
if (Number.isFinite(secs)) return Math.max(0, secs * 1e3);
|
|
1327
|
+
const date = Date.parse(header);
|
|
1328
|
+
return Number.isFinite(date) ? Math.max(0, date - nowMs) : 0;
|
|
1329
|
+
}
|
|
1330
|
+
function retryDelayMs(attempt, retryAfterMs, remainingBudgetMs, random) {
|
|
1331
|
+
if (attempt >= RETRY_MAX_ATTEMPTS) return -1;
|
|
1332
|
+
const backoff = Math.min(RETRY_MAX_DELAY_MS, RETRY_BASE_MS * 2 ** (attempt - 1));
|
|
1333
|
+
const delay = Math.max(retryAfterMs, Math.floor(random * backoff));
|
|
1334
|
+
return delay > remainingBudgetMs ? -1 : delay;
|
|
1335
|
+
}
|
|
1336
|
+
var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
1312
1337
|
async function fetchWithError(url, options) {
|
|
1313
1338
|
const method = options?.method ?? "GET";
|
|
1314
|
-
|
|
1315
|
-
let
|
|
1316
|
-
|
|
1317
|
-
response
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1339
|
+
const deadline = Date.now() + RETRY_BUDGET_MS;
|
|
1340
|
+
for (let attempt = 1; ; attempt++) {
|
|
1341
|
+
logger.debug(`${method} ${url}`);
|
|
1342
|
+
let response;
|
|
1343
|
+
try {
|
|
1344
|
+
response = await fetch(url, options);
|
|
1345
|
+
} catch (error) {
|
|
1346
|
+
const msg = error.message ?? String(error);
|
|
1347
|
+
logger.debug(`Connection failed: ${method} ${url} \u2014 ${msg}`);
|
|
1348
|
+
throw wrapError(error);
|
|
1349
|
+
}
|
|
1350
|
+
logger.debug(`${method} ${url} \u2192 ${response.status}`);
|
|
1351
|
+
if (response.status === 429) {
|
|
1352
|
+
const now = Date.now();
|
|
1353
|
+
const retryAfterMs = parseRetryAfterMs(response.headers?.get?.("Retry-After") ?? null, now);
|
|
1354
|
+
const delay = retryDelayMs(attempt, retryAfterMs, deadline - now, Math.random());
|
|
1355
|
+
if (delay < 0) {
|
|
1356
|
+
const { message, body } = await parseErrorBody(response);
|
|
1357
|
+
throw new RateLimitError(message, Math.max(1, Math.ceil(retryAfterMs / 1e3)), body);
|
|
1358
|
+
}
|
|
1359
|
+
logger.debug(`429 from ${url}; retrying in ${delay}ms (attempt ${attempt})`);
|
|
1360
|
+
await sleep(delay);
|
|
1361
|
+
continue;
|
|
1362
|
+
}
|
|
1363
|
+
if (!response.ok) {
|
|
1364
|
+
await throwHttpError(response);
|
|
1365
|
+
}
|
|
1366
|
+
return response.json();
|
|
1326
1367
|
}
|
|
1327
|
-
return response.json();
|
|
1328
1368
|
}
|
|
1329
1369
|
async function fetchStreamWithError(url, options) {
|
|
1330
1370
|
const method = options?.method ?? "GET";
|
|
@@ -1459,10 +1499,145 @@ async function* parseSSEStream(response) {
|
|
|
1459
1499
|
}
|
|
1460
1500
|
}
|
|
1461
1501
|
|
|
1502
|
+
// src/asset-cache.ts
|
|
1503
|
+
var PREFIX = "covia:asset-meta:";
|
|
1504
|
+
var LocalStorageMetadataStore = class {
|
|
1505
|
+
get(hash) {
|
|
1506
|
+
try {
|
|
1507
|
+
const raw = localStorage.getItem(PREFIX + hash);
|
|
1508
|
+
return raw ? JSON.parse(raw) : void 0;
|
|
1509
|
+
} catch {
|
|
1510
|
+
return void 0;
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
put(hash, metadata) {
|
|
1514
|
+
try {
|
|
1515
|
+
localStorage.setItem(PREFIX + hash, JSON.stringify(metadata));
|
|
1516
|
+
} catch {
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
clear() {
|
|
1520
|
+
try {
|
|
1521
|
+
const doomed = [];
|
|
1522
|
+
for (let i = 0; i < localStorage.length; i++) {
|
|
1523
|
+
const key = localStorage.key(i);
|
|
1524
|
+
if (key?.startsWith(PREFIX)) doomed.push(key);
|
|
1525
|
+
}
|
|
1526
|
+
doomed.forEach((k) => localStorage.removeItem(k));
|
|
1527
|
+
} catch {
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
};
|
|
1531
|
+
function detectDefaultStore() {
|
|
1532
|
+
try {
|
|
1533
|
+
return typeof localStorage !== "undefined" ? new LocalStorageMetadataStore() : null;
|
|
1534
|
+
} catch {
|
|
1535
|
+
return null;
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
var store = detectDefaultStore();
|
|
1539
|
+
function setAssetMetadataStore(s) {
|
|
1540
|
+
store = s;
|
|
1541
|
+
}
|
|
1542
|
+
function getAssetMetadataStore() {
|
|
1543
|
+
return store;
|
|
1544
|
+
}
|
|
1545
|
+
function normaliseHash(hash) {
|
|
1546
|
+
return (hash.startsWith("0x") ? hash.slice(2) : hash).toLowerCase();
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
// src/AdapterManager.ts
|
|
1550
|
+
var ADAPTERS_PATH = "v/info/adapters";
|
|
1551
|
+
var LIST_LIMIT = 1e3;
|
|
1552
|
+
function toAdapterInfo(name, value) {
|
|
1553
|
+
return {
|
|
1554
|
+
name: value?.name ?? name ?? "",
|
|
1555
|
+
description: value?.description,
|
|
1556
|
+
operations: Array.isArray(value?.operations) ? value.operations : []
|
|
1557
|
+
};
|
|
1558
|
+
}
|
|
1559
|
+
var AdapterManager = class {
|
|
1560
|
+
constructor(venue) {
|
|
1561
|
+
this.venue = venue;
|
|
1562
|
+
}
|
|
1563
|
+
/**
|
|
1564
|
+
* List the adapters registered on the venue, with their descriptions and
|
|
1565
|
+
* invocable operation catalog paths. Registered-but-inactive or zero-op
|
|
1566
|
+
* adapters are included — this is the true registry, not an inference
|
|
1567
|
+
* from the operations catalog.
|
|
1568
|
+
*/
|
|
1569
|
+
async list() {
|
|
1570
|
+
const r = await this.venue.workspace.slice(ADAPTERS_PATH, 0, LIST_LIMIT);
|
|
1571
|
+
if (!r.exists || !Array.isArray(r.values)) return [];
|
|
1572
|
+
const out = [];
|
|
1573
|
+
for (const entry of r.values) {
|
|
1574
|
+
if (!entry || typeof entry !== "object") continue;
|
|
1575
|
+
const key = "key" in entry && typeof entry.key === "string" ? entry.key : void 0;
|
|
1576
|
+
const value = "value" in entry ? entry.value : entry;
|
|
1577
|
+
out.push(toAdapterInfo(key, value));
|
|
1578
|
+
}
|
|
1579
|
+
return out;
|
|
1580
|
+
}
|
|
1581
|
+
/**
|
|
1582
|
+
* Get a single adapter's summary by name.
|
|
1583
|
+
* @param name - Adapter name, e.g. "mcp"
|
|
1584
|
+
* @returns {Promise<AdapterInfo | null>} `null` if no adapter with that name is registered
|
|
1585
|
+
*/
|
|
1586
|
+
async get(name) {
|
|
1587
|
+
const r = await this.venue.workspace.read(`${ADAPTERS_PATH}/${encodeURIComponent(name)}`);
|
|
1588
|
+
if (!r.exists) return null;
|
|
1589
|
+
return toAdapterInfo(name, r.value);
|
|
1590
|
+
}
|
|
1591
|
+
};
|
|
1592
|
+
|
|
1462
1593
|
// src/AgentManager.ts
|
|
1594
|
+
function versionAtLeast(version, major, minor) {
|
|
1595
|
+
const m = version?.match(/^(\d+)\.(\d+)/);
|
|
1596
|
+
if (!m) return true;
|
|
1597
|
+
const [maj, min] = [Number(m[1]), Number(m[2])];
|
|
1598
|
+
return maj > major || maj === major && min >= minor;
|
|
1599
|
+
}
|
|
1463
1600
|
var AgentManager = class {
|
|
1464
1601
|
constructor(venue) {
|
|
1465
1602
|
this.venue = venue;
|
|
1603
|
+
// Whether this venue serves GET /api/v1/agents — flipped on the first 404 so
|
|
1604
|
+
// pre-0.4 venues pay the probe once, not one failed GET per read (covia#180).
|
|
1605
|
+
this.agentsGetSupported = true;
|
|
1606
|
+
}
|
|
1607
|
+
_headers() {
|
|
1608
|
+
const headers = { "Content-Type": "application/json" };
|
|
1609
|
+
this.venue.auth.apply(headers, this.venue.venueId);
|
|
1610
|
+
return headers;
|
|
1611
|
+
}
|
|
1612
|
+
/** Whether the venue serves `GET /api/v1/agents`: no if a probe already
|
|
1613
|
+
* 404'd, or if the venue's last known status identifies it as pre-0.4. */
|
|
1614
|
+
supportsAgentsGet() {
|
|
1615
|
+
if (!this.agentsGetSupported) return false;
|
|
1616
|
+
const status = this.venue.lastKnownStatus;
|
|
1617
|
+
if (status && (!status.version || !versionAtLeast(status.version, 0, 4))) {
|
|
1618
|
+
this.agentsGetSupported = false;
|
|
1619
|
+
}
|
|
1620
|
+
return this.agentsGetSupported;
|
|
1621
|
+
}
|
|
1622
|
+
/** A job-free agents GET, falling back to the invoke path on pre-0.4 venues. */
|
|
1623
|
+
async _agentsOr(path, params, fallback) {
|
|
1624
|
+
if (this.supportsAgentsGet()) {
|
|
1625
|
+
try {
|
|
1626
|
+
const qs = new URLSearchParams();
|
|
1627
|
+
for (const [k, v] of Object.entries(params)) if (v !== void 0) qs.set(k, String(v));
|
|
1628
|
+
const q = qs.toString();
|
|
1629
|
+
return await fetchWithError(
|
|
1630
|
+
`${this.venue.baseUrl}/api/v1/agents${path}${q ? `?${q}` : ""}`,
|
|
1631
|
+
{ headers: this._headers() }
|
|
1632
|
+
);
|
|
1633
|
+
} catch (e) {
|
|
1634
|
+
if (!(e instanceof NotFoundError)) throw e;
|
|
1635
|
+
const routeMissing = path === "" || /\bEndpoint (GET|POST|PUT|DELETE|PATCH|HEAD) /.test(e.message);
|
|
1636
|
+
if (!routeMissing) throw e;
|
|
1637
|
+
this.agentsGetSupported = false;
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
return fallback();
|
|
1466
1641
|
}
|
|
1467
1642
|
async create(input) {
|
|
1468
1643
|
return this.venue.operations.run("v/ops/agent/create", input);
|
|
@@ -1495,8 +1670,16 @@ var AgentManager = class {
|
|
|
1495
1670
|
async trigger(agentId) {
|
|
1496
1671
|
return this.venue.operations.run("v/ops/agent/trigger", { agentId });
|
|
1497
1672
|
}
|
|
1673
|
+
/**
|
|
1674
|
+
* List the caller's agents. **Job-free** on covia ≥ 0.4: goes through
|
|
1675
|
+
* `GET /api/v1/agents` (covia#180) — synchronous, no Job persisted. Older
|
|
1676
|
+
* venues transparently fall back to the invoke path (one probe, remembered).
|
|
1677
|
+
*/
|
|
1498
1678
|
async list(includeTerminated) {
|
|
1499
|
-
|
|
1679
|
+
const result = await this._agentsOr("", { includeTerminated }, () => this.venue.operations.run("v/ops/agent/list", { includeTerminated }));
|
|
1680
|
+
const raw = result?.agents ?? [];
|
|
1681
|
+
const agents = raw.map((a) => typeof a === "string" ? { agentId: a } : a);
|
|
1682
|
+
return { agents };
|
|
1500
1683
|
}
|
|
1501
1684
|
async delete(agentId, remove) {
|
|
1502
1685
|
return this.venue.operations.run("v/ops/agent/delete", { agentId, remove });
|
|
@@ -1513,8 +1696,10 @@ var AgentManager = class {
|
|
|
1513
1696
|
async cancelTask(agentId, taskId) {
|
|
1514
1697
|
return this.venue.operations.run("v/ops/agent/cancel-task", { agentId, taskId });
|
|
1515
1698
|
}
|
|
1699
|
+
/** Agent info. **Job-free** on covia ≥ 0.4 (`GET /api/v1/agents/{id}`,
|
|
1700
|
+
* covia#180); older venues fall back to the invoke path. */
|
|
1516
1701
|
async info(agentId) {
|
|
1517
|
-
return this.venue.operations.run("v/ops/agent/info", { agentId });
|
|
1702
|
+
return this._agentsOr(`/${encodeURIComponent(agentId)}`, {}, () => this.venue.operations.run("v/ops/agent/info", { agentId }));
|
|
1518
1703
|
}
|
|
1519
1704
|
async fork(input) {
|
|
1520
1705
|
return this.venue.operations.run("v/ops/agent/fork", input);
|
|
@@ -1871,21 +2056,23 @@ var AssetManager = class {
|
|
|
1871
2056
|
*/
|
|
1872
2057
|
async get(assetId) {
|
|
1873
2058
|
if (cache.has(assetId)) {
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
2059
|
+
return this._wrap(assetId, cache.get(assetId));
|
|
2060
|
+
}
|
|
2061
|
+
const hash = assetHash(assetId);
|
|
2062
|
+
if (hash) {
|
|
2063
|
+
const persisted = getAssetMetadataStore()?.get(normaliseHash(hash));
|
|
2064
|
+
if (persisted) {
|
|
2065
|
+
cache.set(assetId, persisted);
|
|
2066
|
+
return this._wrap(assetId, persisted);
|
|
1879
2067
|
}
|
|
1880
2068
|
}
|
|
1881
2069
|
try {
|
|
1882
2070
|
const data = await fetchWithError(`${this.venue.baseUrl}/api/v1/assets/${assetId}`);
|
|
1883
|
-
if (
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
} else {
|
|
1887
|
-
return new DataAsset(assetId, this.venue, data);
|
|
2071
|
+
if (hash) {
|
|
2072
|
+
cache.set(assetId, data);
|
|
2073
|
+
getAssetMetadataStore()?.put(normaliseHash(hash), data);
|
|
1888
2074
|
}
|
|
2075
|
+
return this._wrap(assetId, data);
|
|
1889
2076
|
} catch (error) {
|
|
1890
2077
|
if (error instanceof NotFoundError) {
|
|
1891
2078
|
throw new AssetNotFoundError(assetId);
|
|
@@ -1893,6 +2080,12 @@ var AssetManager = class {
|
|
|
1893
2080
|
throw error;
|
|
1894
2081
|
}
|
|
1895
2082
|
}
|
|
2083
|
+
_wrap(assetId, data) {
|
|
2084
|
+
if (data.operation) {
|
|
2085
|
+
return new Operation(assetId, this.venue, data);
|
|
2086
|
+
}
|
|
2087
|
+
return new DataAsset(assetId, this.venue, data);
|
|
2088
|
+
}
|
|
1896
2089
|
/**
|
|
1897
2090
|
* List assets with pagination support
|
|
1898
2091
|
* @param options - Pagination options (offset, limit)
|
|
@@ -1978,6 +2171,7 @@ var AssetManager = class {
|
|
|
1978
2171
|
*/
|
|
1979
2172
|
clearCache() {
|
|
1980
2173
|
cache.clear();
|
|
2174
|
+
getAssetMetadataStore()?.clear();
|
|
1981
2175
|
}
|
|
1982
2176
|
// `contentType` defaults to JSON for the metadata/register endpoints. Pass
|
|
1983
2177
|
// `undefined` for binary content upload so fetch infers the type from the
|
|
@@ -2015,9 +2209,47 @@ var OperationManager = class {
|
|
|
2015
2209
|
* @param options - Invoke options (e.g., ucans)
|
|
2016
2210
|
*/
|
|
2017
2211
|
async run(assetId, input, options) {
|
|
2212
|
+
if (this.venue.privateJobs) {
|
|
2213
|
+
return this._runPrivate(assetId, input, options);
|
|
2214
|
+
}
|
|
2018
2215
|
const job = await this.invoke(assetId, input, options);
|
|
2019
2216
|
return await job.result();
|
|
2020
2217
|
}
|
|
2218
|
+
/**
|
|
2219
|
+
* Private-mode execution (covia #192): a memory-only job whose result is
|
|
2220
|
+
* collected through the invoke `wait` window — a completed private job is
|
|
2221
|
+
* immediately forgotten by the venue, so polling cannot be used. If the
|
|
2222
|
+
* operation outlives the venue's wait cap, polling continues while the job
|
|
2223
|
+
* runs; a job that completes between polls is unobservable and surfaces as
|
|
2224
|
+
* a clear error rather than a confusing 404.
|
|
2225
|
+
*/
|
|
2226
|
+
async _runPrivate(assetId, input, options) {
|
|
2227
|
+
const payload = {
|
|
2228
|
+
operation: assetId,
|
|
2229
|
+
input,
|
|
2230
|
+
private: true,
|
|
2231
|
+
wait: true
|
|
2232
|
+
};
|
|
2233
|
+
if (options?.ucans) payload.ucans = options.ucans;
|
|
2234
|
+
const rec = await fetchWithError(`${this.venue.baseUrl}/api/v1/invoke`, {
|
|
2235
|
+
method: "POST",
|
|
2236
|
+
headers: this._buildHeaders(),
|
|
2237
|
+
body: JSON.stringify(payload)
|
|
2238
|
+
});
|
|
2239
|
+
const status = rec.status;
|
|
2240
|
+
if (isJobComplete(status)) return rec.output;
|
|
2241
|
+
if (isJobFinished(status)) {
|
|
2242
|
+
throw new JobFailedError(rec);
|
|
2243
|
+
}
|
|
2244
|
+
try {
|
|
2245
|
+
const job = new Job(rec.id ?? "", this.venue, rec);
|
|
2246
|
+
return await job.result();
|
|
2247
|
+
} catch (e) {
|
|
2248
|
+
throw new CoviaError(
|
|
2249
|
+
`Private job completed while unobserved \u2014 its record is already forgotten, so the result could not be collected. Private jobs that outlive the venue wait window cannot be reliably collected; consider a non-private run for long operations. (${e.message})`
|
|
2250
|
+
);
|
|
2251
|
+
}
|
|
2252
|
+
}
|
|
2021
2253
|
/**
|
|
2022
2254
|
* Execute an operation and return a Job for tracking
|
|
2023
2255
|
* @param assetId - Operation asset ID or named operation
|
|
@@ -2025,6 +2257,11 @@ var OperationManager = class {
|
|
|
2025
2257
|
* @param options - Invoke options (e.g., ucans)
|
|
2026
2258
|
*/
|
|
2027
2259
|
async invoke(assetId, input, options) {
|
|
2260
|
+
if (this.venue.privateJobs) {
|
|
2261
|
+
throw new CoviaError(
|
|
2262
|
+
"Private-jobs mode requires run(): a completed private job is immediately forgotten by the venue, so a poll-style Job cannot collect its result."
|
|
2263
|
+
);
|
|
2264
|
+
}
|
|
2028
2265
|
const payload = {
|
|
2029
2266
|
operation: assetId,
|
|
2030
2267
|
input
|
|
@@ -2047,7 +2284,7 @@ var OperationManager = class {
|
|
|
2047
2284
|
};
|
|
2048
2285
|
|
|
2049
2286
|
// src/WorkspaceManager.ts
|
|
2050
|
-
function
|
|
2287
|
+
function versionAtLeast2(version, major, minor) {
|
|
2051
2288
|
const m = version?.match(/^(\d+)\.(\d+)/);
|
|
2052
2289
|
if (!m) return true;
|
|
2053
2290
|
const [maj, min] = [Number(m[1]), Number(m[2])];
|
|
@@ -2080,7 +2317,7 @@ var WorkspaceManager = class {
|
|
|
2080
2317
|
supportsValues() {
|
|
2081
2318
|
if (!this.valuesSupported) return false;
|
|
2082
2319
|
const status = this.venue.lastKnownStatus;
|
|
2083
|
-
if (status && (!status.version || !
|
|
2320
|
+
if (status && (!status.version || !versionAtLeast2(status.version, 0, 3))) {
|
|
2084
2321
|
this.valuesSupported = false;
|
|
2085
2322
|
}
|
|
2086
2323
|
return this.valuesSupported;
|
|
@@ -2103,7 +2340,8 @@ var WorkspaceManager = class {
|
|
|
2103
2340
|
return this._valuesOr("read", { path, maxSize }, () => this.venue.operations.run("v/ops/covia/read", { path, maxSize }));
|
|
2104
2341
|
}
|
|
2105
2342
|
async list(path, limit, offset, ucans) {
|
|
2106
|
-
|
|
2343
|
+
path = path || "/";
|
|
2344
|
+
if (ucans?.length) return this.venue.operations.run("v/ops/covia/list", { path, limit, offset }, { ucans });
|
|
2107
2345
|
return this._valuesOr("list", { path, limit, offset }, () => this.venue.operations.run("v/ops/covia/list", { path, limit, offset }));
|
|
2108
2346
|
}
|
|
2109
2347
|
async slice(path, offset, limit, ucans) {
|
|
@@ -2163,6 +2401,16 @@ var UCANManager = class {
|
|
|
2163
2401
|
async issue(aud, att, exp) {
|
|
2164
2402
|
return this.venue.operations.run("v/ops/ucan/issue", { aud, att, exp });
|
|
2165
2403
|
}
|
|
2404
|
+
/**
|
|
2405
|
+
* Verify a UCAN against the venue's trust policy and get the verdict
|
|
2406
|
+
* explained — validity with a diagnosable reason, chain depth and root
|
|
2407
|
+
* issuer, per-capability root-authority (owner / venue / refused), and,
|
|
2408
|
+
* when `check` is supplied, whether the token would authorise that request
|
|
2409
|
+
* here. The diagnostic counterpart to an enforcement "Access denied".
|
|
2410
|
+
*/
|
|
2411
|
+
async verify(token, check) {
|
|
2412
|
+
return this.venue.operations.run("v/ops/ucan/verify", { token, ...check });
|
|
2413
|
+
}
|
|
2166
2414
|
};
|
|
2167
2415
|
|
|
2168
2416
|
// src/SecretManager.ts
|
|
@@ -2299,6 +2547,34 @@ function venueBaseUrlCandidates(venueId) {
|
|
|
2299
2547
|
return schemelessVenueCandidates(venueId);
|
|
2300
2548
|
}
|
|
2301
2549
|
var Venue = class _Venue {
|
|
2550
|
+
constructor(options = {}) {
|
|
2551
|
+
/** Connection-level private-jobs mode — see {@link setPrivate}. */
|
|
2552
|
+
this.privateJobs = false;
|
|
2553
|
+
this.baseUrl = options.baseUrl || "";
|
|
2554
|
+
this.venueId = options.venueId || "";
|
|
2555
|
+
this.auth = options.auth || new NoAuth();
|
|
2556
|
+
this.lastKnownStatus = options.status;
|
|
2557
|
+
this.metadata = {
|
|
2558
|
+
name: options.name || "default",
|
|
2559
|
+
description: options.description || ""
|
|
2560
|
+
};
|
|
2561
|
+
}
|
|
2562
|
+
/**
|
|
2563
|
+
* Puts this connection in **private-jobs mode**: every subsequent
|
|
2564
|
+
* `operations.run(...)` executes as a memory-only job (covia #192) — never
|
|
2565
|
+
* persisted to the venue's job index, no durable record, gone on venue
|
|
2566
|
+
* restart. Requires `enablePrivateJobs` on the venue.
|
|
2567
|
+
*
|
|
2568
|
+
* Because a completed private job is immediately forgotten, results are
|
|
2569
|
+
* collected through the invoke `wait` window rather than polling — so
|
|
2570
|
+
* private mode works with `run()`; a poll-style `invoke()` throws.
|
|
2571
|
+
*/
|
|
2572
|
+
setPrivate(enabled) {
|
|
2573
|
+
this.privateJobs = enabled;
|
|
2574
|
+
}
|
|
2575
|
+
get adapters() {
|
|
2576
|
+
return this._adapters ?? (this._adapters = new AdapterManager(this));
|
|
2577
|
+
}
|
|
2302
2578
|
get agents() {
|
|
2303
2579
|
return this._agents ?? (this._agents = new AgentManager(this));
|
|
2304
2580
|
}
|
|
@@ -2320,16 +2596,6 @@ var Venue = class _Venue {
|
|
|
2320
2596
|
get secrets() {
|
|
2321
2597
|
return this._secrets ?? (this._secrets = new SecretManager(this));
|
|
2322
2598
|
}
|
|
2323
|
-
constructor(options = {}) {
|
|
2324
|
-
this.baseUrl = options.baseUrl || "";
|
|
2325
|
-
this.venueId = options.venueId || "";
|
|
2326
|
-
this.auth = options.auth || new NoAuth();
|
|
2327
|
-
this.lastKnownStatus = options.status;
|
|
2328
|
-
this.metadata = {
|
|
2329
|
-
name: options.name || "default",
|
|
2330
|
-
description: options.description || ""
|
|
2331
|
-
};
|
|
2332
|
-
}
|
|
2333
2599
|
/**
|
|
2334
2600
|
* Connect to a venue, validating it with `GET {base}/api/v1/status`. If the
|
|
2335
2601
|
* venue is auth-gated (status answers 401/403 — public access disabled), the
|
|
@@ -2561,12 +2827,45 @@ var Grid = class {
|
|
|
2561
2827
|
return connectedVenue;
|
|
2562
2828
|
}
|
|
2563
2829
|
};
|
|
2830
|
+
|
|
2831
|
+
// src/crypto/ucan.ts
|
|
2832
|
+
var encoder2 = new TextEncoder();
|
|
2833
|
+
var VENUE_RELAY = "venue/relay";
|
|
2834
|
+
function didFor(privateKey) {
|
|
2835
|
+
return `did:key:${encodePublicKey(getPublicKey2(privateKey))}`;
|
|
2836
|
+
}
|
|
2837
|
+
function createUCANJWT(privateKey, audienceDID, att, lifetimeSeconds, proofs = []) {
|
|
2838
|
+
const multikey = encodePublicKey(getPublicKey2(privateKey));
|
|
2839
|
+
const nowSecs = Math.floor(Date.now() / 1e3);
|
|
2840
|
+
const header = JSON.stringify({ alg: "EdDSA", typ: "JWT", kid: multikey });
|
|
2841
|
+
const claims = {
|
|
2842
|
+
iss: `did:key:${multikey}`,
|
|
2843
|
+
aud: audienceDID,
|
|
2844
|
+
att,
|
|
2845
|
+
exp: nowSecs + lifetimeSeconds
|
|
2846
|
+
};
|
|
2847
|
+
if (proofs.length) claims.prf = proofs;
|
|
2848
|
+
const signingInput = `${base64UrlEncode(encoder2.encode(header))}.${base64UrlEncode(encoder2.encode(JSON.stringify(claims)))}`;
|
|
2849
|
+
const signature = sign(encoder2.encode(signingInput), privateKey);
|
|
2850
|
+
return `${signingInput}.${base64UrlEncode(signature)}`;
|
|
2851
|
+
}
|
|
2852
|
+
function identityToken(privateKey, venueDID, lifetimeSeconds = 300) {
|
|
2853
|
+
return createUCANJWT(privateKey, venueDID, [], lifetimeSeconds);
|
|
2854
|
+
}
|
|
2855
|
+
function grant(ownerPrivateKey, audienceDID, withResource, can, lifetimeSeconds) {
|
|
2856
|
+
return createUCANJWT(ownerPrivateKey, audienceDID, [{ with: withResource, can }], lifetimeSeconds);
|
|
2857
|
+
}
|
|
2858
|
+
function relayDelegation(privateKey, venueDID, lifetimeSeconds, caps = []) {
|
|
2859
|
+
const att = [{ with: didFor(privateKey), can: VENUE_RELAY }, ...caps];
|
|
2860
|
+
return createUCANJWT(privateKey, venueDID, att, lifetimeSeconds);
|
|
2861
|
+
}
|
|
2564
2862
|
/*! Bundled license information:
|
|
2565
2863
|
|
|
2566
2864
|
@noble/ed25519/index.js:
|
|
2567
2865
|
(*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) *)
|
|
2568
2866
|
*/
|
|
2569
2867
|
|
|
2868
|
+
exports.AdapterManager = AdapterManager;
|
|
2570
2869
|
exports.Agent = Agent;
|
|
2571
2870
|
exports.AgentManager = AgentManager;
|
|
2572
2871
|
exports.AgentStatus = AgentStatus;
|
|
@@ -2596,14 +2895,18 @@ exports.NoAuth = NoAuth;
|
|
|
2596
2895
|
exports.NotFoundError = NotFoundError;
|
|
2597
2896
|
exports.Operation = Operation;
|
|
2598
2897
|
exports.OperationManager = OperationManager;
|
|
2898
|
+
exports.RateLimitError = RateLimitError;
|
|
2599
2899
|
exports.RunStatus = RunStatus;
|
|
2600
2900
|
exports.SecretManager = SecretManager;
|
|
2601
2901
|
exports.UCANManager = UCANManager;
|
|
2902
|
+
exports.VENUE_RELAY = VENUE_RELAY;
|
|
2602
2903
|
exports.Venue = Venue;
|
|
2603
2904
|
exports.WorkspaceManager = WorkspaceManager;
|
|
2604
2905
|
exports.assetHash = assetHash;
|
|
2605
2906
|
exports.createSSEEvent = createSSEEvent;
|
|
2907
|
+
exports.createUCANJWT = createUCANJWT;
|
|
2606
2908
|
exports.decodePublicKey = decodePublicKey;
|
|
2909
|
+
exports.didFor = didFor;
|
|
2607
2910
|
exports.didFromPublicKey = didFromPublicKey;
|
|
2608
2911
|
exports.didMethod = didMethod;
|
|
2609
2912
|
exports.didUrl = didUrl;
|
|
@@ -2613,14 +2916,21 @@ exports.fetchWithError = fetchWithError;
|
|
|
2613
2916
|
exports.generateKeyPair = generateKeyPair;
|
|
2614
2917
|
exports.getAssetIdFromPath = getAssetIdFromPath;
|
|
2615
2918
|
exports.getAssetIdFromVenueId = getAssetIdFromVenueId;
|
|
2919
|
+
exports.getAssetMetadataStore = getAssetMetadataStore;
|
|
2616
2920
|
exports.getParsedAssetId = getParsedAssetId;
|
|
2921
|
+
exports.grant = grant;
|
|
2617
2922
|
exports.hexToPrivateKey = hexToPrivateKey;
|
|
2923
|
+
exports.identityToken = identityToken;
|
|
2618
2924
|
exports.isDid = isDid;
|
|
2619
2925
|
exports.isJobComplete = isJobComplete;
|
|
2620
2926
|
exports.isJobFinished = isJobFinished;
|
|
2621
2927
|
exports.isJobPaused = isJobPaused;
|
|
2622
2928
|
exports.logger = logger;
|
|
2623
2929
|
exports.parseDidUrl = parseDidUrl;
|
|
2930
|
+
exports.parseRetryAfterMs = parseRetryAfterMs;
|
|
2624
2931
|
exports.parseSSEStream = parseSSEStream;
|
|
2625
2932
|
exports.privateKeyToHex = privateKeyToHex;
|
|
2933
|
+
exports.relayDelegation = relayDelegation;
|
|
2934
|
+
exports.retryDelayMs = retryDelayMs;
|
|
2935
|
+
exports.setAssetMetadataStore = setAssetMetadataStore;
|
|
2626
2936
|
exports.venueBaseUrlCandidates = venueBaseUrlCandidates;
|