nexus-ai-pro 2.0.0 → 2.2.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/API_STABILITY.md +65 -0
- package/CHANGELOG.md +267 -1
- package/MIGRATING.md +1 -1
- package/README.md +17 -8
- package/dist/agent/create-agent.d.ts +9 -1
- package/dist/agent/create-agent.js +40 -1
- package/dist/cache/memory-cache.d.ts +8 -0
- package/dist/cache/memory-cache.js +9 -0
- package/dist/cache/semantic-cache.d.ts +6 -3
- package/dist/cache/semantic-cache.js +5 -2
- package/dist/cli/args.js +3 -0
- package/dist/cli/db.d.ts +16 -4
- package/dist/cli/db.js +169 -22
- package/dist/cli/doctor.d.ts +17 -0
- package/dist/cli/doctor.js +53 -0
- package/dist/cli/graph.d.ts +9 -0
- package/dist/cli/graph.js +47 -0
- package/dist/cli.js +21 -2
- package/dist/core/lifecycle.js +11 -6
- package/dist/core/nexus.d.ts +12 -2
- package/dist/core/nexus.js +106 -23
- package/dist/doctor/index.d.ts +90 -0
- package/dist/doctor/index.js +237 -0
- package/dist/evals/judge.d.ts +11 -0
- package/dist/evals/judge.js +33 -0
- package/dist/evaluate/index.d.ts +1 -0
- package/dist/evaluate/index.js +1 -0
- package/dist/evaluate/provenance.d.ts +22 -0
- package/dist/evaluate/provenance.js +10 -0
- package/dist/evaluate/run.js +20 -4
- package/dist/graph/durability.d.ts +27 -0
- package/dist/graph/durability.js +66 -0
- package/dist/graph/errors.d.ts +30 -4
- package/dist/graph/errors.js +18 -2
- package/dist/graph/event-stream.d.ts +75 -0
- package/dist/graph/event-stream.js +289 -0
- package/dist/graph/functional.d.ts +80 -7
- package/dist/graph/functional.js +138 -35
- package/dist/graph/graph.d.ts +56 -8
- package/dist/graph/graph.js +331 -49
- package/dist/graph/index.d.ts +4 -2
- package/dist/graph/index.js +3 -1
- package/dist/graph/lint.d.ts +57 -0
- package/dist/graph/lint.js +141 -0
- package/dist/graph/run-control.d.ts +28 -0
- package/dist/graph/run-control.js +26 -0
- package/dist/images/evals.js +4 -2
- package/dist/operations/adapters.d.ts +52 -4
- package/dist/operations/adapters.js +194 -7
- package/dist/operations/runner.js +14 -15
- package/dist/operations/stats.js +8 -1
- package/dist/operations/store.d.ts +5 -1
- package/dist/operations/store.js +7 -0
- package/dist/ops/circuit-breaker.d.ts +52 -0
- package/dist/ops/circuit-breaker.js +4 -0
- package/dist/ops/circuit-store.d.ts +13 -2
- package/dist/ops/circuit-store.js +68 -0
- package/dist/ops/circuit-sync.d.ts +17 -0
- package/dist/ops/circuit-sync.js +86 -0
- package/dist/ops/health.d.ts +24 -0
- package/dist/ops/health.js +38 -10
- package/dist/ops/index.d.ts +1 -1
- package/dist/ops/index.js +1 -1
- package/dist/ops/rate-limit-adapters.d.ts +23 -0
- package/dist/ops/rate-limit-adapters.js +34 -0
- package/dist/ops/rate-limiter.d.ts +14 -2
- package/dist/ops/rate-limiter.js +31 -0
- package/dist/postgres/circuits.d.ts +21 -4
- package/dist/postgres/circuits.js +65 -4
- package/dist/postgres/client.d.ts +0 -2
- package/dist/postgres/client.js +0 -4
- package/dist/postgres/evaluate.d.ts +16 -4
- package/dist/postgres/evaluate.js +17 -5
- package/dist/postgres/index.d.ts +32 -11
- package/dist/postgres/index.js +65 -31
- package/dist/postgres/migrations.d.ts +60 -0
- package/dist/postgres/migrations.js +121 -0
- package/dist/postgres/operations.d.ts +14 -3
- package/dist/postgres/operations.js +45 -15
- package/dist/postgres/prompts.d.ts +11 -2
- package/dist/postgres/prompts.js +14 -3
- package/dist/postgres/rollups.d.ts +35 -0
- package/dist/postgres/rollups.js +129 -0
- package/dist/postgres/store.d.ts +11 -2
- package/dist/postgres/store.js +14 -3
- package/dist/postgres/traces.d.ts +13 -3
- package/dist/postgres/traces.js +25 -3
- package/dist/postgres/vectors.d.ts +11 -2
- package/dist/postgres/vectors.js +14 -3
- package/dist/router/auto-router.d.ts +34 -7
- package/dist/router/auto-router.js +201 -68
- package/dist/server/assistant.d.ts +44 -0
- package/dist/server/assistant.js +39 -0
- package/dist/server/errors.d.ts +12 -0
- package/dist/server/errors.js +7 -0
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/runs.d.ts +28 -1
- package/dist/server/runs.js +110 -14
- package/dist/sqlite/index.d.ts +16 -3
- package/dist/sqlite/index.js +16 -3
- package/dist/sqlite/migrations.d.ts +26 -0
- package/dist/sqlite/migrations.js +63 -0
- package/dist/sqlite/operations.d.ts +14 -3
- package/dist/sqlite/operations.js +42 -15
- package/dist/sqlite/store.d.ts +9 -2
- package/dist/sqlite/store.js +13 -3
- package/dist/sqlite/vectors.d.ts +11 -2
- package/dist/sqlite/vectors.js +13 -2
- package/dist/store/tenant.d.ts +12 -0
- package/dist/store/tenant.js +29 -0
- package/dist/tenancy/index.d.ts +113 -0
- package/dist/tenancy/index.js +233 -0
- package/dist/testing/record.d.ts +42 -0
- package/dist/testing/record.js +57 -5
- package/dist/tracing/index.d.ts +3 -3
- package/dist/tracing/index.js +2 -2
- package/dist/tracing/instrument.js +30 -0
- package/dist/tracing/otlp.d.ts +91 -0
- package/dist/tracing/otlp.js +124 -0
- package/dist/tracing/rollups.d.ts +100 -0
- package/dist/tracing/rollups.js +139 -0
- package/dist/tracing/stores.d.ts +17 -0
- package/dist/tracing/stores.js +23 -0
- package/dist/tracing/tracer.d.ts +50 -4
- package/dist/tracing/tracer.js +85 -6
- package/dist/types/config.d.ts +33 -2
- package/dist/types/evaluate.d.ts +37 -0
- package/dist/types/graph.d.ts +354 -9
- package/dist/types/graph.js +3 -1
- package/dist/types/messages.d.ts +5 -0
- package/dist/types/operations.d.ts +22 -2
- package/dist/types/response.d.ts +20 -0
- package/dist/types/server.d.ts +18 -0
- package/dist/types/tracing.d.ts +11 -0
- package/dist/utils/schema-migrations.d.ts +97 -0
- package/dist/utils/schema-migrations.js +91 -0
- package/dist/utils/signals.d.ts +17 -0
- package/dist/utils/signals.js +26 -0
- package/dist/utils/tenant.d.ts +14 -0
- package/dist/utils/tenant.js +16 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.js +1 -0
- package/dist-cjs/agent/create-agent.d.ts +9 -1
- package/dist-cjs/agent/create-agent.js +40 -1
- package/dist-cjs/cache/memory-cache.d.ts +8 -0
- package/dist-cjs/cache/memory-cache.js +9 -0
- package/dist-cjs/cache/semantic-cache.d.ts +6 -3
- package/dist-cjs/cache/semantic-cache.js +5 -2
- package/dist-cjs/cli/args.js +3 -0
- package/dist-cjs/cli/db.d.ts +16 -4
- package/dist-cjs/cli/db.js +200 -20
- package/dist-cjs/cli/doctor.d.ts +17 -0
- package/dist-cjs/cli/doctor.js +56 -0
- package/dist-cjs/cli/graph.d.ts +9 -0
- package/dist-cjs/cli/graph.js +50 -0
- package/dist-cjs/core/lifecycle.js +11 -6
- package/dist-cjs/core/nexus.d.ts +12 -2
- package/dist-cjs/core/nexus.js +106 -23
- package/dist-cjs/doctor/index.d.ts +90 -0
- package/dist-cjs/doctor/index.js +276 -0
- package/dist-cjs/evals/judge.d.ts +11 -0
- package/dist-cjs/evals/judge.js +33 -0
- package/dist-cjs/evaluate/index.d.ts +1 -0
- package/dist-cjs/evaluate/index.js +3 -1
- package/dist-cjs/evaluate/provenance.d.ts +22 -0
- package/dist-cjs/evaluate/provenance.js +14 -0
- package/dist-cjs/evaluate/run.js +20 -4
- package/dist-cjs/graph/durability.d.ts +27 -0
- package/dist-cjs/graph/durability.js +70 -0
- package/dist-cjs/graph/errors.d.ts +30 -4
- package/dist-cjs/graph/errors.js +20 -3
- package/dist-cjs/graph/event-stream.d.ts +75 -0
- package/dist-cjs/graph/event-stream.js +295 -0
- package/dist-cjs/graph/functional.d.ts +80 -7
- package/dist-cjs/graph/functional.js +137 -34
- package/dist-cjs/graph/graph.d.ts +56 -8
- package/dist-cjs/graph/graph.js +330 -48
- package/dist-cjs/graph/index.d.ts +4 -2
- package/dist-cjs/graph/index.js +7 -1
- package/dist-cjs/graph/lint.d.ts +57 -0
- package/dist-cjs/graph/lint.js +144 -0
- package/dist-cjs/graph/run-control.d.ts +28 -0
- package/dist-cjs/graph/run-control.js +30 -0
- package/dist-cjs/images/evals.js +4 -2
- package/dist-cjs/operations/adapters.d.ts +52 -4
- package/dist-cjs/operations/adapters.js +193 -6
- package/dist-cjs/operations/runner.js +14 -15
- package/dist-cjs/operations/stats.js +8 -1
- package/dist-cjs/operations/store.d.ts +5 -1
- package/dist-cjs/operations/store.js +7 -0
- package/dist-cjs/ops/circuit-breaker.d.ts +52 -0
- package/dist-cjs/ops/circuit-breaker.js +4 -0
- package/dist-cjs/ops/circuit-store.d.ts +13 -2
- package/dist-cjs/ops/circuit-store.js +68 -0
- package/dist-cjs/ops/circuit-sync.d.ts +17 -0
- package/dist-cjs/ops/circuit-sync.js +87 -0
- package/dist-cjs/ops/health.d.ts +24 -0
- package/dist-cjs/ops/health.js +38 -10
- package/dist-cjs/ops/index.d.ts +1 -1
- package/dist-cjs/ops/rate-limit-adapters.d.ts +23 -0
- package/dist-cjs/ops/rate-limit-adapters.js +35 -1
- package/dist-cjs/ops/rate-limiter.d.ts +14 -2
- package/dist-cjs/ops/rate-limiter.js +32 -0
- package/dist-cjs/postgres/circuits.d.ts +21 -4
- package/dist-cjs/postgres/circuits.js +98 -3
- package/dist-cjs/postgres/client.d.ts +0 -2
- package/dist-cjs/postgres/client.js +0 -5
- package/dist-cjs/postgres/evaluate.d.ts +16 -4
- package/dist-cjs/postgres/evaluate.js +50 -4
- package/dist-cjs/postgres/index.d.ts +32 -11
- package/dist-cjs/postgres/index.js +69 -20
- package/dist-cjs/postgres/migrations.d.ts +60 -0
- package/dist-cjs/postgres/migrations.js +129 -0
- package/dist-cjs/postgres/operations.d.ts +14 -3
- package/dist-cjs/postgres/operations.js +78 -14
- package/dist-cjs/postgres/prompts.d.ts +11 -2
- package/dist-cjs/postgres/prompts.js +47 -2
- package/dist-cjs/postgres/rollups.d.ts +35 -0
- package/dist-cjs/postgres/rollups.js +168 -0
- package/dist-cjs/postgres/store.d.ts +11 -2
- package/dist-cjs/postgres/store.js +47 -2
- package/dist-cjs/postgres/traces.d.ts +13 -3
- package/dist-cjs/postgres/traces.js +58 -2
- package/dist-cjs/postgres/vectors.d.ts +11 -2
- package/dist-cjs/postgres/vectors.js +47 -2
- package/dist-cjs/router/auto-router.d.ts +34 -7
- package/dist-cjs/router/auto-router.js +201 -68
- package/dist-cjs/server/assistant.d.ts +44 -0
- package/dist-cjs/server/assistant.js +39 -0
- package/dist-cjs/server/errors.d.ts +12 -0
- package/dist-cjs/server/errors.js +9 -1
- package/dist-cjs/server/index.d.ts +1 -1
- package/dist-cjs/server/index.js +2 -1
- package/dist-cjs/server/runs.d.ts +28 -1
- package/dist-cjs/server/runs.js +109 -13
- package/dist-cjs/sqlite/index.d.ts +16 -3
- package/dist-cjs/sqlite/index.js +31 -10
- package/dist-cjs/sqlite/migrations.d.ts +26 -0
- package/dist-cjs/sqlite/migrations.js +71 -0
- package/dist-cjs/sqlite/operations.d.ts +14 -3
- package/dist-cjs/sqlite/operations.js +76 -15
- package/dist-cjs/sqlite/store.d.ts +9 -2
- package/dist-cjs/sqlite/store.js +47 -3
- package/dist-cjs/sqlite/vectors.d.ts +11 -2
- package/dist-cjs/sqlite/vectors.js +47 -2
- package/dist-cjs/store/tenant.d.ts +12 -0
- package/dist-cjs/store/tenant.js +33 -0
- package/dist-cjs/tenancy/index.d.ts +113 -0
- package/dist-cjs/tenancy/index.js +250 -0
- package/dist-cjs/testing/record.d.ts +42 -0
- package/dist-cjs/testing/record.js +57 -5
- package/dist-cjs/tracing/index.d.ts +3 -3
- package/dist-cjs/tracing/index.js +4 -1
- package/dist-cjs/tracing/instrument.js +30 -0
- package/dist-cjs/tracing/otlp.d.ts +91 -0
- package/dist-cjs/tracing/otlp.js +129 -0
- package/dist-cjs/tracing/rollups.d.ts +100 -0
- package/dist-cjs/tracing/rollups.js +147 -0
- package/dist-cjs/tracing/stores.d.ts +17 -0
- package/dist-cjs/tracing/stores.js +24 -0
- package/dist-cjs/tracing/tracer.d.ts +50 -4
- package/dist-cjs/tracing/tracer.js +87 -6
- package/dist-cjs/types/config.d.ts +33 -2
- package/dist-cjs/types/evaluate.d.ts +37 -0
- package/dist-cjs/types/graph.d.ts +354 -9
- package/dist-cjs/types/graph.js +3 -1
- package/dist-cjs/types/messages.d.ts +5 -0
- package/dist-cjs/types/operations.d.ts +22 -2
- package/dist-cjs/types/response.d.ts +20 -0
- package/dist-cjs/types/server.d.ts +18 -0
- package/dist-cjs/types/tracing.d.ts +11 -0
- package/dist-cjs/utils/schema-migrations.d.ts +97 -0
- package/dist-cjs/utils/schema-migrations.js +102 -0
- package/dist-cjs/utils/signals.d.ts +17 -0
- package/dist-cjs/utils/signals.js +29 -0
- package/dist-cjs/utils/tenant.d.ts +14 -0
- package/dist-cjs/utils/tenant.js +22 -0
- package/dist-cjs/version.d.ts +5 -0
- package/dist-cjs/version.js +4 -0
- package/llms.txt +4 -3
- package/package.json +110 -2
package/dist-cjs/server/runs.js
CHANGED
|
@@ -12,6 +12,8 @@ const state_js_1 = require("./state.js");
|
|
|
12
12
|
const THREADS = ['nexus', 'server', 'threads'];
|
|
13
13
|
const RUNS = state_js_1.RUNS_NAMESPACE;
|
|
14
14
|
const KIND_PREFIX = 'assistant:';
|
|
15
|
+
const THREAD_CLAIM = 'nexus-thread:';
|
|
16
|
+
const UNRECORDED_CLAIM_MS = 60_000;
|
|
15
17
|
const DEFAULT_CONCURRENCY = 10;
|
|
16
18
|
const DEFAULT_POLL_MS = 1_000;
|
|
17
19
|
const DEFAULT_RECOVER_MS = 30_000;
|
|
@@ -29,6 +31,8 @@ class RunManager {
|
|
|
29
31
|
store;
|
|
30
32
|
local = new Map();
|
|
31
33
|
slots = new Set();
|
|
34
|
+
controls = new Map();
|
|
35
|
+
drainedRuns = new Set();
|
|
32
36
|
state;
|
|
33
37
|
events;
|
|
34
38
|
now;
|
|
@@ -121,12 +125,22 @@ class RunManager {
|
|
|
121
125
|
}
|
|
122
126
|
async start(options) {
|
|
123
127
|
const base = this.assistant(options.assistant);
|
|
128
|
+
const runId = `run-${randomId()}`;
|
|
124
129
|
let thread;
|
|
125
130
|
if (options.threadId) {
|
|
126
131
|
thread = await this.thread(options.threadId, options.principal);
|
|
127
|
-
thread = await this.settleBusyThread(thread, options);
|
|
132
|
+
thread = await this.settleBusyThread(thread, options, runId);
|
|
128
133
|
}
|
|
129
|
-
|
|
134
|
+
try {
|
|
135
|
+
return await this.startClaimed(runId, base, thread, options);
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
if (thread)
|
|
139
|
+
await this.releaseClaim(thread.id, runId).catch((cause) => this.report(cause, { runId }));
|
|
140
|
+
throw error;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async startClaimed(runId, base, thread, options) {
|
|
130
144
|
let assistant = base;
|
|
131
145
|
let revision;
|
|
132
146
|
if (base.route) {
|
|
@@ -220,11 +234,18 @@ class RunManager {
|
|
|
220
234
|
async drain(options = {}) {
|
|
221
235
|
this.draining = true;
|
|
222
236
|
this.stopWorking();
|
|
237
|
+
if (this.options.queue) {
|
|
238
|
+
for (const control of this.controls.values()) {
|
|
239
|
+
control.draining = true;
|
|
240
|
+
control.reason = 'replica draining';
|
|
241
|
+
}
|
|
242
|
+
}
|
|
223
243
|
const running = [...this.slots];
|
|
224
244
|
const deadline = Date.now() + (options.timeoutMs ?? 25_000);
|
|
225
245
|
while (this.slots.size > 0 && Date.now() < deadline)
|
|
226
246
|
await pause(Math.min(50, deadline - Date.now()));
|
|
227
|
-
const released = [];
|
|
247
|
+
const released = [...this.drainedRuns];
|
|
248
|
+
this.drainedRuns.clear();
|
|
228
249
|
if (this.options.queue) {
|
|
229
250
|
for (const id of [...this.slots]) {
|
|
230
251
|
if (this.runner.release(id))
|
|
@@ -344,6 +365,8 @@ class RunManager {
|
|
|
344
365
|
acceptedId = (await this.runner.enqueue(submit)).id;
|
|
345
366
|
}
|
|
346
367
|
if (acceptedId !== runId) {
|
|
368
|
+
if (thread)
|
|
369
|
+
await this.releaseClaim(thread.id, runId);
|
|
347
370
|
await this.state.delete(RUNS, runId);
|
|
348
371
|
await this.releaseTenant(runId, options.principal?.tenantId);
|
|
349
372
|
return (await this.state.get(RUNS, acceptedId)) ?? run;
|
|
@@ -377,14 +400,18 @@ class RunManager {
|
|
|
377
400
|
async execute(plan, context) {
|
|
378
401
|
const runId = context.operationId;
|
|
379
402
|
let cost = 0;
|
|
403
|
+
const control = { draining: false };
|
|
380
404
|
const runContext = {
|
|
381
405
|
runId,
|
|
382
406
|
threadId: plan.threadId,
|
|
383
407
|
signal: context.signal,
|
|
408
|
+
control,
|
|
384
409
|
principal: plan.principal,
|
|
385
410
|
metadata: plan.metadata,
|
|
386
411
|
attempt: context.attempt,
|
|
387
412
|
...(plan.revision ? { revision: plan.revision.id } : {}),
|
|
413
|
+
saveProgress: (details) => context.heartbeat(details),
|
|
414
|
+
...(context.previousHeartbeat === undefined ? {} : { progress: context.previousHeartbeat }),
|
|
388
415
|
recordCost: async (usd) => {
|
|
389
416
|
if (!Number.isFinite(usd) || usd <= 0)
|
|
390
417
|
return;
|
|
@@ -414,6 +441,7 @@ class RunManager {
|
|
|
414
441
|
? plan.assistant.resume(plan.threadId, plan.resume, runContext)
|
|
415
442
|
: plan.assistant.stream(plan.input, runContext));
|
|
416
443
|
let last;
|
|
444
|
+
this.controls.set(runId, control);
|
|
417
445
|
try {
|
|
418
446
|
for await (const event of stream) {
|
|
419
447
|
last = event;
|
|
@@ -422,6 +450,8 @@ class RunManager {
|
|
|
422
450
|
}
|
|
423
451
|
}
|
|
424
452
|
catch (error) {
|
|
453
|
+
if (control.draining && isDrained(error) && this.runner.release(runId))
|
|
454
|
+
this.drainedRuns.add(runId);
|
|
425
455
|
if (context.signal.aborted && context.signal.reason instanceof errors_js_1.OperationReleasedError) {
|
|
426
456
|
await this.record(runId, 'status', { status: 'queued', reason: 'handed to another worker' });
|
|
427
457
|
await this.settle(runId, 'queued', { addCost: cost });
|
|
@@ -442,6 +472,9 @@ class RunManager {
|
|
|
442
472
|
await this.releaseTenant(runId, plan.principal?.tenantId);
|
|
443
473
|
throw error;
|
|
444
474
|
}
|
|
475
|
+
finally {
|
|
476
|
+
this.controls.delete(runId);
|
|
477
|
+
}
|
|
445
478
|
const interrupt = interruptOf(last);
|
|
446
479
|
const status = interrupt ? 'awaiting_input' : 'succeeded';
|
|
447
480
|
const output = outputOf(last);
|
|
@@ -520,21 +553,21 @@ class RunManager {
|
|
|
520
553
|
const pollMs = this.options.queue?.pollMs ?? DEFAULT_POLL_MS;
|
|
521
554
|
this.schedule(claimed > 0 && this.freeSlots() > 0 ? 0 : Math.min(pollMs, this.options.recoverEveryMs ?? pollMs));
|
|
522
555
|
}
|
|
523
|
-
async settleBusyThread(thread, options) {
|
|
556
|
+
async settleBusyThread(thread, options, runId) {
|
|
524
557
|
const policy = options.onBusy ?? this.options.onBusy ?? 'reject';
|
|
525
558
|
let current = thread;
|
|
526
|
-
|
|
527
|
-
|
|
559
|
+
const deadline = this.now().getTime() + (this.options.queueTimeoutMs ?? 30_000);
|
|
560
|
+
for (let attempt = 0; attempt < 4 || (policy === 'enqueue' && this.now().getTime() < deadline); attempt += 1) {
|
|
561
|
+
const activeId = await this.claimThread(current, runId);
|
|
528
562
|
if (!activeId)
|
|
529
563
|
return current;
|
|
530
564
|
const active = await this.state.get(RUNS, activeId);
|
|
531
|
-
if (!active || isFinished(active.status)) {
|
|
532
|
-
current = { ...current, activeRunId: undefined };
|
|
533
|
-
await this.state.put(THREADS, current.id, current);
|
|
534
|
-
return current;
|
|
535
|
-
}
|
|
536
565
|
if (policy === 'reject')
|
|
537
566
|
throw new errors_js_2.ThreadBusyError(current.id, activeId);
|
|
567
|
+
if (!active) {
|
|
568
|
+
await delay(50);
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
538
571
|
if (policy === 'enqueue') {
|
|
539
572
|
await this.waitForRun(activeId);
|
|
540
573
|
current = await this.thread(current.id, options.principal);
|
|
@@ -551,9 +584,67 @@ class RunManager {
|
|
|
551
584
|
}
|
|
552
585
|
current = { ...current, activeRunId: undefined };
|
|
553
586
|
await this.state.put(THREADS, current.id, current);
|
|
554
|
-
return current;
|
|
555
587
|
}
|
|
556
|
-
|
|
588
|
+
throw new errors_js_2.ThreadBusyError(current.id, current.activeRunId ?? 'another run');
|
|
589
|
+
}
|
|
590
|
+
async claimThread(thread, runId) {
|
|
591
|
+
if (!this.store.findByIdempotencyKey) {
|
|
592
|
+
const activeId = thread.activeRunId;
|
|
593
|
+
return activeId && !(await this.runIsFree(activeId, undefined)) ? activeId : undefined;
|
|
594
|
+
}
|
|
595
|
+
const key = `${THREAD_CLAIM}${thread.id}`;
|
|
596
|
+
for (let attempt = 0; attempt < 8; attempt += 1) {
|
|
597
|
+
const claim = await this.store.findByIdempotencyKey(key);
|
|
598
|
+
const at = this.now().toISOString();
|
|
599
|
+
if (!claim) {
|
|
600
|
+
try {
|
|
601
|
+
await this.store.create({
|
|
602
|
+
id: `${key}:${runId}`,
|
|
603
|
+
status: 'succeeded',
|
|
604
|
+
attempt: 1,
|
|
605
|
+
maxAttempts: 1,
|
|
606
|
+
sequence: 0,
|
|
607
|
+
createdAt: at,
|
|
608
|
+
updatedAt: at,
|
|
609
|
+
kind: 'server.thread',
|
|
610
|
+
idempotencyKey: key,
|
|
611
|
+
result: { runId },
|
|
612
|
+
});
|
|
613
|
+
return undefined;
|
|
614
|
+
}
|
|
615
|
+
catch (error) {
|
|
616
|
+
if (error instanceof errors_js_1.OperationDuplicateError)
|
|
617
|
+
continue;
|
|
618
|
+
throw error;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
const holder = claim.result?.runId;
|
|
622
|
+
if (holder === runId)
|
|
623
|
+
return undefined;
|
|
624
|
+
if (holder && !(await this.runIsFree(holder, claim.updatedAt)))
|
|
625
|
+
return holder;
|
|
626
|
+
const taken = await this.store.update({ ...claim, result: { runId }, sequence: claim.sequence + 1, updatedAt: at }, claim.sequence);
|
|
627
|
+
if (taken)
|
|
628
|
+
return undefined;
|
|
629
|
+
}
|
|
630
|
+
const holder = (await this.store.findByIdempotencyKey(key))?.result?.runId;
|
|
631
|
+
return holder ?? 'another run';
|
|
632
|
+
}
|
|
633
|
+
async runIsFree(runId, claimedAt) {
|
|
634
|
+
const run = await this.state.get(RUNS, runId);
|
|
635
|
+
if (run)
|
|
636
|
+
return isFinished(run.status);
|
|
637
|
+
if (claimedAt === undefined)
|
|
638
|
+
return true;
|
|
639
|
+
return this.now().getTime() - Date.parse(claimedAt) > UNRECORDED_CLAIM_MS;
|
|
640
|
+
}
|
|
641
|
+
async releaseClaim(threadId, runId) {
|
|
642
|
+
if (!this.store.findByIdempotencyKey)
|
|
643
|
+
return;
|
|
644
|
+
const claim = await this.store.findByIdempotencyKey(`${THREAD_CLAIM}${threadId}`);
|
|
645
|
+
if (!claim || claim.result?.runId !== runId)
|
|
646
|
+
return;
|
|
647
|
+
await this.store.update({ ...claim, result: {}, sequence: claim.sequence + 1, updatedAt: this.now().toISOString() }, claim.sequence);
|
|
557
648
|
}
|
|
558
649
|
async waitForRun(runId) {
|
|
559
650
|
const deadline = this.now().getTime() + (this.options.queueTimeoutMs ?? 30_000);
|
|
@@ -570,6 +661,7 @@ class RunManager {
|
|
|
570
661
|
async releaseThread(threadId, runId) {
|
|
571
662
|
if (!threadId)
|
|
572
663
|
return;
|
|
664
|
+
await this.releaseClaim(threadId, runId).catch((error) => this.report(error, { runId }));
|
|
573
665
|
const thread = await this.state.get(THREADS, threadId);
|
|
574
666
|
if (!thread || thread.activeRunId !== runId)
|
|
575
667
|
return;
|
|
@@ -664,3 +756,7 @@ function delay(ms) {
|
|
|
664
756
|
timer.unref?.();
|
|
665
757
|
});
|
|
666
758
|
}
|
|
759
|
+
function isDrained(error) {
|
|
760
|
+
const code = typeof error === 'object' && error !== null ? error.code : undefined;
|
|
761
|
+
return code === 'GRAPH_DRAINED' || code === 'RUN_HANDED_OFF';
|
|
762
|
+
}
|
|
@@ -1,4 +1,17 @@
|
|
|
1
|
+
import type { SchemaMigration } from '../utils/schema-migrations.js';
|
|
2
|
+
export { type AppliedMigration, type MigrationResult, type MigrationStatus, migrationChecksum, type SchemaMigration, SchemaMigrationError, } from '../utils/schema-migrations.js';
|
|
1
3
|
export { fromLibsql, fromSqliteDatabase, type LibsqlLikeClient, type SqliteDatabaseLike, type SqliteLikeClient, type SqliteValue, } from './client.js';
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
4
|
+
export { applySqliteMigrations, type SqliteMigrateOptions, sqliteMigrationStatus } from './migrations.js';
|
|
5
|
+
export { SqliteOperationStore, type SqliteOperationStoreOptions, sqliteOperationStoreMigration, sqliteOperationStoreMigrations, } from './operations.js';
|
|
6
|
+
export { SqliteStore, type SqliteStoreOptions, sqliteStoreMigration, sqliteStoreMigrations } from './store.js';
|
|
7
|
+
export { SqliteVectorStore, type SqliteVectorStoreOptions, sqliteVectorStoreMigration, sqliteVectorStoreMigrations, } from './vectors.js';
|
|
8
|
+
/** The SQLite adapters a migration can include. */
|
|
9
|
+
export type SqliteAdapter = 'operations' | 'store' | 'vectors';
|
|
10
|
+
/**
|
|
11
|
+
* The versioned migrations of the chosen adapters on their default tables, for
|
|
12
|
+
* `applySqliteMigrations()`, `sqliteMigrationStatus()`, and `nexus db migrate`. Defaults to every
|
|
13
|
+
* adapter. A store on a custom table migrates through its own `migrate()`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function sqliteMigrations(options?: {
|
|
16
|
+
adapters?: readonly SqliteAdapter[];
|
|
17
|
+
}): SchemaMigration[];
|
package/dist-cjs/sqlite/index.js
CHANGED
|
@@ -1,15 +1,36 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.sqliteVectorStoreMigration = exports.SqliteVectorStore = exports.sqliteStoreMigration = exports.SqliteStore = exports.sqliteOperationStoreMigration = exports.SqliteOperationStore = exports.fromSqliteDatabase = exports.fromLibsql = void 0;
|
|
3
|
+
exports.sqliteVectorStoreMigrations = exports.sqliteVectorStoreMigration = exports.SqliteVectorStore = exports.sqliteStoreMigrations = exports.sqliteStoreMigration = exports.SqliteStore = exports.sqliteOperationStoreMigrations = exports.sqliteOperationStoreMigration = exports.SqliteOperationStore = exports.sqliteMigrationStatus = exports.applySqliteMigrations = exports.fromSqliteDatabase = exports.fromLibsql = exports.SchemaMigrationError = exports.migrationChecksum = void 0;
|
|
4
|
+
exports.sqliteMigrations = sqliteMigrations;
|
|
5
|
+
const operations_js_1 = require("./operations.js");
|
|
6
|
+
const store_js_1 = require("./store.js");
|
|
7
|
+
const vectors_js_1 = require("./vectors.js");
|
|
8
|
+
var schema_migrations_js_1 = require("../utils/schema-migrations.js");
|
|
9
|
+
Object.defineProperty(exports, "migrationChecksum", { enumerable: true, get: function () { return schema_migrations_js_1.migrationChecksum; } });
|
|
10
|
+
Object.defineProperty(exports, "SchemaMigrationError", { enumerable: true, get: function () { return schema_migrations_js_1.SchemaMigrationError; } });
|
|
4
11
|
var client_js_1 = require("./client.js");
|
|
5
12
|
Object.defineProperty(exports, "fromLibsql", { enumerable: true, get: function () { return client_js_1.fromLibsql; } });
|
|
6
13
|
Object.defineProperty(exports, "fromSqliteDatabase", { enumerable: true, get: function () { return client_js_1.fromSqliteDatabase; } });
|
|
7
|
-
var
|
|
8
|
-
Object.defineProperty(exports, "
|
|
9
|
-
Object.defineProperty(exports, "
|
|
10
|
-
var
|
|
11
|
-
Object.defineProperty(exports, "
|
|
12
|
-
Object.defineProperty(exports, "
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
Object.defineProperty(exports, "
|
|
14
|
+
var migrations_js_1 = require("./migrations.js");
|
|
15
|
+
Object.defineProperty(exports, "applySqliteMigrations", { enumerable: true, get: function () { return migrations_js_1.applySqliteMigrations; } });
|
|
16
|
+
Object.defineProperty(exports, "sqliteMigrationStatus", { enumerable: true, get: function () { return migrations_js_1.sqliteMigrationStatus; } });
|
|
17
|
+
var operations_js_2 = require("./operations.js");
|
|
18
|
+
Object.defineProperty(exports, "SqliteOperationStore", { enumerable: true, get: function () { return operations_js_2.SqliteOperationStore; } });
|
|
19
|
+
Object.defineProperty(exports, "sqliteOperationStoreMigration", { enumerable: true, get: function () { return operations_js_2.sqliteOperationStoreMigration; } });
|
|
20
|
+
Object.defineProperty(exports, "sqliteOperationStoreMigrations", { enumerable: true, get: function () { return operations_js_2.sqliteOperationStoreMigrations; } });
|
|
21
|
+
var store_js_2 = require("./store.js");
|
|
22
|
+
Object.defineProperty(exports, "SqliteStore", { enumerable: true, get: function () { return store_js_2.SqliteStore; } });
|
|
23
|
+
Object.defineProperty(exports, "sqliteStoreMigration", { enumerable: true, get: function () { return store_js_2.sqliteStoreMigration; } });
|
|
24
|
+
Object.defineProperty(exports, "sqliteStoreMigrations", { enumerable: true, get: function () { return store_js_2.sqliteStoreMigrations; } });
|
|
25
|
+
var vectors_js_2 = require("./vectors.js");
|
|
26
|
+
Object.defineProperty(exports, "SqliteVectorStore", { enumerable: true, get: function () { return vectors_js_2.SqliteVectorStore; } });
|
|
27
|
+
Object.defineProperty(exports, "sqliteVectorStoreMigration", { enumerable: true, get: function () { return vectors_js_2.sqliteVectorStoreMigration; } });
|
|
28
|
+
Object.defineProperty(exports, "sqliteVectorStoreMigrations", { enumerable: true, get: function () { return vectors_js_2.sqliteVectorStoreMigrations; } });
|
|
29
|
+
function sqliteMigrations(options = {}) {
|
|
30
|
+
const adapters = new Set(options.adapters ?? ['operations', 'store', 'vectors']);
|
|
31
|
+
return [
|
|
32
|
+
...(adapters.has('operations') ? (0, operations_js_1.sqliteOperationStoreMigrations)() : []),
|
|
33
|
+
...(adapters.has('store') ? (0, store_js_1.sqliteStoreMigrations)() : []),
|
|
34
|
+
...(adapters.has('vectors') ? (0, vectors_js_1.sqliteVectorStoreMigrations)() : []),
|
|
35
|
+
];
|
|
36
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type MigrationResult, type MigrationStatus, type SchemaMigration } from '../utils/schema-migrations.js';
|
|
2
|
+
import { type SqliteDatabaseLike, type SqliteLikeClient } from './client.js';
|
|
3
|
+
export { type AppliedMigration, type MigrationResult, type MigrationStatus, migrationChecksum, type SchemaMigration, SchemaMigrationError, } from '../utils/schema-migrations.js';
|
|
4
|
+
/** Options for applying or inspecting SQLite migrations. */
|
|
5
|
+
export interface SqliteMigrateOptions {
|
|
6
|
+
/** Plans without writing anything, not even the table that records migrations. */
|
|
7
|
+
dryRun?: boolean;
|
|
8
|
+
/** The table that records applied migrations. Defaults to `nexus_schema_migrations`. */
|
|
9
|
+
table?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Where a SQLite database stands against a list of migrations. Reads only: on a database that has
|
|
13
|
+
* never been migrated, everything is pending.
|
|
14
|
+
*/
|
|
15
|
+
export declare function sqliteMigrationStatus(database: SqliteLikeClient | SqliteDatabaseLike, migrations: readonly SchemaMigration[], options?: Pick<SqliteMigrateOptions, 'table'>): Promise<MigrationStatus>;
|
|
16
|
+
/**
|
|
17
|
+
* Applies the pending migrations in order, recording each with a checksum.
|
|
18
|
+
*
|
|
19
|
+
* Each migration runs inside `BEGIN IMMEDIATE`, which takes SQLite's write lock: its statements and
|
|
20
|
+
* the row recording it land together or not at all, and a second process migrating the same file
|
|
21
|
+
* waits for the first instead of interleaving with it. A migration whose statements changed after it
|
|
22
|
+
* ran is refused before anything is written.
|
|
23
|
+
*/
|
|
24
|
+
export declare function applySqliteMigrations(database: SqliteLikeClient | SqliteDatabaseLike, migrations: readonly SchemaMigration[], options?: SqliteMigrateOptions): Promise<MigrationResult>;
|
|
25
|
+
/** The statement that creates the migrations table, which `migrate()` runs first. */
|
|
26
|
+
export declare function sqliteMigrationsTableStatement(table?: string): string;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SchemaMigrationError = exports.migrationChecksum = void 0;
|
|
4
|
+
exports.sqliteMigrationStatus = sqliteMigrationStatus;
|
|
5
|
+
exports.applySqliteMigrations = applySqliteMigrations;
|
|
6
|
+
exports.sqliteMigrationsTableStatement = sqliteMigrationsTableStatement;
|
|
7
|
+
const schema_migrations_js_1 = require("../utils/schema-migrations.js");
|
|
8
|
+
const client_js_1 = require("./client.js");
|
|
9
|
+
var schema_migrations_js_2 = require("../utils/schema-migrations.js");
|
|
10
|
+
Object.defineProperty(exports, "migrationChecksum", { enumerable: true, get: function () { return schema_migrations_js_2.migrationChecksum; } });
|
|
11
|
+
Object.defineProperty(exports, "SchemaMigrationError", { enumerable: true, get: function () { return schema_migrations_js_2.SchemaMigrationError; } });
|
|
12
|
+
async function sqliteMigrationStatus(database, migrations, options = {}) {
|
|
13
|
+
return (0, schema_migrations_js_1.planMigrations)(migrations, await readApplied((0, client_js_1.toSqliteClient)(database), options.table ?? schema_migrations_js_1.MIGRATIONS_TABLE));
|
|
14
|
+
}
|
|
15
|
+
async function applySqliteMigrations(database, migrations, options = {}) {
|
|
16
|
+
const client = (0, client_js_1.toSqliteClient)(database);
|
|
17
|
+
const tableName = options.table ?? schema_migrations_js_1.MIGRATIONS_TABLE;
|
|
18
|
+
if (options.dryRun) {
|
|
19
|
+
const status = await sqliteMigrationStatus(client, migrations, options);
|
|
20
|
+
(0, schema_migrations_js_1.assertUnchanged)(status);
|
|
21
|
+
return { applied: status.pending, statements: status.pending.flatMap((m) => [...m.statements]), dryRun: true };
|
|
22
|
+
}
|
|
23
|
+
(0, schema_migrations_js_1.planMigrations)(migrations, []);
|
|
24
|
+
await client.exec(sqliteMigrationsTableStatement(tableName));
|
|
25
|
+
const status = (0, schema_migrations_js_1.planMigrations)(migrations, await readApplied(client, tableName));
|
|
26
|
+
(0, schema_migrations_js_1.assertUnchanged)(status);
|
|
27
|
+
const table = (0, client_js_1.quoteSqliteTable)(tableName);
|
|
28
|
+
const statements = [];
|
|
29
|
+
for (const migration of status.pending) {
|
|
30
|
+
const record = `INSERT OR IGNORE INTO ${table} (component, version, name, checksum, applied_at) VALUES (${(0, schema_migrations_js_1.sqlLiteral)(migration.component)}, ${migration.version}, ${(0, schema_migrations_js_1.sqlLiteral)(migration.name)}, ${(0, schema_migrations_js_1.sqlLiteral)((0, schema_migrations_js_1.migrationChecksum)(migration))}, ${(0, schema_migrations_js_1.sqlLiteral)(new Date().toISOString())})`;
|
|
31
|
+
const script = ['BEGIN IMMEDIATE', ...migration.statements, record, 'COMMIT'].join(';\n');
|
|
32
|
+
try {
|
|
33
|
+
await client.exec(`${script};`);
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
try {
|
|
37
|
+
await client.exec('ROLLBACK');
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
}
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
statements.push(...migration.statements);
|
|
44
|
+
}
|
|
45
|
+
return { applied: status.pending, statements, dryRun: false };
|
|
46
|
+
}
|
|
47
|
+
function sqliteMigrationsTableStatement(table = schema_migrations_js_1.MIGRATIONS_TABLE) {
|
|
48
|
+
return `CREATE TABLE IF NOT EXISTS ${(0, client_js_1.quoteSqliteTable)(table)} (
|
|
49
|
+
component TEXT NOT NULL,
|
|
50
|
+
version INTEGER NOT NULL,
|
|
51
|
+
name TEXT NOT NULL,
|
|
52
|
+
checksum TEXT NOT NULL,
|
|
53
|
+
applied_at TEXT NOT NULL,
|
|
54
|
+
PRIMARY KEY (component, version)
|
|
55
|
+
)`;
|
|
56
|
+
}
|
|
57
|
+
async function readApplied(client, table) {
|
|
58
|
+
const exists = (await client.all(`SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?`, [
|
|
59
|
+
table,
|
|
60
|
+
]));
|
|
61
|
+
if (exists.length === 0)
|
|
62
|
+
return [];
|
|
63
|
+
const rows = (await client.all(`SELECT component, version, name, checksum, applied_at FROM ${(0, client_js_1.quoteSqliteTable)(table)} ORDER BY applied_at, component, version`, []));
|
|
64
|
+
return rows.map((row) => ({
|
|
65
|
+
component: String(row.component),
|
|
66
|
+
version: Number(row.version),
|
|
67
|
+
name: String(row.name),
|
|
68
|
+
checksum: String(row.checksum),
|
|
69
|
+
appliedAt: String(row.applied_at),
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import { type OperationRecord, type OperationStore, type OperationStoreFilter, type OperationStoreStats } from '../types/operations.js';
|
|
2
|
+
import type { MigrationResult, SchemaMigration } from '../utils/schema-migrations.js';
|
|
2
3
|
import { type SqliteDatabaseLike, type SqliteLikeClient } from './client.js';
|
|
4
|
+
import type { SqliteMigrateOptions } from './migrations.js';
|
|
3
5
|
/** Options for the SQLite operation store. */
|
|
4
6
|
export interface SqliteOperationStoreOptions {
|
|
5
7
|
/** Table name. Defaults to `nexus_operations`. */
|
|
6
8
|
table?: string;
|
|
7
9
|
}
|
|
8
|
-
/** The schema, as statements
|
|
10
|
+
/** The schema, as statements: every migration's, in order. For the application's own tooling. */
|
|
9
11
|
export declare function sqliteOperationStoreMigration(options?: SqliteOperationStoreOptions): string[];
|
|
12
|
+
/**
|
|
13
|
+
* The versioned schema, which `migrate()` applies. Version 1 is the 2.0 table; version 2 indexes
|
|
14
|
+
* queued work by age, so a claim reads the oldest few rows instead of sorting the queue; version 3
|
|
15
|
+
* indexes queued work by tenant.
|
|
16
|
+
*/
|
|
17
|
+
export declare function sqliteOperationStoreMigrations(options?: SqliteOperationStoreOptions): SchemaMigration[];
|
|
10
18
|
/**
|
|
11
19
|
* Operation records in SQLite: durable operations, and — through `OperationStoreCheckpointer` — graph
|
|
12
20
|
* and workflow checkpoints, on one machine with no server to run.
|
|
@@ -20,8 +28,11 @@ export declare class SqliteOperationStore<TResult = unknown> implements Operatio
|
|
|
20
28
|
private readonly client;
|
|
21
29
|
private readonly table;
|
|
22
30
|
constructor(database: SqliteLikeClient | SqliteDatabaseLike, options?: SqliteOperationStoreOptions);
|
|
23
|
-
/**
|
|
24
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Applies this store's pending migrations, recorded in `nexus_schema_migrations`, each inside
|
|
33
|
+
* `BEGIN IMMEDIATE`. Never runs implicitly. Safe on a file an older release created.
|
|
34
|
+
*/
|
|
35
|
+
migrate(options?: SqliteMigrateOptions): Promise<MigrationResult>;
|
|
25
36
|
/**
|
|
26
37
|
* Inserts a new record. Throws `OperationDuplicateError` when its idempotency key is already
|
|
27
38
|
* claimed. Refuses records carrying raw bytes.
|
|
@@ -1,7 +1,41 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.SqliteOperationStore = void 0;
|
|
4
37
|
exports.sqliteOperationStoreMigration = sqliteOperationStoreMigration;
|
|
38
|
+
exports.sqliteOperationStoreMigrations = sqliteOperationStoreMigrations;
|
|
5
39
|
const errors_js_1 = require("../operations/errors.js");
|
|
6
40
|
const serialization_js_1 = require("../operations/serialization.js");
|
|
7
41
|
const operations_js_1 = require("../types/operations.js");
|
|
@@ -9,8 +43,31 @@ const client_js_1 = require("./client.js");
|
|
|
9
43
|
const DEFAULT_TABLE = 'nexus_operations';
|
|
10
44
|
const TERMINAL = operations_js_1.TERMINAL_OPERATION_STATUSES.map((status) => `'${status}'`).join(', ');
|
|
11
45
|
function sqliteOperationStoreMigration(options = {}) {
|
|
46
|
+
return sqliteOperationStoreMigrations(options).flatMap((migration) => [...migration.statements]);
|
|
47
|
+
}
|
|
48
|
+
function sqliteOperationStoreMigrations(options = {}) {
|
|
12
49
|
const name = options.table ?? DEFAULT_TABLE;
|
|
13
50
|
const table = (0, client_js_1.quoteSqliteTable)(name);
|
|
51
|
+
const component = `operations:${name}`;
|
|
52
|
+
return [
|
|
53
|
+
{ component, version: 1, name: 'create the operations table', statements: createStatements(name, table) },
|
|
54
|
+
{
|
|
55
|
+
component,
|
|
56
|
+
version: 2,
|
|
57
|
+
name: 'index queued work by age',
|
|
58
|
+
statements: [`CREATE INDEX IF NOT EXISTS "${name}_queued" ON ${table} (status, created_at, id)`],
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
component,
|
|
62
|
+
version: 3,
|
|
63
|
+
name: 'index queued work by tenant',
|
|
64
|
+
statements: [
|
|
65
|
+
`CREATE INDEX IF NOT EXISTS "${name}_tenant_queued" ON ${table} (status, json_extract(doc, '$.tenantId'), created_at, id)`,
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
}
|
|
70
|
+
function createStatements(name, table) {
|
|
14
71
|
return [
|
|
15
72
|
`CREATE TABLE IF NOT EXISTS ${table} (
|
|
16
73
|
id TEXT PRIMARY KEY,
|
|
@@ -36,9 +93,9 @@ class SqliteOperationStore {
|
|
|
36
93
|
this.client = (0, client_js_1.toSqliteClient)(database);
|
|
37
94
|
this.table = (0, client_js_1.quoteSqliteTable)(options.table ?? DEFAULT_TABLE);
|
|
38
95
|
}
|
|
39
|
-
async migrate() {
|
|
40
|
-
|
|
41
|
-
|
|
96
|
+
async migrate(options = {}) {
|
|
97
|
+
const { applySqliteMigrations } = await Promise.resolve().then(() => __importStar(require('./migrations.js')));
|
|
98
|
+
return applySqliteMigrations(this.client, sqliteOperationStoreMigrations(this.options), options);
|
|
42
99
|
}
|
|
43
100
|
async create(record) {
|
|
44
101
|
(0, serialization_js_1.assertSerializableRecord)(record);
|
|
@@ -103,29 +160,21 @@ class SqliteOperationStore {
|
|
|
103
160
|
}
|
|
104
161
|
async listQueued(limit, filter) {
|
|
105
162
|
const params = [new Date().toISOString()];
|
|
106
|
-
|
|
107
|
-
if (filter?.kindPrefix) {
|
|
108
|
-
params.push(filter.kindPrefix, filter.kindPrefix);
|
|
109
|
-
kind = ' AND substr(kind, 1, length(?)) = ?';
|
|
110
|
-
}
|
|
163
|
+
const narrowed = filterSql(filter, params);
|
|
111
164
|
params.push(limit);
|
|
112
165
|
return this.many(`SELECT doc FROM ${this.table}
|
|
113
|
-
WHERE status = 'queued' AND (lease_expires_at IS NULL OR lease_expires_at <= ?)${
|
|
166
|
+
WHERE status = 'queued' AND (lease_expires_at IS NULL OR lease_expires_at <= ?)${narrowed}
|
|
114
167
|
ORDER BY created_at, id
|
|
115
168
|
LIMIT ?`, params);
|
|
116
169
|
}
|
|
117
170
|
async stats(now, filter) {
|
|
118
171
|
const params = [now];
|
|
119
|
-
|
|
120
|
-
if (filter?.kindPrefix) {
|
|
121
|
-
params.push(filter.kindPrefix, filter.kindPrefix);
|
|
122
|
-
kind = ' AND substr(kind, 1, length(?)) = ?';
|
|
123
|
-
}
|
|
172
|
+
const narrowed = filterSql(filter, params);
|
|
124
173
|
const rows = (await this.client.all(`SELECT status, count(*) AS count,
|
|
125
174
|
min(CASE WHEN status = 'queued' THEN created_at END) AS oldest,
|
|
126
175
|
sum(CASE WHEN status = 'running' AND (lease_expires_at IS NULL OR lease_expires_at <= ?) THEN 1 ELSE 0 END) AS lapsed
|
|
127
176
|
FROM ${this.table}
|
|
128
|
-
WHERE status NOT IN (${TERMINAL})${
|
|
177
|
+
WHERE status NOT IN (${TERMINAL})${narrowed}
|
|
129
178
|
GROUP BY status`, params));
|
|
130
179
|
const byStatus = {};
|
|
131
180
|
let oldestQueuedAt;
|
|
@@ -151,3 +200,15 @@ class SqliteOperationStore {
|
|
|
151
200
|
}
|
|
152
201
|
}
|
|
153
202
|
exports.SqliteOperationStore = SqliteOperationStore;
|
|
203
|
+
function filterSql(filter, params) {
|
|
204
|
+
let sql = '';
|
|
205
|
+
if (filter?.kindPrefix) {
|
|
206
|
+
params.push(filter.kindPrefix, filter.kindPrefix);
|
|
207
|
+
sql += ' AND substr(kind, 1, length(?)) = ?';
|
|
208
|
+
}
|
|
209
|
+
if (filter?.tenantId !== undefined) {
|
|
210
|
+
params.push(filter.tenantId);
|
|
211
|
+
sql += " AND json_extract(doc, '$.tenantId') = ?";
|
|
212
|
+
}
|
|
213
|
+
return sql;
|
|
214
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Store, StoreIndexOptions, StoreItem, StoreNamespace, StorePutOptions, StoreSearchOptions } from '../types/store.js';
|
|
2
|
+
import type { MigrationResult, SchemaMigration } from '../utils/schema-migrations.js';
|
|
2
3
|
import { type SqliteDatabaseLike, type SqliteLikeClient } from './client.js';
|
|
4
|
+
import type { SqliteMigrateOptions } from './migrations.js';
|
|
3
5
|
/** Options for the SQLite store. */
|
|
4
6
|
export interface SqliteStoreOptions {
|
|
5
7
|
/** Table name. Defaults to `nexus_store`. */
|
|
@@ -11,6 +13,8 @@ export interface SqliteStoreOptions {
|
|
|
11
13
|
}
|
|
12
14
|
/** The schema, as statements. */
|
|
13
15
|
export declare function sqliteStoreMigration(options?: Pick<SqliteStoreOptions, 'table'>): string[];
|
|
16
|
+
/** The versioned schema, which `migrate()` applies. Version 1 is the 2.0 schema. */
|
|
17
|
+
export declare function sqliteStoreMigrations(options?: Pick<SqliteStoreOptions, 'table'>): SchemaMigration[];
|
|
14
18
|
/**
|
|
15
19
|
* Long-term memory in SQLite, for one machine that needs memory to survive a restart.
|
|
16
20
|
*
|
|
@@ -25,8 +29,11 @@ export declare class SqliteStore implements Store {
|
|
|
25
29
|
private readonly table;
|
|
26
30
|
private readonly now;
|
|
27
31
|
constructor(database: SqliteLikeClient | SqliteDatabaseLike, options?: SqliteStoreOptions);
|
|
28
|
-
/**
|
|
29
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Applies this store's pending migrations, recorded in `nexus_schema_migrations`, each inside
|
|
34
|
+
* `BEGIN IMMEDIATE`. Never runs implicitly. Safe on a file an older release created.
|
|
35
|
+
*/
|
|
36
|
+
migrate(options?: SqliteMigrateOptions): Promise<MigrationResult>;
|
|
30
37
|
/** Stores an item, keeping its original `createdAt` when it replaces one. */
|
|
31
38
|
put<V>(namespace: StoreNamespace, key: string, value: V, options?: StorePutOptions): Promise<void>;
|
|
32
39
|
/** Reads an item, or `undefined` when it does not exist or has expired. */
|