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