@hotcell/daemon 0.1.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/dist/agent-check.d.ts +1 -0
- package/dist/agent-check.js +105 -0
- package/dist/agent-check.js.map +1 -0
- package/dist/api/server.d.ts +64 -0
- package/dist/api/server.js +1368 -0
- package/dist/api/server.js.map +1 -0
- package/dist/api/ws.d.ts +14 -0
- package/dist/api/ws.js +214 -0
- package/dist/api/ws.js.map +1 -0
- package/dist/applevz-check.d.ts +1 -0
- package/dist/applevz-check.js +280 -0
- package/dist/applevz-check.js.map +1 -0
- package/dist/backups.d.ts +29 -0
- package/dist/backups.js +76 -0
- package/dist/backups.js.map +1 -0
- package/dist/capacity.d.ts +63 -0
- package/dist/capacity.js +95 -0
- package/dist/capacity.js.map +1 -0
- package/dist/config.d.ts +241 -0
- package/dist/config.js +152 -0
- package/dist/config.js.map +1 -0
- package/dist/cost.d.ts +9 -0
- package/dist/cost.js +19 -0
- package/dist/cost.js.map +1 -0
- package/dist/density-bench.d.ts +1 -0
- package/dist/density-bench.js +97 -0
- package/dist/density-bench.js.map +1 -0
- package/dist/driver/agent-driver.d.ts +67 -0
- package/dist/driver/agent-driver.js +197 -0
- package/dist/driver/agent-driver.js.map +1 -0
- package/dist/driver/agent.d.ts +94 -0
- package/dist/driver/agent.js +319 -0
- package/dist/driver/agent.js.map +1 -0
- package/dist/driver/applevz.d.ts +95 -0
- package/dist/driver/applevz.js +527 -0
- package/dist/driver/applevz.js.map +1 -0
- package/dist/driver/container.d.ts +99 -0
- package/dist/driver/container.js +733 -0
- package/dist/driver/container.js.map +1 -0
- package/dist/driver/fc-api.d.ts +85 -0
- package/dist/driver/fc-api.js +173 -0
- package/dist/driver/fc-api.js.map +1 -0
- package/dist/driver/firecracker.d.ts +126 -0
- package/dist/driver/firecracker.js +560 -0
- package/dist/driver/firecracker.js.map +1 -0
- package/dist/driver/index.d.ts +17 -0
- package/dist/driver/index.js +61 -0
- package/dist/driver/index.js.map +1 -0
- package/dist/driver/router.d.ts +82 -0
- package/dist/driver/router.js +159 -0
- package/dist/driver/router.js.map +1 -0
- package/dist/driver/types.d.ts +234 -0
- package/dist/driver/types.js +2 -0
- package/dist/driver/types.js.map +1 -0
- package/dist/driver/unsupported.d.ts +50 -0
- package/dist/driver/unsupported.js +81 -0
- package/dist/driver/unsupported.js.map +1 -0
- package/dist/driver/vz-image.d.ts +35 -0
- package/dist/driver/vz-image.js +75 -0
- package/dist/driver/vz-image.js.map +1 -0
- package/dist/e2e-harness.d.ts +1 -0
- package/dist/e2e-harness.js +99 -0
- package/dist/e2e-harness.js.map +1 -0
- package/dist/egress-check.d.ts +8 -0
- package/dist/egress-check.js +317 -0
- package/dist/egress-check.js.map +1 -0
- package/dist/fc-check.d.ts +1 -0
- package/dist/fc-check.js +113 -0
- package/dist/fc-check.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +114 -0
- package/dist/index.js.map +1 -0
- package/dist/kernels.d.ts +22 -0
- package/dist/kernels.js +134 -0
- package/dist/kernels.js.map +1 -0
- package/dist/lifecycle.d.ts +49 -0
- package/dist/lifecycle.js +111 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/logger.d.ts +16 -0
- package/dist/logger.js +67 -0
- package/dist/logger.js.map +1 -0
- package/dist/metrics.d.ts +46 -0
- package/dist/metrics.js +92 -0
- package/dist/metrics.js.map +1 -0
- package/dist/net/firewall.d.ts +4 -0
- package/dist/net/firewall.js +80 -0
- package/dist/net/firewall.js.map +1 -0
- package/dist/pricing.d.ts +36 -0
- package/dist/pricing.js +81 -0
- package/dist/pricing.js.map +1 -0
- package/dist/proxy/allowlist-default.d.ts +23 -0
- package/dist/proxy/allowlist-default.js +53 -0
- package/dist/proxy/allowlist-default.js.map +1 -0
- package/dist/proxy/allowlist.d.ts +43 -0
- package/dist/proxy/allowlist.js +87 -0
- package/dist/proxy/allowlist.js.map +1 -0
- package/dist/proxy/egress.d.ts +49 -0
- package/dist/proxy/egress.js +599 -0
- package/dist/proxy/egress.js.map +1 -0
- package/dist/proxy/ratelimit.d.ts +49 -0
- package/dist/proxy/ratelimit.js +74 -0
- package/dist/proxy/ratelimit.js.map +1 -0
- package/dist/proxy/server.d.ts +26 -0
- package/dist/proxy/server.js +202 -0
- package/dist/proxy/server.js.map +1 -0
- package/dist/router-check.d.ts +1 -0
- package/dist/router-check.js +97 -0
- package/dist/router-check.js.map +1 -0
- package/dist/smoke-fc.d.ts +1 -0
- package/dist/smoke-fc.js +183 -0
- package/dist/smoke-fc.js.map +1 -0
- package/dist/smoke-microvm.d.ts +1 -0
- package/dist/smoke-microvm.js +187 -0
- package/dist/smoke-microvm.js.map +1 -0
- package/dist/smoke-remote.d.ts +20 -0
- package/dist/smoke-remote.js +155 -0
- package/dist/smoke-remote.js.map +1 -0
- package/dist/smoke-vz.d.ts +1 -0
- package/dist/smoke-vz.js +161 -0
- package/dist/smoke-vz.js.map +1 -0
- package/dist/smoke.d.ts +7 -0
- package/dist/smoke.js +962 -0
- package/dist/smoke.js.map +1 -0
- package/dist/store.d.ts +124 -0
- package/dist/store.js +578 -0
- package/dist/store.js.map +1 -0
- package/dist/tracing.d.ts +45 -0
- package/dist/tracing.js +144 -0
- package/dist/tracing.js.map +1 -0
- package/dist/types.d.ts +274 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/util.d.ts +27 -0
- package/dist/util.js +63 -0
- package/dist/util.js.map +1 -0
- package/dist/warmpool-check.d.ts +1 -0
- package/dist/warmpool-check.js +83 -0
- package/dist/warmpool-check.js.map +1 -0
- package/dist/web/dashboard.d.ts +1 -0
- package/dist/web/dashboard.js +456 -0
- package/dist/web/dashboard.js.map +1 -0
- package/package.json +53 -0
package/dist/store.js
ADDED
|
@@ -0,0 +1,578 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { mkdirSync } from "node:fs";
|
|
3
|
+
import { dirname } from "node:path";
|
|
4
|
+
import { DatabaseSync } from "node:sqlite";
|
|
5
|
+
/** Zero-valued usage accumulator for a fresh sandbox. */
|
|
6
|
+
export function emptyUsage() {
|
|
7
|
+
return {
|
|
8
|
+
cpuSeconds: 0,
|
|
9
|
+
memByteSeconds: 0,
|
|
10
|
+
egressBytes: 0,
|
|
11
|
+
providerCalls: 0,
|
|
12
|
+
providerBytes: 0,
|
|
13
|
+
providerTokensIn: 0,
|
|
14
|
+
providerTokensOut: 0,
|
|
15
|
+
providerCost: 0,
|
|
16
|
+
lastCpuTotalNs: 0,
|
|
17
|
+
lastSampledAt: "",
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Durable sandbox registry backed by embedded SQLite (`node:sqlite`, built into
|
|
22
|
+
* Node ≥22 — no external dependency). Alongside the sandbox records it tracks
|
|
23
|
+
* background processes, exposed preview ports, sessions, and code-interpreter
|
|
24
|
+
* contexts so the full control-plane state survives a daemon restart (the
|
|
25
|
+
* lead-in to the lifecycle FSM).
|
|
26
|
+
*
|
|
27
|
+
* The in-memory `Map`s are a hot cache that is the working copy during the
|
|
28
|
+
* daemon's lifetime — they preserve mutate-by-reference semantics for callers
|
|
29
|
+
* that tweak a returned record in place. Every mutating method is write-through
|
|
30
|
+
* to SQLite; on construction the cache is hydrated from the database. Pass
|
|
31
|
+
* `:memory:` (the default) for an ephemeral, in-process store (tests, smoke).
|
|
32
|
+
*/
|
|
33
|
+
export class SandboxStore {
|
|
34
|
+
db;
|
|
35
|
+
byId = new Map();
|
|
36
|
+
// sandboxId -> procId -> process
|
|
37
|
+
procs = new Map();
|
|
38
|
+
// sandboxId -> port -> exposed port
|
|
39
|
+
exposed = new Map();
|
|
40
|
+
// exposeId -> route target (O(1) lookup for the proxy)
|
|
41
|
+
routes = new Map();
|
|
42
|
+
// sandboxId -> sessionId -> session
|
|
43
|
+
sessions = new Map();
|
|
44
|
+
// sandboxId -> contextId -> code context
|
|
45
|
+
contexts = new Map();
|
|
46
|
+
// egress token -> record (sandboxId + policy + spend; O(1) lookup for the egress proxy)
|
|
47
|
+
egressTokens = new Map();
|
|
48
|
+
constructor(dbPath = ":memory:") {
|
|
49
|
+
if (dbPath !== ":memory:")
|
|
50
|
+
mkdirSync(dirname(dbPath), { recursive: true });
|
|
51
|
+
this.db = new DatabaseSync(dbPath);
|
|
52
|
+
if (dbPath !== ":memory:")
|
|
53
|
+
this.db.exec("PRAGMA journal_mode = WAL;");
|
|
54
|
+
this.migrate();
|
|
55
|
+
this.hydrate();
|
|
56
|
+
}
|
|
57
|
+
/** Close the underlying database handle (call on daemon shutdown). */
|
|
58
|
+
close() {
|
|
59
|
+
this.db.close();
|
|
60
|
+
}
|
|
61
|
+
migrate() {
|
|
62
|
+
this.db.exec(`
|
|
63
|
+
CREATE TABLE IF NOT EXISTS sandboxes (
|
|
64
|
+
id TEXT PRIMARY KEY,
|
|
65
|
+
image TEXT NOT NULL,
|
|
66
|
+
status TEXT NOT NULL,
|
|
67
|
+
createdAt TEXT NOT NULL,
|
|
68
|
+
driver TEXT NOT NULL DEFAULT '',
|
|
69
|
+
labels TEXT NOT NULL,
|
|
70
|
+
env TEXT NOT NULL,
|
|
71
|
+
persist INTEGER NOT NULL,
|
|
72
|
+
lastActivityAt TEXT NOT NULL DEFAULT '',
|
|
73
|
+
sleepAfterMs INTEGER NOT NULL DEFAULT 0,
|
|
74
|
+
usage TEXT NOT NULL DEFAULT '{}',
|
|
75
|
+
limits TEXT NOT NULL DEFAULT '{}',
|
|
76
|
+
egressSpendCap REAL NOT NULL DEFAULT 0
|
|
77
|
+
);
|
|
78
|
+
CREATE TABLE IF NOT EXISTS processes (
|
|
79
|
+
sandboxId TEXT NOT NULL,
|
|
80
|
+
procId TEXT NOT NULL,
|
|
81
|
+
pid INTEGER NOT NULL,
|
|
82
|
+
command TEXT NOT NULL,
|
|
83
|
+
status TEXT NOT NULL,
|
|
84
|
+
exitCode INTEGER,
|
|
85
|
+
startedAt TEXT NOT NULL,
|
|
86
|
+
logPath TEXT NOT NULL,
|
|
87
|
+
PRIMARY KEY (sandboxId, procId)
|
|
88
|
+
);
|
|
89
|
+
CREATE TABLE IF NOT EXISTS exposed_ports (
|
|
90
|
+
sandboxId TEXT NOT NULL,
|
|
91
|
+
port INTEGER NOT NULL,
|
|
92
|
+
exposeId TEXT NOT NULL,
|
|
93
|
+
token TEXT,
|
|
94
|
+
createdAt TEXT NOT NULL,
|
|
95
|
+
url TEXT NOT NULL,
|
|
96
|
+
PRIMARY KEY (sandboxId, port)
|
|
97
|
+
);
|
|
98
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
99
|
+
sandboxId TEXT NOT NULL,
|
|
100
|
+
sessionId TEXT NOT NULL,
|
|
101
|
+
cwd TEXT NOT NULL,
|
|
102
|
+
env TEXT NOT NULL,
|
|
103
|
+
createdAt TEXT NOT NULL,
|
|
104
|
+
PRIMARY KEY (sandboxId, sessionId)
|
|
105
|
+
);
|
|
106
|
+
CREATE TABLE IF NOT EXISTS code_contexts (
|
|
107
|
+
sandboxId TEXT NOT NULL,
|
|
108
|
+
contextId TEXT NOT NULL,
|
|
109
|
+
language TEXT NOT NULL,
|
|
110
|
+
dir TEXT NOT NULL,
|
|
111
|
+
procId TEXT NOT NULL,
|
|
112
|
+
pid INTEGER NOT NULL,
|
|
113
|
+
seq INTEGER NOT NULL,
|
|
114
|
+
createdAt TEXT NOT NULL,
|
|
115
|
+
PRIMARY KEY (sandboxId, contextId)
|
|
116
|
+
);
|
|
117
|
+
CREATE TABLE IF NOT EXISTS egress_tokens (
|
|
118
|
+
token TEXT PRIMARY KEY,
|
|
119
|
+
sandboxId TEXT NOT NULL,
|
|
120
|
+
createdAt TEXT NOT NULL,
|
|
121
|
+
policy TEXT NOT NULL DEFAULT '{}',
|
|
122
|
+
spendUsd REAL NOT NULL DEFAULT 0
|
|
123
|
+
);
|
|
124
|
+
`);
|
|
125
|
+
// Backfill columns added after the first release on databases created by an
|
|
126
|
+
// older daemon (CREATE TABLE IF NOT EXISTS leaves existing tables untouched).
|
|
127
|
+
this.ensureColumn("sandboxes", "lastActivityAt", "TEXT NOT NULL DEFAULT ''");
|
|
128
|
+
this.ensureColumn("sandboxes", "sleepAfterMs", "INTEGER NOT NULL DEFAULT 0");
|
|
129
|
+
this.ensureColumn("sandboxes", "usage", "TEXT NOT NULL DEFAULT '{}'");
|
|
130
|
+
this.ensureColumn("sandboxes", "limits", "TEXT NOT NULL DEFAULT '{}'");
|
|
131
|
+
this.ensureColumn("sandboxes", "egressSpendCap", "REAL NOT NULL DEFAULT 0");
|
|
132
|
+
this.ensureColumn("sandboxes", "driver", "TEXT NOT NULL DEFAULT ''");
|
|
133
|
+
this.ensureColumn("egress_tokens", "policy", "TEXT NOT NULL DEFAULT '{}'");
|
|
134
|
+
this.ensureColumn("egress_tokens", "spendUsd", "REAL NOT NULL DEFAULT 0");
|
|
135
|
+
}
|
|
136
|
+
/** Add a column to a table if it isn't already present (idempotent migration). */
|
|
137
|
+
ensureColumn(table, column, decl) {
|
|
138
|
+
const cols = this.db.prepare(`PRAGMA table_info(${table})`).all();
|
|
139
|
+
if (!cols.some((c) => c.name === column)) {
|
|
140
|
+
this.db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${decl}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/** Load all persisted rows into the in-memory cache on startup. */
|
|
144
|
+
hydrate() {
|
|
145
|
+
for (const row of this.db.prepare("SELECT * FROM sandboxes").all()) {
|
|
146
|
+
this.byId.set(row.id, rowToSandbox(row));
|
|
147
|
+
}
|
|
148
|
+
for (const row of this.db.prepare("SELECT * FROM processes").all()) {
|
|
149
|
+
mapIn(this.procs, row.sandboxId).set(row.procId, rowToProcess(row));
|
|
150
|
+
}
|
|
151
|
+
for (const row of this.db.prepare("SELECT * FROM exposed_ports").all()) {
|
|
152
|
+
const exposed = rowToExposed(row);
|
|
153
|
+
mapIn(this.exposed, row.sandboxId).set(exposed.port, exposed);
|
|
154
|
+
this.routes.set(exposed.exposeId, {
|
|
155
|
+
sandboxId: row.sandboxId,
|
|
156
|
+
port: exposed.port,
|
|
157
|
+
token: exposed.token,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
for (const row of this.db.prepare("SELECT * FROM sessions").all()) {
|
|
161
|
+
mapIn(this.sessions, row.sandboxId).set(row.sessionId, rowToSession(row));
|
|
162
|
+
}
|
|
163
|
+
for (const row of this.db.prepare("SELECT * FROM code_contexts").all()) {
|
|
164
|
+
mapIn(this.contexts, row.sandboxId).set(row.contextId, rowToContext(row));
|
|
165
|
+
}
|
|
166
|
+
for (const row of this.db.prepare("SELECT * FROM egress_tokens").all()) {
|
|
167
|
+
this.egressTokens.set(row.token, rowToEgressToken(row));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
static newId() {
|
|
171
|
+
return randomBytes(6).toString("hex");
|
|
172
|
+
}
|
|
173
|
+
static newContextId() {
|
|
174
|
+
return randomBytes(4).toString("hex");
|
|
175
|
+
}
|
|
176
|
+
static newProcId() {
|
|
177
|
+
return randomBytes(4).toString("hex");
|
|
178
|
+
}
|
|
179
|
+
static newSessionId() {
|
|
180
|
+
return randomBytes(4).toString("hex");
|
|
181
|
+
}
|
|
182
|
+
static newBackupId() {
|
|
183
|
+
return randomBytes(6).toString("hex");
|
|
184
|
+
}
|
|
185
|
+
/** Mint an opaque per-sandbox egress token (used as the gateway's API key). */
|
|
186
|
+
static newEgressToken() {
|
|
187
|
+
return "hc-" + randomBytes(24).toString("hex");
|
|
188
|
+
}
|
|
189
|
+
// --- sandboxes -----------------------------------------------------------
|
|
190
|
+
/** Insert or update a sandbox record (write-through; also use to persist
|
|
191
|
+
* in-place edits to a record returned by `get`). */
|
|
192
|
+
add(record) {
|
|
193
|
+
this.byId.set(record.id, record);
|
|
194
|
+
this.db
|
|
195
|
+
.prepare(`INSERT INTO sandboxes
|
|
196
|
+
(id, image, status, createdAt, driver, labels, env, persist, lastActivityAt, sleepAfterMs, usage, limits, egressSpendCap)
|
|
197
|
+
VALUES
|
|
198
|
+
($id, $image, $status, $createdAt, $driver, $labels, $env, $persist, $lastActivityAt, $sleepAfterMs, $usage, $limits, $egressSpendCap)
|
|
199
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
200
|
+
image=$image, status=$status, createdAt=$createdAt, driver=$driver,
|
|
201
|
+
labels=$labels, env=$env, persist=$persist,
|
|
202
|
+
lastActivityAt=$lastActivityAt, sleepAfterMs=$sleepAfterMs, usage=$usage, limits=$limits,
|
|
203
|
+
egressSpendCap=$egressSpendCap`)
|
|
204
|
+
.run({
|
|
205
|
+
id: record.id,
|
|
206
|
+
image: record.image,
|
|
207
|
+
status: record.status,
|
|
208
|
+
createdAt: record.createdAt,
|
|
209
|
+
driver: record.driver ?? "",
|
|
210
|
+
labels: JSON.stringify(record.labels),
|
|
211
|
+
env: JSON.stringify(record.env),
|
|
212
|
+
persist: record.persist ? 1 : 0,
|
|
213
|
+
lastActivityAt: record.lastActivityAt,
|
|
214
|
+
sleepAfterMs: record.sleepAfterMs,
|
|
215
|
+
usage: JSON.stringify(record.usage),
|
|
216
|
+
limits: JSON.stringify(record.limits ?? {}),
|
|
217
|
+
egressSpendCap: record.egressSpendCapUsd ?? 0,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Persist updated cumulative usage for a sandbox (write-through). Cheap single
|
|
222
|
+
* column used by the metrics sampler on every tick. No-op for an unknown id.
|
|
223
|
+
*/
|
|
224
|
+
setUsage(id, usage) {
|
|
225
|
+
const rec = this.byId.get(id);
|
|
226
|
+
if (!rec)
|
|
227
|
+
return;
|
|
228
|
+
rec.usage = usage;
|
|
229
|
+
this.db
|
|
230
|
+
.prepare("UPDATE sandboxes SET usage = ? WHERE id = ?")
|
|
231
|
+
.run(JSON.stringify(usage), id);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Add to a sandbox's cumulative egress byte counter (write-through). Called by
|
|
235
|
+
* the preview proxy as connections close. No-op for an unknown id.
|
|
236
|
+
*/
|
|
237
|
+
addEgress(id, bytes) {
|
|
238
|
+
const rec = this.byId.get(id);
|
|
239
|
+
if (!rec || bytes <= 0)
|
|
240
|
+
return;
|
|
241
|
+
rec.usage.egressBytes += bytes;
|
|
242
|
+
this.db
|
|
243
|
+
.prepare("UPDATE sandboxes SET usage = ? WHERE id = ?")
|
|
244
|
+
.run(JSON.stringify(rec.usage), id);
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Record one LLM-provider call's usage (write-through). Called by the egress
|
|
248
|
+
* credential proxy as each provider response completes. No-op for unknown id.
|
|
249
|
+
*/
|
|
250
|
+
addProviderUsage(id, delta) {
|
|
251
|
+
const rec = this.byId.get(id);
|
|
252
|
+
if (!rec)
|
|
253
|
+
return;
|
|
254
|
+
rec.usage.providerCalls += 1;
|
|
255
|
+
rec.usage.providerBytes += Math.max(0, delta.bytes);
|
|
256
|
+
rec.usage.providerTokensIn += Math.max(0, delta.tokensIn);
|
|
257
|
+
rec.usage.providerTokensOut += Math.max(0, delta.tokensOut);
|
|
258
|
+
rec.usage.providerCost += Math.max(0, delta.cost);
|
|
259
|
+
this.db
|
|
260
|
+
.prepare("UPDATE sandboxes SET usage = ? WHERE id = ?")
|
|
261
|
+
.run(JSON.stringify(rec.usage), id);
|
|
262
|
+
}
|
|
263
|
+
// --- egress tokens -------------------------------------------------------
|
|
264
|
+
/** Bind an egress token to a sandbox with an optional policy (write-through). */
|
|
265
|
+
addEgressToken(token, sandboxId, policy = {}) {
|
|
266
|
+
const record = {
|
|
267
|
+
token,
|
|
268
|
+
sandboxId,
|
|
269
|
+
policy,
|
|
270
|
+
createdAt: new Date().toISOString(),
|
|
271
|
+
spendUsd: 0,
|
|
272
|
+
};
|
|
273
|
+
this.egressTokens.set(token, record);
|
|
274
|
+
this.db
|
|
275
|
+
.prepare("INSERT OR REPLACE INTO egress_tokens (token, sandboxId, createdAt, policy, spendUsd) VALUES (?, ?, ?, ?, ?)")
|
|
276
|
+
.run(token, sandboxId, record.createdAt, JSON.stringify(policy), 0);
|
|
277
|
+
}
|
|
278
|
+
/** Resolve an egress token to its sandbox id (O(1)). Back-compat shorthand. */
|
|
279
|
+
resolveEgressToken(token) {
|
|
280
|
+
return this.egressTokens.get(token)?.sandboxId;
|
|
281
|
+
}
|
|
282
|
+
/** Resolve an egress token to its full record (sandbox + policy + spend). */
|
|
283
|
+
resolveEgressTokenFull(token) {
|
|
284
|
+
return this.egressTokens.get(token);
|
|
285
|
+
}
|
|
286
|
+
/** Add to a token's cumulative spend (write-through). Drives the spend cap. */
|
|
287
|
+
addEgressTokenSpend(token, usd) {
|
|
288
|
+
const rec = this.egressTokens.get(token);
|
|
289
|
+
if (!rec || !(usd > 0))
|
|
290
|
+
return;
|
|
291
|
+
rec.spendUsd += usd;
|
|
292
|
+
this.db
|
|
293
|
+
.prepare("UPDATE egress_tokens SET spendUsd = ? WHERE token = ?")
|
|
294
|
+
.run(rec.spendUsd, token);
|
|
295
|
+
}
|
|
296
|
+
/** List the egress token records minted for a sandbox. */
|
|
297
|
+
listEgressTokens(sandboxId) {
|
|
298
|
+
return [...this.egressTokens.values()].filter((r) => r.sandboxId === sandboxId);
|
|
299
|
+
}
|
|
300
|
+
/** Revoke a single egress token. Returns whether it existed. */
|
|
301
|
+
removeEgressToken(token) {
|
|
302
|
+
this.db.prepare("DELETE FROM egress_tokens WHERE token = ?").run(token);
|
|
303
|
+
return this.egressTokens.delete(token);
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Mark a sandbox as just-active (refresh `lastActivityAt`). Cheap single-column
|
|
307
|
+
* write-through used on every operation that runs work in the sandbox, so the
|
|
308
|
+
* idle reaper sees recent use. No-op for an unknown id.
|
|
309
|
+
*/
|
|
310
|
+
touch(id) {
|
|
311
|
+
const rec = this.byId.get(id);
|
|
312
|
+
if (!rec)
|
|
313
|
+
return;
|
|
314
|
+
rec.lastActivityAt = new Date().toISOString();
|
|
315
|
+
this.db
|
|
316
|
+
.prepare("UPDATE sandboxes SET lastActivityAt = ? WHERE id = ?")
|
|
317
|
+
.run(rec.lastActivityAt, id);
|
|
318
|
+
}
|
|
319
|
+
get(id) {
|
|
320
|
+
return this.byId.get(id);
|
|
321
|
+
}
|
|
322
|
+
remove(id) {
|
|
323
|
+
this.db.prepare("DELETE FROM sandboxes WHERE id = ?").run(id);
|
|
324
|
+
return this.byId.delete(id);
|
|
325
|
+
}
|
|
326
|
+
list() {
|
|
327
|
+
return [...this.byId.values()].sort((a, b) => a.createdAt < b.createdAt ? 1 : -1);
|
|
328
|
+
}
|
|
329
|
+
// --- processes -----------------------------------------------------------
|
|
330
|
+
/** Insert or update a background-process record (write-through). */
|
|
331
|
+
addProcess(sandboxId, proc) {
|
|
332
|
+
mapIn(this.procs, sandboxId).set(proc.procId, proc);
|
|
333
|
+
this.db
|
|
334
|
+
.prepare(`INSERT INTO processes (sandboxId, procId, pid, command, status, exitCode, startedAt, logPath)
|
|
335
|
+
VALUES ($sandboxId, $procId, $pid, $command, $status, $exitCode, $startedAt, $logPath)
|
|
336
|
+
ON CONFLICT(sandboxId, procId) DO UPDATE SET
|
|
337
|
+
pid=$pid, command=$command, status=$status, exitCode=$exitCode,
|
|
338
|
+
startedAt=$startedAt, logPath=$logPath`)
|
|
339
|
+
.run({
|
|
340
|
+
sandboxId,
|
|
341
|
+
procId: proc.procId,
|
|
342
|
+
pid: proc.pid,
|
|
343
|
+
command: proc.command,
|
|
344
|
+
status: proc.status,
|
|
345
|
+
exitCode: proc.exitCode,
|
|
346
|
+
startedAt: proc.startedAt,
|
|
347
|
+
logPath: proc.logPath,
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
getProcess(sandboxId, procId) {
|
|
351
|
+
return this.procs.get(sandboxId)?.get(procId);
|
|
352
|
+
}
|
|
353
|
+
listProcesses(sandboxId) {
|
|
354
|
+
return [...(this.procs.get(sandboxId)?.values() ?? [])].sort((a, b) => a.startedAt < b.startedAt ? 1 : -1);
|
|
355
|
+
}
|
|
356
|
+
// --- exposed ports -------------------------------------------------------
|
|
357
|
+
addExposed(sandboxId, exposed) {
|
|
358
|
+
mapIn(this.exposed, sandboxId).set(exposed.port, exposed);
|
|
359
|
+
this.routes.set(exposed.exposeId, {
|
|
360
|
+
sandboxId,
|
|
361
|
+
port: exposed.port,
|
|
362
|
+
token: exposed.token,
|
|
363
|
+
});
|
|
364
|
+
this.db
|
|
365
|
+
.prepare(`INSERT INTO exposed_ports (sandboxId, port, exposeId, token, createdAt, url)
|
|
366
|
+
VALUES ($sandboxId, $port, $exposeId, $token, $createdAt, $url)
|
|
367
|
+
ON CONFLICT(sandboxId, port) DO UPDATE SET
|
|
368
|
+
exposeId=$exposeId, token=$token, createdAt=$createdAt, url=$url`)
|
|
369
|
+
.run({
|
|
370
|
+
sandboxId,
|
|
371
|
+
port: exposed.port,
|
|
372
|
+
exposeId: exposed.exposeId,
|
|
373
|
+
token: exposed.token,
|
|
374
|
+
createdAt: exposed.createdAt,
|
|
375
|
+
url: exposed.url,
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
removeExposed(sandboxId, port) {
|
|
379
|
+
const map = this.exposed.get(sandboxId);
|
|
380
|
+
const exposed = map?.get(port);
|
|
381
|
+
if (!map || !exposed)
|
|
382
|
+
return false;
|
|
383
|
+
map.delete(port);
|
|
384
|
+
this.routes.delete(exposed.exposeId);
|
|
385
|
+
this.db
|
|
386
|
+
.prepare("DELETE FROM exposed_ports WHERE sandboxId = ? AND port = ?")
|
|
387
|
+
.run(sandboxId, port);
|
|
388
|
+
return true;
|
|
389
|
+
}
|
|
390
|
+
listExposed(sandboxId) {
|
|
391
|
+
return [...(this.exposed.get(sandboxId)?.values() ?? [])].sort((a, b) => a.port - b.port);
|
|
392
|
+
}
|
|
393
|
+
/** Resolve a preview route label (`<sandboxId>-<port>`) to its target. */
|
|
394
|
+
resolveRoute(exposeId) {
|
|
395
|
+
return this.routes.get(exposeId);
|
|
396
|
+
}
|
|
397
|
+
// --- sessions ------------------------------------------------------------
|
|
398
|
+
/** Insert or update a session record (write-through; also use to persist
|
|
399
|
+
* in-place edits to cwd/env on a session returned by `getSession`). */
|
|
400
|
+
addSession(sandboxId, session) {
|
|
401
|
+
mapIn(this.sessions, sandboxId).set(session.sessionId, session);
|
|
402
|
+
this.db
|
|
403
|
+
.prepare(`INSERT INTO sessions (sandboxId, sessionId, cwd, env, createdAt)
|
|
404
|
+
VALUES ($sandboxId, $sessionId, $cwd, $env, $createdAt)
|
|
405
|
+
ON CONFLICT(sandboxId, sessionId) DO UPDATE SET
|
|
406
|
+
cwd=$cwd, env=$env, createdAt=$createdAt`)
|
|
407
|
+
.run({
|
|
408
|
+
sandboxId,
|
|
409
|
+
sessionId: session.sessionId,
|
|
410
|
+
cwd: session.cwd,
|
|
411
|
+
env: JSON.stringify(session.env),
|
|
412
|
+
createdAt: session.createdAt,
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
getSession(sandboxId, sessionId) {
|
|
416
|
+
return this.sessions.get(sandboxId)?.get(sessionId);
|
|
417
|
+
}
|
|
418
|
+
listSessions(sandboxId) {
|
|
419
|
+
return [...(this.sessions.get(sandboxId)?.values() ?? [])].sort((a, b) => a.createdAt < b.createdAt ? 1 : -1);
|
|
420
|
+
}
|
|
421
|
+
removeSession(sandboxId, sessionId) {
|
|
422
|
+
this.db
|
|
423
|
+
.prepare("DELETE FROM sessions WHERE sandboxId = ? AND sessionId = ?")
|
|
424
|
+
.run(sandboxId, sessionId);
|
|
425
|
+
return this.sessions.get(sandboxId)?.delete(sessionId) ?? false;
|
|
426
|
+
}
|
|
427
|
+
// --- code contexts -------------------------------------------------------
|
|
428
|
+
/** Insert or update a code-interpreter context record (write-through; also
|
|
429
|
+
* use to persist the bumped `seq` after running a cell). */
|
|
430
|
+
addContext(sandboxId, ctx) {
|
|
431
|
+
mapIn(this.contexts, sandboxId).set(ctx.contextId, ctx);
|
|
432
|
+
this.db
|
|
433
|
+
.prepare(`INSERT INTO code_contexts (sandboxId, contextId, language, dir, procId, pid, seq, createdAt)
|
|
434
|
+
VALUES ($sandboxId, $contextId, $language, $dir, $procId, $pid, $seq, $createdAt)
|
|
435
|
+
ON CONFLICT(sandboxId, contextId) DO UPDATE SET
|
|
436
|
+
language=$language, dir=$dir, procId=$procId, pid=$pid,
|
|
437
|
+
seq=$seq, createdAt=$createdAt`)
|
|
438
|
+
.run({
|
|
439
|
+
sandboxId,
|
|
440
|
+
contextId: ctx.contextId,
|
|
441
|
+
language: ctx.language,
|
|
442
|
+
dir: ctx.dir,
|
|
443
|
+
procId: ctx.procId,
|
|
444
|
+
pid: ctx.pid,
|
|
445
|
+
seq: ctx.seq,
|
|
446
|
+
createdAt: ctx.createdAt,
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
getContext(sandboxId, contextId) {
|
|
450
|
+
return this.contexts.get(sandboxId)?.get(contextId);
|
|
451
|
+
}
|
|
452
|
+
listContexts(sandboxId) {
|
|
453
|
+
return [...(this.contexts.get(sandboxId)?.values() ?? [])].sort((a, b) => a.createdAt < b.createdAt ? 1 : -1);
|
|
454
|
+
}
|
|
455
|
+
removeContext(sandboxId, contextId) {
|
|
456
|
+
this.db
|
|
457
|
+
.prepare("DELETE FROM code_contexts WHERE sandboxId = ? AND contextId = ?")
|
|
458
|
+
.run(sandboxId, contextId);
|
|
459
|
+
return this.contexts.get(sandboxId)?.delete(contextId) ?? false;
|
|
460
|
+
}
|
|
461
|
+
/** Drop all process + exposed-port + session + context + egress-token state for a destroyed sandbox. */
|
|
462
|
+
clearSandbox(sandboxId) {
|
|
463
|
+
this.clearRuntimeState(sandboxId);
|
|
464
|
+
this.sessions.delete(sandboxId);
|
|
465
|
+
this.db.prepare("DELETE FROM sessions WHERE sandboxId = ?").run(sandboxId);
|
|
466
|
+
for (const rec of this.listEgressTokens(sandboxId))
|
|
467
|
+
this.egressTokens.delete(rec.token);
|
|
468
|
+
this.db.prepare("DELETE FROM egress_tokens WHERE sandboxId = ?").run(sandboxId);
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Drop the state tied to a live container — background processes, exposed
|
|
472
|
+
* ports, and code-interpreter contexts (their kernels die with the
|
|
473
|
+
* container) — when a sandbox is stopped. Sessions (just cwd/env strings) and
|
|
474
|
+
* the sandbox record are kept so `start` resumes with them intact.
|
|
475
|
+
*/
|
|
476
|
+
clearRuntimeState(sandboxId) {
|
|
477
|
+
this.procs.delete(sandboxId);
|
|
478
|
+
this.contexts.delete(sandboxId);
|
|
479
|
+
const ports = this.exposed.get(sandboxId);
|
|
480
|
+
if (ports) {
|
|
481
|
+
for (const exposed of ports.values())
|
|
482
|
+
this.routes.delete(exposed.exposeId);
|
|
483
|
+
this.exposed.delete(sandboxId);
|
|
484
|
+
}
|
|
485
|
+
this.db.prepare("DELETE FROM processes WHERE sandboxId = ?").run(sandboxId);
|
|
486
|
+
this.db.prepare("DELETE FROM code_contexts WHERE sandboxId = ?").run(sandboxId);
|
|
487
|
+
this.db.prepare("DELETE FROM exposed_ports WHERE sandboxId = ?").run(sandboxId);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
/** Get-or-create the inner per-sandbox map for a two-level cache. */
|
|
491
|
+
function mapIn(outer, key) {
|
|
492
|
+
let inner = outer.get(key);
|
|
493
|
+
if (!inner) {
|
|
494
|
+
inner = new Map();
|
|
495
|
+
outer.set(key, inner);
|
|
496
|
+
}
|
|
497
|
+
return inner;
|
|
498
|
+
}
|
|
499
|
+
function rowToSandbox(row) {
|
|
500
|
+
return {
|
|
501
|
+
id: row.id,
|
|
502
|
+
image: row.image,
|
|
503
|
+
status: row.status,
|
|
504
|
+
createdAt: row.createdAt,
|
|
505
|
+
driver: row.driver || undefined,
|
|
506
|
+
labels: JSON.parse(row.labels),
|
|
507
|
+
env: JSON.parse(row.env),
|
|
508
|
+
persist: row.persist === 1,
|
|
509
|
+
lastActivityAt: row.lastActivityAt || row.createdAt,
|
|
510
|
+
sleepAfterMs: row.sleepAfterMs ?? 0,
|
|
511
|
+
limits: parseJsonObject(row.limits),
|
|
512
|
+
egressSpendCapUsd: typeof row.egressSpendCap === "number" ? row.egressSpendCap : 0,
|
|
513
|
+
usage: { ...emptyUsage(), ...parseUsage(row.usage) },
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
function parseUsage(raw) {
|
|
517
|
+
return parseJsonObject(raw);
|
|
518
|
+
}
|
|
519
|
+
/** Parse a JSON-object column, tolerating null/empty/malformed values. */
|
|
520
|
+
function parseJsonObject(raw) {
|
|
521
|
+
if (typeof raw !== "string" || !raw)
|
|
522
|
+
return {};
|
|
523
|
+
try {
|
|
524
|
+
return JSON.parse(raw);
|
|
525
|
+
}
|
|
526
|
+
catch {
|
|
527
|
+
return {};
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
function rowToEgressToken(row) {
|
|
531
|
+
return {
|
|
532
|
+
token: row.token,
|
|
533
|
+
sandboxId: row.sandboxId,
|
|
534
|
+
policy: parseJsonObject(row.policy),
|
|
535
|
+
createdAt: row.createdAt,
|
|
536
|
+
spendUsd: typeof row.spendUsd === "number" ? row.spendUsd : 0,
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
function rowToProcess(row) {
|
|
540
|
+
return {
|
|
541
|
+
procId: row.procId,
|
|
542
|
+
pid: row.pid,
|
|
543
|
+
command: row.command,
|
|
544
|
+
status: row.status,
|
|
545
|
+
exitCode: row.exitCode,
|
|
546
|
+
startedAt: row.startedAt,
|
|
547
|
+
logPath: row.logPath,
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
function rowToExposed(row) {
|
|
551
|
+
return {
|
|
552
|
+
port: row.port,
|
|
553
|
+
exposeId: row.exposeId,
|
|
554
|
+
token: row.token,
|
|
555
|
+
createdAt: row.createdAt,
|
|
556
|
+
url: row.url,
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
function rowToSession(row) {
|
|
560
|
+
return {
|
|
561
|
+
sessionId: row.sessionId,
|
|
562
|
+
cwd: row.cwd,
|
|
563
|
+
env: JSON.parse(row.env),
|
|
564
|
+
createdAt: row.createdAt,
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
function rowToContext(row) {
|
|
568
|
+
return {
|
|
569
|
+
contextId: row.contextId,
|
|
570
|
+
language: row.language,
|
|
571
|
+
dir: row.dir,
|
|
572
|
+
procId: row.procId,
|
|
573
|
+
pid: row.pid,
|
|
574
|
+
seq: row.seq,
|
|
575
|
+
createdAt: row.createdAt,
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal, dependency-free distributed tracing — the Phase 2 "OpenTelemetry
|
|
3
|
+
* traces (create→exec→destroy)" deliverable without pulling in the (large)
|
|
4
|
+
* `@opentelemetry/*` tree.
|
|
5
|
+
*
|
|
6
|
+
* Every finished span is kept in an in-memory ring (served at `GET /traces`) and,
|
|
7
|
+
* when an OTLP/HTTP endpoint is configured, batch-exported as OTLP-JSON to
|
|
8
|
+
* `<endpoint>/v1/traces` so it lands in Jaeger/Tempo/Honeycomb/etc. The wire
|
|
9
|
+
* shape follows the OTLP spec (resourceSpans → scopeSpans → spans) closely
|
|
10
|
+
* enough for standard collectors to ingest.
|
|
11
|
+
*/
|
|
12
|
+
export type SpanStatus = "unset" | "ok" | "error";
|
|
13
|
+
export interface SpanData {
|
|
14
|
+
traceId: string;
|
|
15
|
+
spanId: string;
|
|
16
|
+
parentId?: string;
|
|
17
|
+
name: string;
|
|
18
|
+
/** Wall-clock start, unix nanoseconds (string to survive JSON without precision loss). */
|
|
19
|
+
startUnixNano: string;
|
|
20
|
+
endUnixNano: string;
|
|
21
|
+
durationMs: number;
|
|
22
|
+
attributes: Record<string, string | number | boolean>;
|
|
23
|
+
status: SpanStatus;
|
|
24
|
+
}
|
|
25
|
+
export interface Span {
|
|
26
|
+
readonly traceId: string;
|
|
27
|
+
readonly spanId: string;
|
|
28
|
+
setAttribute(key: string, value: string | number | boolean): this;
|
|
29
|
+
setStatus(status: SpanStatus): this;
|
|
30
|
+
/** Finish the span: record duration, push to the ring, queue for export. */
|
|
31
|
+
end(): void;
|
|
32
|
+
}
|
|
33
|
+
interface TracerConfig {
|
|
34
|
+
serviceName: string;
|
|
35
|
+
otlpEndpoint: string;
|
|
36
|
+
ringSize: number;
|
|
37
|
+
}
|
|
38
|
+
export declare function configureTracing(opts: Partial<TracerConfig>): void;
|
|
39
|
+
/** Stop the background OTLP flusher (call on daemon shutdown). */
|
|
40
|
+
export declare function stopTracing(): void;
|
|
41
|
+
/** Recent finished spans, newest first. */
|
|
42
|
+
export declare function recentSpans(): SpanData[];
|
|
43
|
+
/** Begin a span. Pass `parent` to nest it within an existing trace. */
|
|
44
|
+
export declare function startSpan(name: string, attributes?: Record<string, string | number | boolean>, parent?: Span): Span;
|
|
45
|
+
export {};
|