@covia/covia-sdk 1.7.4 → 1.9.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/README.md +98 -33
- package/dist/index.d.mts +196 -64
- package/dist/index.d.ts +196 -64
- package/dist/index.js +503 -157
- package/dist/index.mjs +500 -158
- package/package.json +9 -4
package/dist/index.js
CHANGED
|
@@ -45,6 +45,15 @@ var GridError = class extends CoviaError {
|
|
|
45
45
|
this.responseBody = responseBody;
|
|
46
46
|
}
|
|
47
47
|
};
|
|
48
|
+
var UnsupportedVenueFeatureError = class extends CoviaError {
|
|
49
|
+
constructor(feature) {
|
|
50
|
+
super(
|
|
51
|
+
`The connected venue cannot serve ${feature} without creating a job. Invoke the corresponding operation explicitly if creating a persisted job is intended.`
|
|
52
|
+
);
|
|
53
|
+
this.feature = feature;
|
|
54
|
+
this.name = "UnsupportedVenueFeatureError";
|
|
55
|
+
}
|
|
56
|
+
};
|
|
48
57
|
var CoviaConnectionError = class extends CoviaError {
|
|
49
58
|
constructor(message, options = {}) {
|
|
50
59
|
super(message);
|
|
@@ -114,6 +123,14 @@ var JobNotFoundError = class extends NotFoundError {
|
|
|
114
123
|
this.jobId = jobId;
|
|
115
124
|
}
|
|
116
125
|
};
|
|
126
|
+
var AgentSessionNotFoundError = class extends CoviaError {
|
|
127
|
+
constructor(agentId, sessionId) {
|
|
128
|
+
super(`Agent session not found: ${agentId}/${sessionId}`, 404);
|
|
129
|
+
this.agentId = agentId;
|
|
130
|
+
this.sessionId = sessionId;
|
|
131
|
+
this.name = "AgentSessionNotFoundError";
|
|
132
|
+
}
|
|
133
|
+
};
|
|
117
134
|
|
|
118
135
|
// node_modules/.pnpm/@noble+ed25519@3.1.0/node_modules/@noble/ed25519/index.js
|
|
119
136
|
var ed25519_CURVE = Object.freeze({
|
|
@@ -1033,9 +1050,13 @@ function privateKeyToHex(key) {
|
|
|
1033
1050
|
return Array.from(key).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1034
1051
|
}
|
|
1035
1052
|
function hexToPrivateKey(hex) {
|
|
1036
|
-
const
|
|
1053
|
+
const cleaned = hex.startsWith("0x") || hex.startsWith("0X") ? hex.slice(2) : hex;
|
|
1054
|
+
if (!/^[0-9a-fA-F]{64}$/.test(cleaned)) {
|
|
1055
|
+
throw new Error("Invalid Ed25519 private key: expected 64 hex characters (32 bytes)");
|
|
1056
|
+
}
|
|
1057
|
+
const bytes = new Uint8Array(32);
|
|
1037
1058
|
for (let i = 0; i < bytes.length; i++) {
|
|
1038
|
-
bytes[i] = parseInt(
|
|
1059
|
+
bytes[i] = parseInt(cleaned.substring(i * 2, i * 2 + 2), 16);
|
|
1039
1060
|
}
|
|
1040
1061
|
return bytes;
|
|
1041
1062
|
}
|
|
@@ -1149,6 +1170,14 @@ function createEdDSAJWT(privateKey, lifetimeSeconds = 300, audience) {
|
|
|
1149
1170
|
}
|
|
1150
1171
|
|
|
1151
1172
|
// src/Credentials.ts
|
|
1173
|
+
function base64Encode(text) {
|
|
1174
|
+
const bytes = new TextEncoder().encode(text);
|
|
1175
|
+
let binary = "";
|
|
1176
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
1177
|
+
binary += String.fromCharCode(bytes[i]);
|
|
1178
|
+
}
|
|
1179
|
+
return btoa(binary);
|
|
1180
|
+
}
|
|
1152
1181
|
var Auth = class {
|
|
1153
1182
|
};
|
|
1154
1183
|
var NoAuth = class extends Auth {
|
|
@@ -1171,7 +1200,7 @@ var BasicAuth = class extends Auth {
|
|
|
1171
1200
|
this._password = password;
|
|
1172
1201
|
}
|
|
1173
1202
|
apply(headers, _audience) {
|
|
1174
|
-
const credentials =
|
|
1203
|
+
const credentials = base64Encode(`${this._username}:${this._password}`);
|
|
1175
1204
|
headers["Authorization"] = `Basic ${credentials}`;
|
|
1176
1205
|
}
|
|
1177
1206
|
};
|
|
@@ -1188,7 +1217,13 @@ var Ed25519Auth = class _Ed25519Auth extends Auth {
|
|
|
1188
1217
|
this._lifetime = tokenLifetimeSeconds;
|
|
1189
1218
|
}
|
|
1190
1219
|
apply(headers, audience) {
|
|
1191
|
-
const
|
|
1220
|
+
const aud = this._audience ?? (audience || void 0);
|
|
1221
|
+
if (!aud) {
|
|
1222
|
+
throw new CoviaError(
|
|
1223
|
+
"Ed25519Auth requires a venue audience to bind the token to: connect via Grid.connect()/Venue.connect() so the venue DID is known, or pin auth.audience explicitly."
|
|
1224
|
+
);
|
|
1225
|
+
}
|
|
1226
|
+
const jwt = createEdDSAJWT(this._privateKey, this._lifetime, aud);
|
|
1192
1227
|
headers["Authorization"] = `Bearer ${jwt}`;
|
|
1193
1228
|
}
|
|
1194
1229
|
/** The caller's DID derived from the public key. */
|
|
@@ -1302,17 +1337,24 @@ async function parseErrorBody(response) {
|
|
|
1302
1337
|
let body = null;
|
|
1303
1338
|
let message = `Request failed with status ${response.status}`;
|
|
1304
1339
|
try {
|
|
1305
|
-
|
|
1340
|
+
if (typeof response.text === "function") {
|
|
1341
|
+
const text = await response.text();
|
|
1342
|
+
if (text) {
|
|
1343
|
+
try {
|
|
1344
|
+
body = JSON.parse(text);
|
|
1345
|
+
} catch {
|
|
1346
|
+
body = text;
|
|
1347
|
+
message = text;
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
} else {
|
|
1351
|
+
body = await response.json();
|
|
1352
|
+
}
|
|
1306
1353
|
if (body && typeof body === "object" && "error" in body) {
|
|
1307
1354
|
const err2 = body.error;
|
|
1308
1355
|
if (typeof err2 === "string") message = err2;
|
|
1309
1356
|
}
|
|
1310
1357
|
} catch {
|
|
1311
|
-
try {
|
|
1312
|
-
const text = await response.text();
|
|
1313
|
-
if (text) message = text;
|
|
1314
|
-
} catch {
|
|
1315
|
-
}
|
|
1316
1358
|
}
|
|
1317
1359
|
return { message, body };
|
|
1318
1360
|
}
|
|
@@ -1606,13 +1648,82 @@ var AdapterManager = class {
|
|
|
1606
1648
|
}
|
|
1607
1649
|
};
|
|
1608
1650
|
|
|
1609
|
-
// src/
|
|
1651
|
+
// src/VenueTransport.ts
|
|
1652
|
+
function requestOptions(venue, options) {
|
|
1653
|
+
const {
|
|
1654
|
+
contentType,
|
|
1655
|
+
headers: suppliedHeaders = {},
|
|
1656
|
+
...request
|
|
1657
|
+
} = options;
|
|
1658
|
+
const headers = { ...suppliedHeaders };
|
|
1659
|
+
const effectiveContentType = contentType !== void 0 ? contentType : request.body != null ? "application/json" : null;
|
|
1660
|
+
if (effectiveContentType && headers["Content-Type"] === void 0) {
|
|
1661
|
+
headers["Content-Type"] = effectiveContentType;
|
|
1662
|
+
}
|
|
1663
|
+
venue.auth.apply(headers, venue.venueId);
|
|
1664
|
+
return { ...request, headers };
|
|
1665
|
+
}
|
|
1666
|
+
function venueJson(venue, path, options = {}) {
|
|
1667
|
+
return fetchWithError(
|
|
1668
|
+
`${venue.baseUrl}${path}`,
|
|
1669
|
+
requestOptions(venue, options)
|
|
1670
|
+
);
|
|
1671
|
+
}
|
|
1672
|
+
function venueStream(venue, path, options = {}) {
|
|
1673
|
+
return fetchStreamWithError(
|
|
1674
|
+
`${venue.baseUrl}${path}`,
|
|
1675
|
+
requestOptions(venue, options)
|
|
1676
|
+
);
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
// src/venue-features.ts
|
|
1610
1680
|
function versionAtLeast(version, major, minor) {
|
|
1611
1681
|
const m = version?.match(/^(\d+)\.(\d+)/);
|
|
1612
1682
|
if (!m) return true;
|
|
1613
1683
|
const [maj, min] = [Number(m[1]), Number(m[2])];
|
|
1614
1684
|
return maj > major || maj === major && min >= minor;
|
|
1615
1685
|
}
|
|
1686
|
+
var ROUTE_MISSING_404 = /\bEndpoint (GET|POST|PUT|DELETE|PATCH|HEAD) /;
|
|
1687
|
+
|
|
1688
|
+
// src/values-util.ts
|
|
1689
|
+
function record(value) {
|
|
1690
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
1691
|
+
}
|
|
1692
|
+
var SLICE_PAGE_SIZE = 200;
|
|
1693
|
+
async function sliceAll(workspace, path, pageSize = SLICE_PAGE_SIZE) {
|
|
1694
|
+
const items = [];
|
|
1695
|
+
let offset = 0;
|
|
1696
|
+
for (; ; ) {
|
|
1697
|
+
const page = await workspace.slice(path, offset, pageSize);
|
|
1698
|
+
if (!page.exists) {
|
|
1699
|
+
if (items.length === 0) return items;
|
|
1700
|
+
throw new CoviaError(`Sliceable value at ${path} disappeared mid-read`);
|
|
1701
|
+
}
|
|
1702
|
+
const values = page.values ?? [];
|
|
1703
|
+
items.push(...values);
|
|
1704
|
+
const nextOffset = (page.offset ?? offset) + values.length;
|
|
1705
|
+
const done = page.count !== void 0 ? nextOffset >= page.count : values.length < pageSize;
|
|
1706
|
+
if (values.length === 0 || done) break;
|
|
1707
|
+
if (nextOffset <= offset) {
|
|
1708
|
+
throw new CoviaError(`Venue returned a slice of ${path} that did not advance`);
|
|
1709
|
+
}
|
|
1710
|
+
offset = nextOffset;
|
|
1711
|
+
}
|
|
1712
|
+
return items;
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
// src/AgentManager.ts
|
|
1716
|
+
function sessionRecord(sessionId, value) {
|
|
1717
|
+
const session = record(value) ?? {};
|
|
1718
|
+
const meta = record(session.meta);
|
|
1719
|
+
return {
|
|
1720
|
+
id: sessionId,
|
|
1721
|
+
metadata: meta ?? {},
|
|
1722
|
+
pending: Array.isArray(session.pending) ? session.pending : [],
|
|
1723
|
+
frames: Array.isArray(session.frames) ? session.frames : [],
|
|
1724
|
+
wakeTime: typeof session.wakeTime === "number" ? session.wakeTime : void 0
|
|
1725
|
+
};
|
|
1726
|
+
}
|
|
1616
1727
|
var AgentManager = class {
|
|
1617
1728
|
constructor(venue) {
|
|
1618
1729
|
this.venue = venue;
|
|
@@ -1620,11 +1731,6 @@ var AgentManager = class {
|
|
|
1620
1731
|
// pre-0.4 venues pay the probe once, not one failed GET per read (covia#180).
|
|
1621
1732
|
this.agentsGetSupported = true;
|
|
1622
1733
|
}
|
|
1623
|
-
_headers() {
|
|
1624
|
-
const headers = { "Content-Type": "application/json" };
|
|
1625
|
-
this.venue.auth.apply(headers, this.venue.venueId);
|
|
1626
|
-
return headers;
|
|
1627
|
-
}
|
|
1628
1734
|
/** Whether the venue serves `GET /api/v1/agents`: no if a probe already
|
|
1629
1735
|
* 404'd, or if the venue's last known status identifies it as pre-0.4. */
|
|
1630
1736
|
supportsAgentsGet() {
|
|
@@ -1635,25 +1741,25 @@ var AgentManager = class {
|
|
|
1635
1741
|
}
|
|
1636
1742
|
return this.agentsGetSupported;
|
|
1637
1743
|
}
|
|
1638
|
-
/** A job-free agents GET
|
|
1639
|
-
async
|
|
1744
|
+
/** A job-free agents GET that rejects when the endpoint is unavailable. */
|
|
1745
|
+
async agentsGet(path, params) {
|
|
1640
1746
|
if (this.supportsAgentsGet()) {
|
|
1641
1747
|
try {
|
|
1642
1748
|
const qs = new URLSearchParams();
|
|
1643
1749
|
for (const [k, v] of Object.entries(params)) if (v !== void 0) qs.set(k, String(v));
|
|
1644
1750
|
const q = qs.toString();
|
|
1645
|
-
return await
|
|
1646
|
-
|
|
1647
|
-
{
|
|
1751
|
+
return await venueJson(
|
|
1752
|
+
this.venue,
|
|
1753
|
+
`/api/v1/agents${path}${q ? `?${q}` : ""}`
|
|
1648
1754
|
);
|
|
1649
1755
|
} catch (e) {
|
|
1650
1756
|
if (!(e instanceof NotFoundError)) throw e;
|
|
1651
|
-
const routeMissing = path === "" ||
|
|
1757
|
+
const routeMissing = path === "" || ROUTE_MISSING_404.test(e.message);
|
|
1652
1758
|
if (!routeMissing) throw e;
|
|
1653
1759
|
this.agentsGetSupported = false;
|
|
1654
1760
|
}
|
|
1655
1761
|
}
|
|
1656
|
-
|
|
1762
|
+
throw new UnsupportedVenueFeatureError("agent reads");
|
|
1657
1763
|
}
|
|
1658
1764
|
async create(input) {
|
|
1659
1765
|
return this.venue.operations.run("v/ops/agent/create", input);
|
|
@@ -1698,10 +1804,10 @@ var AgentManager = class {
|
|
|
1698
1804
|
/**
|
|
1699
1805
|
* List the caller's agents. **Job-free** on covia ≥ 0.4: goes through
|
|
1700
1806
|
* `GET /api/v1/agents` (covia#180) — synchronous, no Job persisted. Older
|
|
1701
|
-
* venues
|
|
1807
|
+
* venues reject rather than silently creating a persisted Job.
|
|
1702
1808
|
*/
|
|
1703
1809
|
async list(includeTerminated) {
|
|
1704
|
-
const result = await this.
|
|
1810
|
+
const result = await this.agentsGet("", { includeTerminated });
|
|
1705
1811
|
const raw = result?.agents ?? [];
|
|
1706
1812
|
const agents = raw.map((a) => typeof a === "string" ? { agentId: a } : a);
|
|
1707
1813
|
return { agents };
|
|
@@ -1722,9 +1828,61 @@ var AgentManager = class {
|
|
|
1722
1828
|
return this.venue.operations.run("v/ops/agent/cancel-task", { agentId, taskId });
|
|
1723
1829
|
}
|
|
1724
1830
|
/** Agent info. **Job-free** on covia ≥ 0.4 (`GET /api/v1/agents/{id}`,
|
|
1725
|
-
* covia#180); older venues
|
|
1831
|
+
* covia#180); older venues require an explicit compatibility opt-in. */
|
|
1726
1832
|
async info(agentId) {
|
|
1727
|
-
return this.
|
|
1833
|
+
return this.agentsGet(`/${encodeURIComponent(agentId)}`, {});
|
|
1834
|
+
}
|
|
1835
|
+
/**
|
|
1836
|
+
* Page an agent's sessions directly from `g/<agentId>/sessions`.
|
|
1837
|
+
* This is a job-free Values read; session adapter-specific fields remain
|
|
1838
|
+
* available on each record's `value` while common runtime fields are typed.
|
|
1839
|
+
*/
|
|
1840
|
+
async listSessions(agentId, options = {}) {
|
|
1841
|
+
const result = await this.venue.workspace.slice(
|
|
1842
|
+
`g/${agentId}/sessions`,
|
|
1843
|
+
options.offset,
|
|
1844
|
+
options.limit
|
|
1845
|
+
);
|
|
1846
|
+
const sessions = (result.values ?? []).flatMap((entry) => {
|
|
1847
|
+
const pair = record(entry);
|
|
1848
|
+
if (!pair || typeof pair.key !== "string") return [];
|
|
1849
|
+
return [sessionRecord(pair.key, pair.value)];
|
|
1850
|
+
});
|
|
1851
|
+
return {
|
|
1852
|
+
items: sessions,
|
|
1853
|
+
total: result.count ?? sessions.length,
|
|
1854
|
+
offset: result.offset ?? options.offset ?? 0,
|
|
1855
|
+
limit: options.limit ?? sessions.length
|
|
1856
|
+
};
|
|
1857
|
+
}
|
|
1858
|
+
/** Read one agent session directly from the workspace Values surface. */
|
|
1859
|
+
async getSession(agentId, sessionId) {
|
|
1860
|
+
const path = `g/${agentId}/sessions/${sessionId}`;
|
|
1861
|
+
const result = await this.venue.workspace.read(path);
|
|
1862
|
+
if (!result.exists) {
|
|
1863
|
+
throw new AgentSessionNotFoundError(agentId, sessionId);
|
|
1864
|
+
}
|
|
1865
|
+
if (result.truncated) {
|
|
1866
|
+
return this._readLargeSession(path, sessionId);
|
|
1867
|
+
}
|
|
1868
|
+
if (result.value === void 0 || result.value === null) {
|
|
1869
|
+
throw new AgentSessionNotFoundError(agentId, sessionId);
|
|
1870
|
+
}
|
|
1871
|
+
return sessionRecord(sessionId, result.value);
|
|
1872
|
+
}
|
|
1873
|
+
async _readLargeSession(path, sessionId) {
|
|
1874
|
+
const [meta, wakeTime, pending, frames] = await Promise.all([
|
|
1875
|
+
this.venue.workspace.read(`${path}/meta`),
|
|
1876
|
+
this.venue.workspace.read(`${path}/wakeTime`),
|
|
1877
|
+
sliceAll(this.venue.workspace, `${path}/pending`),
|
|
1878
|
+
sliceAll(this.venue.workspace, `${path}/frames`)
|
|
1879
|
+
]);
|
|
1880
|
+
return sessionRecord(sessionId, {
|
|
1881
|
+
meta: meta.exists ? meta.value : void 0,
|
|
1882
|
+
wakeTime: wakeTime.exists ? wakeTime.value : void 0,
|
|
1883
|
+
pending,
|
|
1884
|
+
frames
|
|
1885
|
+
});
|
|
1728
1886
|
}
|
|
1729
1887
|
async fork(input) {
|
|
1730
1888
|
return this.venue.operations.run("v/ops/agent/fork", input);
|
|
@@ -1886,23 +2044,50 @@ var Job = class {
|
|
|
1886
2044
|
};
|
|
1887
2045
|
|
|
1888
2046
|
// src/JobManager.ts
|
|
2047
|
+
function jobPage(value) {
|
|
2048
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
2049
|
+
throw new CoviaError("Venue returned an invalid jobs listing");
|
|
2050
|
+
}
|
|
2051
|
+
const page = value;
|
|
2052
|
+
if (!Array.isArray(page.items) || !page.items.every((item) => typeof item === "string") || !Number.isInteger(page.total) || (page.total ?? -1) < 0 || !Number.isInteger(page.offset) || (page.offset ?? -1) < 0 || !Number.isInteger(page.limit) || (page.limit ?? -1) < 0) {
|
|
2053
|
+
throw new CoviaError("Venue returned an invalid jobs page");
|
|
2054
|
+
}
|
|
2055
|
+
return page;
|
|
2056
|
+
}
|
|
1889
2057
|
var JobManager = class {
|
|
1890
2058
|
constructor(venue) {
|
|
1891
2059
|
this.venue = venue;
|
|
1892
2060
|
}
|
|
1893
2061
|
async list() {
|
|
1894
|
-
const
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
2062
|
+
const items = [];
|
|
2063
|
+
let offset = 0;
|
|
2064
|
+
let targetTotal;
|
|
2065
|
+
while (targetTotal === void 0 || items.length < targetTotal) {
|
|
2066
|
+
const body = await venueJson(
|
|
2067
|
+
this.venue,
|
|
2068
|
+
`/api/v1/jobs?offset=${offset}&limit=1000`
|
|
2069
|
+
);
|
|
2070
|
+
if (Array.isArray(body)) {
|
|
2071
|
+
if (!body.every((item) => typeof item === "string")) {
|
|
2072
|
+
throw new CoviaError("Venue returned an invalid jobs listing");
|
|
2073
|
+
}
|
|
2074
|
+
return body;
|
|
2075
|
+
}
|
|
2076
|
+
const page = jobPage(body);
|
|
2077
|
+
targetTotal ?? (targetTotal = page.total);
|
|
2078
|
+
items.push(...page.items);
|
|
2079
|
+
if (page.items.length === 0) break;
|
|
2080
|
+
const nextOffset = page.offset + page.items.length;
|
|
2081
|
+
if (nextOffset <= offset) {
|
|
2082
|
+
throw new CoviaError("Venue returned a jobs page that did not advance");
|
|
2083
|
+
}
|
|
2084
|
+
offset = nextOffset;
|
|
2085
|
+
}
|
|
2086
|
+
return items;
|
|
1900
2087
|
}
|
|
1901
2088
|
async get(jobId) {
|
|
1902
2089
|
try {
|
|
1903
|
-
const data = await
|
|
1904
|
-
headers: this._buildHeaders()
|
|
1905
|
-
});
|
|
2090
|
+
const data = await venueJson(this.venue, `/api/v1/jobs/${jobId}`);
|
|
1906
2091
|
return new Job(jobId, this.venue, data);
|
|
1907
2092
|
} catch (error) {
|
|
1908
2093
|
if (error instanceof NotFoundError) {
|
|
@@ -1913,9 +2098,8 @@ var JobManager = class {
|
|
|
1913
2098
|
}
|
|
1914
2099
|
async cancel(jobId) {
|
|
1915
2100
|
try {
|
|
1916
|
-
return await
|
|
1917
|
-
method: "PUT"
|
|
1918
|
-
headers: this._buildHeaders()
|
|
2101
|
+
return await venueJson(this.venue, `/api/v1/jobs/${jobId}/cancel`, {
|
|
2102
|
+
method: "PUT"
|
|
1919
2103
|
});
|
|
1920
2104
|
} catch (error) {
|
|
1921
2105
|
if (error instanceof NotFoundError) {
|
|
@@ -1926,9 +2110,8 @@ var JobManager = class {
|
|
|
1926
2110
|
}
|
|
1927
2111
|
async delete(jobId) {
|
|
1928
2112
|
try {
|
|
1929
|
-
await
|
|
1930
|
-
method: "PUT"
|
|
1931
|
-
headers: this._buildHeaders()
|
|
2113
|
+
await venueStream(this.venue, `/api/v1/jobs/${jobId}/delete`, {
|
|
2114
|
+
method: "PUT"
|
|
1932
2115
|
});
|
|
1933
2116
|
} catch (error) {
|
|
1934
2117
|
if (error instanceof NotFoundError) {
|
|
@@ -1939,9 +2122,8 @@ var JobManager = class {
|
|
|
1939
2122
|
}
|
|
1940
2123
|
async pause(jobId) {
|
|
1941
2124
|
try {
|
|
1942
|
-
return await
|
|
1943
|
-
method: "PUT"
|
|
1944
|
-
headers: this._buildHeaders()
|
|
2125
|
+
return await venueJson(this.venue, `/api/v1/jobs/${jobId}/pause`, {
|
|
2126
|
+
method: "PUT"
|
|
1945
2127
|
});
|
|
1946
2128
|
} catch (error) {
|
|
1947
2129
|
if (error instanceof NotFoundError) {
|
|
@@ -1952,9 +2134,8 @@ var JobManager = class {
|
|
|
1952
2134
|
}
|
|
1953
2135
|
async resume(jobId) {
|
|
1954
2136
|
try {
|
|
1955
|
-
return await
|
|
1956
|
-
method: "PUT"
|
|
1957
|
-
headers: this._buildHeaders()
|
|
2137
|
+
return await venueJson(this.venue, `/api/v1/jobs/${jobId}/resume`, {
|
|
2138
|
+
method: "PUT"
|
|
1958
2139
|
});
|
|
1959
2140
|
} catch (error) {
|
|
1960
2141
|
if (error instanceof NotFoundError) {
|
|
@@ -1965,9 +2146,8 @@ var JobManager = class {
|
|
|
1965
2146
|
}
|
|
1966
2147
|
async sendMessage(jobId, message) {
|
|
1967
2148
|
try {
|
|
1968
|
-
return await
|
|
2149
|
+
return await venueJson(this.venue, `/api/v1/jobs/${jobId}`, {
|
|
1969
2150
|
method: "POST",
|
|
1970
|
-
headers: this._buildHeaders(),
|
|
1971
2151
|
body: JSON.stringify(message)
|
|
1972
2152
|
});
|
|
1973
2153
|
} catch (error) {
|
|
@@ -1978,16 +2158,11 @@ var JobManager = class {
|
|
|
1978
2158
|
}
|
|
1979
2159
|
}
|
|
1980
2160
|
async *stream(jobId) {
|
|
1981
|
-
const response = await
|
|
1982
|
-
headers: {
|
|
2161
|
+
const response = await venueStream(this.venue, `/api/v1/jobs/${jobId}/sse`, {
|
|
2162
|
+
headers: { "Accept": "text/event-stream" }
|
|
1983
2163
|
});
|
|
1984
2164
|
yield* parseSSEStream(response);
|
|
1985
2165
|
}
|
|
1986
|
-
_buildHeaders() {
|
|
1987
|
-
const headers = { "Content-Type": "application/json" };
|
|
1988
|
-
this.venue.auth.apply(headers, this.venue.venueId);
|
|
1989
|
-
return headers;
|
|
1990
|
-
}
|
|
1991
2166
|
};
|
|
1992
2167
|
|
|
1993
2168
|
// src/Asset.ts
|
|
@@ -2067,10 +2242,12 @@ var DataAsset = class extends Asset {
|
|
|
2067
2242
|
};
|
|
2068
2243
|
|
|
2069
2244
|
// src/AssetManager.ts
|
|
2070
|
-
var cache = /* @__PURE__ */ new Map();
|
|
2071
2245
|
var AssetManager = class {
|
|
2072
2246
|
constructor(venue) {
|
|
2073
2247
|
this.venue = venue;
|
|
2248
|
+
// Memory cache is manager/venue-local. Content-addressed metadata may still
|
|
2249
|
+
// be shared deliberately through the configured persistent metadata store.
|
|
2250
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
2074
2251
|
}
|
|
2075
2252
|
/**
|
|
2076
2253
|
* Get an asset by lattice address.
|
|
@@ -2083,23 +2260,25 @@ var AssetManager = class {
|
|
|
2083
2260
|
* @returns Returns either an Operation or DataAsset based on the asset's metadata
|
|
2084
2261
|
*/
|
|
2085
2262
|
async get(assetId) {
|
|
2086
|
-
if (cache.has(assetId)) {
|
|
2087
|
-
return this._wrap(assetId, cache.get(assetId));
|
|
2263
|
+
if (this.cache.has(assetId)) {
|
|
2264
|
+
return this._wrap(assetId, this.cache.get(assetId));
|
|
2088
2265
|
}
|
|
2089
2266
|
const hash = assetHash(assetId);
|
|
2090
2267
|
if (hash) {
|
|
2091
2268
|
const persisted = getAssetMetadataStore()?.get(normaliseHash(hash));
|
|
2092
2269
|
if (persisted) {
|
|
2093
|
-
cache.set(assetId, persisted);
|
|
2270
|
+
this.cache.set(assetId, persisted);
|
|
2094
2271
|
return this._wrap(assetId, persisted);
|
|
2095
2272
|
}
|
|
2096
2273
|
}
|
|
2097
2274
|
try {
|
|
2098
|
-
const data = await
|
|
2099
|
-
|
|
2100
|
-
|
|
2275
|
+
const data = await venueJson(
|
|
2276
|
+
this.venue,
|
|
2277
|
+
`/api/v1/assets/${assetId}`,
|
|
2278
|
+
{ contentType: null }
|
|
2279
|
+
);
|
|
2101
2280
|
if (hash) {
|
|
2102
|
-
cache.set(assetId, data);
|
|
2281
|
+
this.cache.set(assetId, data);
|
|
2103
2282
|
getAssetMetadataStore()?.put(normaliseHash(hash), data);
|
|
2104
2283
|
}
|
|
2105
2284
|
return this._wrap(assetId, data);
|
|
@@ -2126,18 +2305,19 @@ var AssetManager = class {
|
|
|
2126
2305
|
if (options.limit !== void 0) {
|
|
2127
2306
|
params.set("limit", String(options.limit));
|
|
2128
2307
|
}
|
|
2129
|
-
return
|
|
2130
|
-
|
|
2131
|
-
|
|
2308
|
+
return venueJson(
|
|
2309
|
+
this.venue,
|
|
2310
|
+
`/api/v1/assets?${params.toString()}`,
|
|
2311
|
+
{ contentType: null }
|
|
2312
|
+
);
|
|
2132
2313
|
}
|
|
2133
2314
|
/**
|
|
2134
2315
|
* Register a new asset
|
|
2135
2316
|
* @param assetData - Asset configuration
|
|
2136
2317
|
*/
|
|
2137
2318
|
async register(assetData) {
|
|
2138
|
-
return
|
|
2319
|
+
return venueJson(this.venue, "/api/v1/assets", {
|
|
2139
2320
|
method: "POST",
|
|
2140
|
-
headers: this._buildHeaders(),
|
|
2141
2321
|
body: JSON.stringify(assetData)
|
|
2142
2322
|
}).then((response) => this.get(response));
|
|
2143
2323
|
}
|
|
@@ -2147,9 +2327,11 @@ var AssetManager = class {
|
|
|
2147
2327
|
*/
|
|
2148
2328
|
async getMetadata(assetId) {
|
|
2149
2329
|
try {
|
|
2150
|
-
return await
|
|
2151
|
-
|
|
2152
|
-
|
|
2330
|
+
return await venueJson(
|
|
2331
|
+
this.venue,
|
|
2332
|
+
`/api/v1/assets/${assetId}`,
|
|
2333
|
+
{ contentType: null }
|
|
2334
|
+
);
|
|
2153
2335
|
} catch (error) {
|
|
2154
2336
|
if (error instanceof NotFoundError) {
|
|
2155
2337
|
throw new AssetNotFoundError(assetId);
|
|
@@ -2165,9 +2347,9 @@ var AssetManager = class {
|
|
|
2165
2347
|
*/
|
|
2166
2348
|
async putContent(assetId, content) {
|
|
2167
2349
|
try {
|
|
2168
|
-
return await
|
|
2350
|
+
return await venueJson(this.venue, `/api/v1/assets/${assetId}/content`, {
|
|
2169
2351
|
method: "PUT",
|
|
2170
|
-
|
|
2352
|
+
contentType: null,
|
|
2171
2353
|
body: content
|
|
2172
2354
|
});
|
|
2173
2355
|
} catch (error) {
|
|
@@ -2183,9 +2365,11 @@ var AssetManager = class {
|
|
|
2183
2365
|
*/
|
|
2184
2366
|
async getContent(assetId) {
|
|
2185
2367
|
try {
|
|
2186
|
-
const response = await
|
|
2187
|
-
|
|
2188
|
-
|
|
2368
|
+
const response = await venueStream(
|
|
2369
|
+
this.venue,
|
|
2370
|
+
`/api/v1/assets/${assetId}/content`,
|
|
2371
|
+
{ contentType: null }
|
|
2372
|
+
);
|
|
2189
2373
|
return response.body;
|
|
2190
2374
|
} catch (error) {
|
|
2191
2375
|
if (error instanceof NotFoundError) {
|
|
@@ -2206,17 +2390,11 @@ var AssetManager = class {
|
|
|
2206
2390
|
* Clear the asset cache.
|
|
2207
2391
|
*/
|
|
2208
2392
|
clearCache() {
|
|
2209
|
-
cache.clear();
|
|
2210
|
-
getAssetMetadataStore()?.clear();
|
|
2393
|
+
this.cache.clear();
|
|
2211
2394
|
}
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
_buildHeaders(contentType = "application/json") {
|
|
2216
|
-
const headers = {};
|
|
2217
|
-
if (contentType) headers["Content-Type"] = contentType;
|
|
2218
|
-
this.venue.auth.apply(headers, this.venue.venueId);
|
|
2219
|
-
return headers;
|
|
2395
|
+
/** Clear the explicitly configured cross-session metadata store. */
|
|
2396
|
+
clearPersistentCache() {
|
|
2397
|
+
getAssetMetadataStore()?.clear();
|
|
2220
2398
|
}
|
|
2221
2399
|
};
|
|
2222
2400
|
|
|
@@ -2229,23 +2407,23 @@ var OperationManager = class {
|
|
|
2229
2407
|
* List all named operations available on this venue
|
|
2230
2408
|
*/
|
|
2231
2409
|
async list() {
|
|
2232
|
-
return
|
|
2410
|
+
return venueJson(this.venue, "/api/v1/operations");
|
|
2233
2411
|
}
|
|
2234
2412
|
/**
|
|
2235
2413
|
* Get details of a named operation
|
|
2236
2414
|
* @param name - Operation name (e.g., "v/ops/schema/infer")
|
|
2237
2415
|
*/
|
|
2238
2416
|
async get(name) {
|
|
2239
|
-
return
|
|
2417
|
+
return venueJson(this.venue, `/api/v1/operations/${name}`);
|
|
2240
2418
|
}
|
|
2241
2419
|
/**
|
|
2242
2420
|
* Execute an operation and wait for the result
|
|
2243
2421
|
* @param assetId - Operation asset ID or named operation
|
|
2244
2422
|
* @param input - Operation input parameters
|
|
2245
|
-
* @param options -
|
|
2423
|
+
* @param options - Execution options (e.g., ucans or private execution)
|
|
2246
2424
|
*/
|
|
2247
2425
|
async run(assetId, input, options) {
|
|
2248
|
-
if (this.venue.privateJobs) {
|
|
2426
|
+
if (options?.private ?? this.venue.privateJobs) {
|
|
2249
2427
|
return this._runPrivate(assetId, input, options);
|
|
2250
2428
|
}
|
|
2251
2429
|
const job = await this.invoke(assetId, input, options);
|
|
@@ -2267,9 +2445,8 @@ var OperationManager = class {
|
|
|
2267
2445
|
wait: true
|
|
2268
2446
|
};
|
|
2269
2447
|
if (options?.ucans) payload.ucans = options.ucans;
|
|
2270
|
-
const rec = await
|
|
2448
|
+
const rec = await venueJson(this.venue, "/api/v1/invoke", {
|
|
2271
2449
|
method: "POST",
|
|
2272
|
-
headers: this._buildHeaders(),
|
|
2273
2450
|
body: JSON.stringify(payload)
|
|
2274
2451
|
});
|
|
2275
2452
|
const status = rec.status;
|
|
@@ -2281,6 +2458,7 @@ var OperationManager = class {
|
|
|
2281
2458
|
const job = new Job(rec.id ?? "", this.venue, rec);
|
|
2282
2459
|
return await job.result();
|
|
2283
2460
|
} catch (e) {
|
|
2461
|
+
if (!(e instanceof NotFoundError)) throw e;
|
|
2284
2462
|
throw new CoviaError(
|
|
2285
2463
|
`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})`
|
|
2286
2464
|
);
|
|
@@ -2293,7 +2471,7 @@ var OperationManager = class {
|
|
|
2293
2471
|
* @param options - Invoke options (e.g., ucans)
|
|
2294
2472
|
*/
|
|
2295
2473
|
async invoke(assetId, input, options) {
|
|
2296
|
-
if (this.venue.privateJobs) {
|
|
2474
|
+
if (options?.private ?? this.venue.privateJobs) {
|
|
2297
2475
|
throw new CoviaError(
|
|
2298
2476
|
"Private-jobs mode requires run(): a completed private job is immediately forgotten by the venue, so a poll-style Job cannot collect its result."
|
|
2299
2477
|
);
|
|
@@ -2305,27 +2483,15 @@ var OperationManager = class {
|
|
|
2305
2483
|
if (options?.ucans) {
|
|
2306
2484
|
payload.ucans = options.ucans;
|
|
2307
2485
|
}
|
|
2308
|
-
const response = await
|
|
2486
|
+
const response = await venueJson(this.venue, "/api/v1/invoke", {
|
|
2309
2487
|
method: "POST",
|
|
2310
|
-
headers: this._buildHeaders(),
|
|
2311
2488
|
body: JSON.stringify(payload)
|
|
2312
2489
|
});
|
|
2313
2490
|
return new Job(response.id ?? "", this.venue, response);
|
|
2314
2491
|
}
|
|
2315
|
-
_buildHeaders() {
|
|
2316
|
-
const headers = { "Content-Type": "application/json" };
|
|
2317
|
-
this.venue.auth.apply(headers, this.venue.venueId);
|
|
2318
|
-
return headers;
|
|
2319
|
-
}
|
|
2320
2492
|
};
|
|
2321
2493
|
|
|
2322
2494
|
// src/WorkspaceManager.ts
|
|
2323
|
-
function versionAtLeast2(version, major, minor) {
|
|
2324
|
-
const m = version?.match(/^(\d+)\.(\d+)/);
|
|
2325
|
-
if (!m) return true;
|
|
2326
|
-
const [maj, min] = [Number(m[1]), Number(m[2])];
|
|
2327
|
-
return maj > major || maj === major && min >= minor;
|
|
2328
|
-
}
|
|
2329
2495
|
var WorkspaceManager = class {
|
|
2330
2496
|
constructor(venue) {
|
|
2331
2497
|
this.venue = venue;
|
|
@@ -2333,16 +2499,11 @@ var WorkspaceManager = class {
|
|
|
2333
2499
|
// so pre-0.3 venues pay the probe once, not one failed GET per read.
|
|
2334
2500
|
this.valuesSupported = true;
|
|
2335
2501
|
}
|
|
2336
|
-
_headers() {
|
|
2337
|
-
const headers = { "Content-Type": "application/json" };
|
|
2338
|
-
this.venue.auth.apply(headers, this.venue.venueId);
|
|
2339
|
-
return headers;
|
|
2340
|
-
}
|
|
2341
2502
|
/** GET a job-free `/api/v1/values/{op}` read; omit undefined params. */
|
|
2342
2503
|
_values(op, params) {
|
|
2343
2504
|
const qs = new URLSearchParams();
|
|
2344
2505
|
for (const [k, v] of Object.entries(params)) if (v !== void 0) qs.set(k, String(v));
|
|
2345
|
-
return
|
|
2506
|
+
return venueJson(this.venue, `/api/v1/values/${op}?${qs.toString()}`);
|
|
2346
2507
|
}
|
|
2347
2508
|
/**
|
|
2348
2509
|
* Whether the venue serves `GET /api/v1/values/*`: no if a probe already
|
|
@@ -2353,40 +2514,46 @@ var WorkspaceManager = class {
|
|
|
2353
2514
|
supportsValues() {
|
|
2354
2515
|
if (!this.valuesSupported) return false;
|
|
2355
2516
|
const status = this.venue.lastKnownStatus;
|
|
2356
|
-
if (status && (!status.version || !
|
|
2517
|
+
if (status && (!status.version || !versionAtLeast(status.version, 0, 3))) {
|
|
2357
2518
|
this.valuesSupported = false;
|
|
2358
2519
|
}
|
|
2359
2520
|
return this.valuesSupported;
|
|
2360
2521
|
}
|
|
2361
|
-
|
|
2362
|
-
|
|
2522
|
+
unsupported(feature) {
|
|
2523
|
+
throw new UnsupportedVenueFeatureError(feature);
|
|
2524
|
+
}
|
|
2525
|
+
/** A job-free Values read that rejects when the endpoint is unavailable. */
|
|
2526
|
+
async valuesRead(op, params) {
|
|
2363
2527
|
if (this.supportsValues()) {
|
|
2364
2528
|
try {
|
|
2365
2529
|
return await this._values(op, params);
|
|
2366
2530
|
} catch (e) {
|
|
2367
2531
|
if (!(e instanceof NotFoundError)) throw e;
|
|
2532
|
+
if (!ROUTE_MISSING_404.test(e.message)) throw e;
|
|
2368
2533
|
this.valuesSupported = false;
|
|
2369
2534
|
}
|
|
2370
2535
|
}
|
|
2371
|
-
return
|
|
2536
|
+
return this.unsupported(`workspace ${op} reads`);
|
|
2372
2537
|
}
|
|
2373
2538
|
// ── job-free reads (#177) ───────────────────────────────────────────────────
|
|
2374
2539
|
async read(path, maxSize, ucans) {
|
|
2375
|
-
if (ucans?.length) return this.
|
|
2376
|
-
return this.
|
|
2540
|
+
if (ucans?.length) return this.unsupported("UCAN-authorised workspace reads");
|
|
2541
|
+
return this.valuesRead("read", { path, maxSize });
|
|
2377
2542
|
}
|
|
2378
2543
|
async list(path, limit, offset, ucans) {
|
|
2379
2544
|
path = path || "/";
|
|
2380
|
-
if (ucans?.length) return this.
|
|
2381
|
-
return this.
|
|
2545
|
+
if (ucans?.length) return this.unsupported("UCAN-authorised workspace listings");
|
|
2546
|
+
return this.valuesRead("list", { path, limit, offset });
|
|
2382
2547
|
}
|
|
2383
2548
|
async slice(path, offset, limit, ucans) {
|
|
2384
|
-
if (ucans?.length) return this.
|
|
2385
|
-
return this.
|
|
2549
|
+
if (ucans?.length) return this.unsupported("UCAN-authorised workspace slices");
|
|
2550
|
+
return this.valuesRead("slice", { path, offset, limit });
|
|
2386
2551
|
}
|
|
2387
2552
|
async inspect(paths, budget, compact, ucans) {
|
|
2388
|
-
if (ucans?.length || Array.isArray(paths)) return this.
|
|
2389
|
-
|
|
2553
|
+
if (ucans?.length || Array.isArray(paths)) return this.unsupported(
|
|
2554
|
+
Array.isArray(paths) ? "multi-path workspace inspection" : "UCAN-authorised workspace inspection"
|
|
2555
|
+
);
|
|
2556
|
+
return this.valuesRead("inspect", { path: paths, budget, compact });
|
|
2390
2557
|
}
|
|
2391
2558
|
/**
|
|
2392
2559
|
* Count entries at a depth below `path` — a job-free server-side tally, so the
|
|
@@ -2398,8 +2565,8 @@ var WorkspaceManager = class {
|
|
|
2398
2565
|
*/
|
|
2399
2566
|
async count(path, opts = {}) {
|
|
2400
2567
|
const { depth, ucans } = opts;
|
|
2401
|
-
if (ucans?.length) return this.
|
|
2402
|
-
return this.
|
|
2568
|
+
if (ucans?.length) return this.unsupported("UCAN-authorised workspace counts");
|
|
2569
|
+
return this.valuesRead("count", { path, depth });
|
|
2403
2570
|
}
|
|
2404
2571
|
/**
|
|
2405
2572
|
* Count entries at a depth below `path`, optionally partitioned by a field —
|
|
@@ -2411,8 +2578,8 @@ var WorkspaceManager = class {
|
|
|
2411
2578
|
*/
|
|
2412
2579
|
async aggregate(path, opts = {}) {
|
|
2413
2580
|
const { depth, groupBy, ucans } = opts;
|
|
2414
|
-
if (ucans?.length) return this.
|
|
2415
|
-
return this.
|
|
2581
|
+
if (ucans?.length) return this.unsupported("UCAN-authorised workspace aggregation");
|
|
2582
|
+
return this.valuesRead("aggregate", { path, depth, groupBy });
|
|
2416
2583
|
}
|
|
2417
2584
|
// ── writes stay on the job path (they should leave an audit record) ─────────
|
|
2418
2585
|
async write(path, value, ucans) {
|
|
@@ -2473,6 +2640,121 @@ var SecretManager = class {
|
|
|
2473
2640
|
}
|
|
2474
2641
|
};
|
|
2475
2642
|
|
|
2643
|
+
// src/SkillManager.ts
|
|
2644
|
+
var PAGE_SIZE = 100;
|
|
2645
|
+
var SkillManager = class {
|
|
2646
|
+
constructor(venue) {
|
|
2647
|
+
this.venue = venue;
|
|
2648
|
+
}
|
|
2649
|
+
/** Return every skill asset directly contained at `path`. */
|
|
2650
|
+
async list(path) {
|
|
2651
|
+
const location = path.replace(/\/+$/, "");
|
|
2652
|
+
const skills = [];
|
|
2653
|
+
let offset = 0;
|
|
2654
|
+
for (; ; ) {
|
|
2655
|
+
const page = await this.venue.workspace.list(location, PAGE_SIZE, offset);
|
|
2656
|
+
if (!page.exists) {
|
|
2657
|
+
if (skills.length === 0) return [];
|
|
2658
|
+
throw new CoviaError(`Skill listing at ${location} disappeared mid-listing`);
|
|
2659
|
+
}
|
|
2660
|
+
const keys = page.keys ?? [];
|
|
2661
|
+
const assets = await Promise.all(
|
|
2662
|
+
keys.map((key) => this.get(`${location}/${key}`))
|
|
2663
|
+
);
|
|
2664
|
+
skills.push(...assets);
|
|
2665
|
+
const nextOffset = (page.offset ?? offset) + keys.length;
|
|
2666
|
+
if (keys.length === 0 || nextOffset >= (page.count ?? nextOffset)) break;
|
|
2667
|
+
if (nextOffset <= offset) {
|
|
2668
|
+
throw new CoviaError("Venue returned a skills page that did not advance");
|
|
2669
|
+
}
|
|
2670
|
+
offset = nextOffset;
|
|
2671
|
+
}
|
|
2672
|
+
return skills;
|
|
2673
|
+
}
|
|
2674
|
+
/** Return the ordinary asset at exactly `path`, with typed skill metadata. */
|
|
2675
|
+
async get(path) {
|
|
2676
|
+
return this.venue.assets.get(path);
|
|
2677
|
+
}
|
|
2678
|
+
};
|
|
2679
|
+
|
|
2680
|
+
// src/MemoryManager.ts
|
|
2681
|
+
var DEFAULT_MEMORY_PATH = "w/memory";
|
|
2682
|
+
function memoryChange(value) {
|
|
2683
|
+
const result = record(value);
|
|
2684
|
+
if (typeof result?.n !== "number" || typeof result.count !== "number") {
|
|
2685
|
+
throw new CoviaError("Venue returned an invalid memory mutation result");
|
|
2686
|
+
}
|
|
2687
|
+
return { number: result.n, count: result.count };
|
|
2688
|
+
}
|
|
2689
|
+
var MemoryManager = class {
|
|
2690
|
+
constructor(venue) {
|
|
2691
|
+
this.venue = venue;
|
|
2692
|
+
}
|
|
2693
|
+
/**
|
|
2694
|
+
* Read memory directly from the workspace Values surface. This is job-free;
|
|
2695
|
+
* unlike `v/ops/memory {command:'recall'}`, it returns structured entries
|
|
2696
|
+
* rather than an LLM-oriented numbered text block.
|
|
2697
|
+
*/
|
|
2698
|
+
async list(path = DEFAULT_MEMORY_PATH) {
|
|
2699
|
+
const result = await this.venue.workspace.read(path);
|
|
2700
|
+
if (!result.exists) {
|
|
2701
|
+
return [];
|
|
2702
|
+
}
|
|
2703
|
+
let raw;
|
|
2704
|
+
if (result.truncated) {
|
|
2705
|
+
raw = await sliceAll(this.venue.workspace, path);
|
|
2706
|
+
} else if (result.value === void 0 || result.value === null) {
|
|
2707
|
+
return [];
|
|
2708
|
+
} else if (Array.isArray(result.value)) {
|
|
2709
|
+
raw = result.value;
|
|
2710
|
+
} else {
|
|
2711
|
+
throw new CoviaError(`Memory at ${path} is not a flat list`);
|
|
2712
|
+
}
|
|
2713
|
+
const entries = raw.map((value, index) => {
|
|
2714
|
+
const item = record(value);
|
|
2715
|
+
const text = typeof value === "string" ? value : typeof item?.text === "string" ? item.text : void 0;
|
|
2716
|
+
if (text === void 0) {
|
|
2717
|
+
throw new CoviaError(`Memory entry ${index + 1} at ${path} has no text`);
|
|
2718
|
+
}
|
|
2719
|
+
return {
|
|
2720
|
+
number: index + 1,
|
|
2721
|
+
text,
|
|
2722
|
+
createdAt: typeof item?.ts === "number" ? item.ts : void 0,
|
|
2723
|
+
updatedAt: typeof item?.updated === "number" ? item.updated : void 0
|
|
2724
|
+
};
|
|
2725
|
+
});
|
|
2726
|
+
return entries;
|
|
2727
|
+
}
|
|
2728
|
+
/** Append a memory entry. Mutations intentionally remain audited Jobs. */
|
|
2729
|
+
async remember(text, path = DEFAULT_MEMORY_PATH) {
|
|
2730
|
+
const result = await this.venue.operations.run("v/ops/memory", {
|
|
2731
|
+
command: "remember",
|
|
2732
|
+
text,
|
|
2733
|
+
path
|
|
2734
|
+
});
|
|
2735
|
+
return memoryChange(result);
|
|
2736
|
+
}
|
|
2737
|
+
/** Replace a 1-based memory entry. Mutations intentionally remain audited Jobs. */
|
|
2738
|
+
async update(number, text, path = DEFAULT_MEMORY_PATH) {
|
|
2739
|
+
const result = await this.venue.operations.run("v/ops/memory", {
|
|
2740
|
+
command: "update",
|
|
2741
|
+
n: number,
|
|
2742
|
+
text,
|
|
2743
|
+
path
|
|
2744
|
+
});
|
|
2745
|
+
return memoryChange(result);
|
|
2746
|
+
}
|
|
2747
|
+
/** Remove a 1-based memory entry. Mutations intentionally remain audited Jobs. */
|
|
2748
|
+
async forget(number, path = DEFAULT_MEMORY_PATH) {
|
|
2749
|
+
const result = await this.venue.operations.run("v/ops/memory", {
|
|
2750
|
+
command: "forget",
|
|
2751
|
+
n: number,
|
|
2752
|
+
path
|
|
2753
|
+
});
|
|
2754
|
+
return memoryChange(result);
|
|
2755
|
+
}
|
|
2756
|
+
};
|
|
2757
|
+
|
|
2476
2758
|
// src/Agent.ts
|
|
2477
2759
|
var Agent = class _Agent {
|
|
2478
2760
|
constructor(id, venue) {
|
|
@@ -2514,6 +2796,14 @@ var Agent = class _Agent {
|
|
|
2514
2796
|
async info() {
|
|
2515
2797
|
return this._agents.info(this.id);
|
|
2516
2798
|
}
|
|
2799
|
+
/** Page this agent's sessions through the job-free workspace Values API. */
|
|
2800
|
+
async listSessions(options) {
|
|
2801
|
+
return this._agents.listSessions(this.id, options);
|
|
2802
|
+
}
|
|
2803
|
+
/** Read one session through the job-free workspace Values API. */
|
|
2804
|
+
async getSession(sessionId) {
|
|
2805
|
+
return this._agents.getSession(this.id, sessionId);
|
|
2806
|
+
}
|
|
2517
2807
|
/**
|
|
2518
2808
|
* Fork this agent into a new agent.
|
|
2519
2809
|
* @param agentId - ID for the new forked agent
|
|
@@ -2598,7 +2888,11 @@ function connectionFailureMessage(venueId, attempts) {
|
|
|
2598
2888
|
}
|
|
2599
2889
|
var Venue = class _Venue {
|
|
2600
2890
|
constructor(options = {}) {
|
|
2601
|
-
|
|
2891
|
+
this._closed = false;
|
|
2892
|
+
/**
|
|
2893
|
+
* Connection-level private-jobs mode — see {@link setPrivate}.
|
|
2894
|
+
* @deprecated Pass `{ private: true }` to `operations.run()` instead.
|
|
2895
|
+
*/
|
|
2602
2896
|
this.privateJobs = false;
|
|
2603
2897
|
this.baseUrl = options.baseUrl || "";
|
|
2604
2898
|
this.venueId = options.venueId || "";
|
|
@@ -2609,6 +2903,10 @@ var Venue = class _Venue {
|
|
|
2609
2903
|
description: options.description || ""
|
|
2610
2904
|
};
|
|
2611
2905
|
}
|
|
2906
|
+
/** Whether this handle has been closed and should not be reused by Grid. */
|
|
2907
|
+
get closed() {
|
|
2908
|
+
return this._closed;
|
|
2909
|
+
}
|
|
2612
2910
|
/**
|
|
2613
2911
|
* Puts this connection in **private-jobs mode**: every subsequent
|
|
2614
2912
|
* `operations.run(...)` executes as a memory-only job (covia #192) — never
|
|
@@ -2617,7 +2915,10 @@ var Venue = class _Venue {
|
|
|
2617
2915
|
*
|
|
2618
2916
|
* Because a completed private job is immediately forgotten, results are
|
|
2619
2917
|
* collected through the invoke `wait` window rather than polling — so
|
|
2620
|
-
|
|
2918
|
+
* private mode works with `run()`; a poll-style `invoke()` throws.
|
|
2919
|
+
*
|
|
2920
|
+
* @deprecated Pass `{ private: true }` to `operations.run()` instead. The
|
|
2921
|
+
* per-call option avoids mutable connection-wide execution state.
|
|
2621
2922
|
*/
|
|
2622
2923
|
setPrivate(enabled) {
|
|
2623
2924
|
this.privateJobs = enabled;
|
|
@@ -2646,6 +2947,12 @@ var Venue = class _Venue {
|
|
|
2646
2947
|
get secrets() {
|
|
2647
2948
|
return this._secrets ?? (this._secrets = new SecretManager(this));
|
|
2648
2949
|
}
|
|
2950
|
+
get skills() {
|
|
2951
|
+
return this._skills ?? (this._skills = new SkillManager(this));
|
|
2952
|
+
}
|
|
2953
|
+
get memory() {
|
|
2954
|
+
return this._memory ?? (this._memory = new MemoryManager(this));
|
|
2955
|
+
}
|
|
2649
2956
|
/**
|
|
2650
2957
|
* Connect to a venue, validating it with `GET {base}/api/v1/status`. If the
|
|
2651
2958
|
* venue is auth-gated (status answers 401/403 — public access disabled), the
|
|
@@ -2675,7 +2982,7 @@ var Venue = class _Venue {
|
|
|
2675
2982
|
baseUrl: venueId.baseUrl,
|
|
2676
2983
|
venueId: venueId.venueId,
|
|
2677
2984
|
name: venueId.metadata.name,
|
|
2678
|
-
auth,
|
|
2985
|
+
auth: auth ?? venueId.auth,
|
|
2679
2986
|
status: venueId.lastKnownStatus
|
|
2680
2987
|
});
|
|
2681
2988
|
await connected.status();
|
|
@@ -2694,7 +3001,7 @@ var Venue = class _Venue {
|
|
|
2694
3001
|
if (typeof endpoint !== "string") {
|
|
2695
3002
|
throw new CoviaError("No (string) endpoint found for DID");
|
|
2696
3003
|
}
|
|
2697
|
-
candidates = [endpoint.replace(/\/api\/v1
|
|
3004
|
+
candidates = [stripTrailingSlash(endpoint).replace(/\/api\/v1$/, "")];
|
|
2698
3005
|
} else {
|
|
2699
3006
|
candidates = venueBaseUrlCandidates(venueId);
|
|
2700
3007
|
}
|
|
@@ -2702,7 +3009,11 @@ var Venue = class _Venue {
|
|
|
2702
3009
|
for (const baseUrl of candidates) {
|
|
2703
3010
|
const statusUrl = baseUrl + "/api/v1/status";
|
|
2704
3011
|
try {
|
|
2705
|
-
const data = await
|
|
3012
|
+
const data = await venueJson({
|
|
3013
|
+
baseUrl,
|
|
3014
|
+
venueId: expectedDid ?? "",
|
|
3015
|
+
auth: new NoAuth()
|
|
3016
|
+
}, "/api/v1/status");
|
|
2706
3017
|
if (!data.did) {
|
|
2707
3018
|
throw new CoviaError(`Venue status at ${statusUrl} did not include a DID`);
|
|
2708
3019
|
}
|
|
@@ -2787,9 +3098,10 @@ var Venue = class _Venue {
|
|
|
2787
3098
|
* @returns {Promise<string[]>}
|
|
2788
3099
|
*/
|
|
2789
3100
|
async listSecrets() {
|
|
2790
|
-
const result = await
|
|
2791
|
-
|
|
2792
|
-
|
|
3101
|
+
const result = await venueJson(
|
|
3102
|
+
this,
|
|
3103
|
+
"/api/v1/secrets"
|
|
3104
|
+
);
|
|
2793
3105
|
return Array.isArray(result.items) ? result.items : [];
|
|
2794
3106
|
}
|
|
2795
3107
|
/**
|
|
@@ -2797,9 +3109,8 @@ var Venue = class _Venue {
|
|
|
2797
3109
|
* @param name - Secret name
|
|
2798
3110
|
*/
|
|
2799
3111
|
async deleteSecret(name) {
|
|
2800
|
-
await
|
|
2801
|
-
method: "DELETE"
|
|
2802
|
-
headers: this._buildHeaders()
|
|
3112
|
+
await venueStream(this, `/api/v1/secrets/${encodeURIComponent(name)}`, {
|
|
3113
|
+
method: "DELETE"
|
|
2803
3114
|
});
|
|
2804
3115
|
}
|
|
2805
3116
|
/**
|
|
@@ -2808,7 +3119,7 @@ var Venue = class _Venue {
|
|
|
2808
3119
|
* @throws {VenueIdentityChangedError} If this address reports a different known DID.
|
|
2809
3120
|
*/
|
|
2810
3121
|
async status() {
|
|
2811
|
-
const data = await
|
|
3122
|
+
const data = await venueJson(this, "/api/v1/status");
|
|
2812
3123
|
if (data.did) {
|
|
2813
3124
|
if (this.venueId) {
|
|
2814
3125
|
assertVenueIdentity(this.venueId, data.did, this.baseUrl);
|
|
@@ -2876,7 +3187,8 @@ var Venue = class _Venue {
|
|
|
2876
3187
|
* Clears cached asset data for this venue.
|
|
2877
3188
|
*/
|
|
2878
3189
|
close() {
|
|
2879
|
-
this.
|
|
3190
|
+
this._closed = true;
|
|
3191
|
+
this._assets?.clearCache();
|
|
2880
3192
|
}
|
|
2881
3193
|
/**
|
|
2882
3194
|
* Disposable support — allows `using venue = await Grid.connect(...)` in TS 5.2+.
|
|
@@ -2884,15 +3196,28 @@ var Venue = class _Venue {
|
|
|
2884
3196
|
[Symbol.dispose]() {
|
|
2885
3197
|
this.close();
|
|
2886
3198
|
}
|
|
2887
|
-
_buildHeaders() {
|
|
2888
|
-
const headers = { "Content-Type": "application/json" };
|
|
2889
|
-
this.auth.apply(headers, this.venueId);
|
|
2890
|
-
return headers;
|
|
2891
|
-
}
|
|
2892
3199
|
};
|
|
2893
3200
|
|
|
2894
3201
|
// src/Grid.ts
|
|
2895
|
-
var
|
|
3202
|
+
var anonymousConnections = /* @__PURE__ */ new Map();
|
|
3203
|
+
var authenticatedConnections = /* @__PURE__ */ new WeakMap();
|
|
3204
|
+
function connectionsFor(auth) {
|
|
3205
|
+
if (!auth) return anonymousConnections;
|
|
3206
|
+
let connections = authenticatedConnections.get(auth);
|
|
3207
|
+
if (!connections) {
|
|
3208
|
+
connections = /* @__PURE__ */ new Map();
|
|
3209
|
+
authenticatedConnections.set(auth, connections);
|
|
3210
|
+
}
|
|
3211
|
+
return connections;
|
|
3212
|
+
}
|
|
3213
|
+
function normaliseKey(venueId) {
|
|
3214
|
+
return venueId.replace(/\/+$/, "");
|
|
3215
|
+
}
|
|
3216
|
+
function removeEntry(cache, entry) {
|
|
3217
|
+
for (const [key, candidate] of cache) {
|
|
3218
|
+
if (candidate === entry) cache.delete(key);
|
|
3219
|
+
}
|
|
3220
|
+
}
|
|
2896
3221
|
var Grid = class {
|
|
2897
3222
|
/**
|
|
2898
3223
|
* Static method to connect to a venue
|
|
@@ -2901,18 +3226,34 @@ var Grid = class {
|
|
|
2901
3226
|
* @returns {Promise<Venue>} A new Venue instance configured appropriately
|
|
2902
3227
|
*/
|
|
2903
3228
|
static async connect(venueId, auth) {
|
|
2904
|
-
const
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
3229
|
+
const cache = connectionsFor(auth);
|
|
3230
|
+
const key = normaliseKey(venueId);
|
|
3231
|
+
const cached = cache.get(key);
|
|
3232
|
+
if (cached) {
|
|
3233
|
+
if (!cached.venue?.closed) return cached.promise;
|
|
3234
|
+
removeEntry(cache, cached);
|
|
3235
|
+
}
|
|
3236
|
+
const entry = {};
|
|
3237
|
+
entry.promise = Venue.connect(venueId, auth).then((venue) => {
|
|
3238
|
+
entry.venue = venue;
|
|
3239
|
+
cache.set(normaliseKey(venue.baseUrl), entry);
|
|
3240
|
+
if (key.startsWith("did:")) {
|
|
3241
|
+
cache.set(normaliseKey(venue.venueId), entry);
|
|
3242
|
+
}
|
|
3243
|
+
return venue;
|
|
3244
|
+
}).catch((error) => {
|
|
3245
|
+
removeEntry(cache, entry);
|
|
3246
|
+
throw error;
|
|
3247
|
+
});
|
|
3248
|
+
cache.set(key, entry);
|
|
3249
|
+
return entry.promise;
|
|
2910
3250
|
}
|
|
2911
3251
|
};
|
|
2912
3252
|
|
|
2913
3253
|
// src/crypto/ucan.ts
|
|
2914
3254
|
var encoder2 = new TextEncoder();
|
|
2915
3255
|
var VENUE_RELAY = "venue/relay";
|
|
3256
|
+
var UCV_VERSION = "0.10.0";
|
|
2916
3257
|
function didFor(privateKey) {
|
|
2917
3258
|
return `did:key:${encodePublicKey(getPublicKey2(privateKey))}`;
|
|
2918
3259
|
}
|
|
@@ -2923,10 +3264,11 @@ function createUCANJWT(privateKey, audienceDID, att, lifetimeSeconds, proofs = [
|
|
|
2923
3264
|
const claims = {
|
|
2924
3265
|
iss: `did:key:${multikey}`,
|
|
2925
3266
|
aud: audienceDID,
|
|
3267
|
+
ucv: UCV_VERSION,
|
|
2926
3268
|
att,
|
|
2927
|
-
|
|
3269
|
+
prf: proofs,
|
|
3270
|
+
exp: lifetimeSeconds === null ? null : nowSecs + lifetimeSeconds
|
|
2928
3271
|
};
|
|
2929
|
-
if (proofs.length) claims.prf = proofs;
|
|
2930
3272
|
const signingInput = `${base64UrlEncode(encoder2.encode(header))}.${base64UrlEncode(encoder2.encode(JSON.stringify(claims)))}`;
|
|
2931
3273
|
const signature = sign(encoder2.encode(signingInput), privateKey);
|
|
2932
3274
|
return `${signingInput}.${base64UrlEncode(signature)}`;
|
|
@@ -2950,6 +3292,7 @@ function relayDelegation(privateKey, venueDID, lifetimeSeconds, caps = []) {
|
|
|
2950
3292
|
exports.AdapterManager = AdapterManager;
|
|
2951
3293
|
exports.Agent = Agent;
|
|
2952
3294
|
exports.AgentManager = AgentManager;
|
|
3295
|
+
exports.AgentSessionNotFoundError = AgentSessionNotFoundError;
|
|
2953
3296
|
exports.AgentStatus = AgentStatus;
|
|
2954
3297
|
exports.Asset = Asset;
|
|
2955
3298
|
exports.AssetManager = AssetManager;
|
|
@@ -2972,6 +3315,7 @@ exports.JobManager = JobManager;
|
|
|
2972
3315
|
exports.JobNotFoundError = JobNotFoundError;
|
|
2973
3316
|
exports.JobStatus = JobStatus;
|
|
2974
3317
|
exports.KeyPairAuth = KeyPairAuth;
|
|
3318
|
+
exports.MemoryManager = MemoryManager;
|
|
2975
3319
|
exports.Namespace = Namespace;
|
|
2976
3320
|
exports.NoAuth = NoAuth;
|
|
2977
3321
|
exports.NotFoundError = NotFoundError;
|
|
@@ -2980,7 +3324,9 @@ exports.OperationManager = OperationManager;
|
|
|
2980
3324
|
exports.RateLimitError = RateLimitError;
|
|
2981
3325
|
exports.RunStatus = RunStatus;
|
|
2982
3326
|
exports.SecretManager = SecretManager;
|
|
3327
|
+
exports.SkillManager = SkillManager;
|
|
2983
3328
|
exports.UCANManager = UCANManager;
|
|
3329
|
+
exports.UnsupportedVenueFeatureError = UnsupportedVenueFeatureError;
|
|
2984
3330
|
exports.VENUE_RELAY = VENUE_RELAY;
|
|
2985
3331
|
exports.Venue = Venue;
|
|
2986
3332
|
exports.VenueIdentityChangedError = VenueIdentityChangedError;
|