nexus-ai-pro 2.1.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 +38 -0
- package/CHANGELOG.md +145 -1
- package/README.md +13 -8
- 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.js +12 -1
- package/dist/core/lifecycle.js +11 -6
- package/dist/core/nexus.d.ts +6 -0
- package/dist/core/nexus.js +103 -22
- package/dist/doctor/index.d.ts +90 -0
- package/dist/doctor/index.js +237 -0
- package/dist/graph/functional.d.ts +80 -7
- package/dist/graph/functional.js +138 -35
- package/dist/graph/graph.d.ts +15 -5
- package/dist/graph/graph.js +72 -20
- 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 +1 -0
- 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/rate-limiter.d.ts +2 -0
- package/dist/ops/rate-limiter.js +2 -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 +4 -0
- package/dist/server/assistant.js +8 -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 +24 -1
- package/dist/server/runs.js +90 -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/tracing/instrument.js +2 -0
- package/dist/types/config.d.ts +24 -2
- package/dist/types/graph.d.ts +11 -1
- package/dist/types/messages.d.ts +5 -0
- package/dist/types/operations.d.ts +6 -0
- package/dist/types/response.d.ts +20 -0
- package/dist/types/server.d.ts +10 -1
- 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 +1 -1
- package/dist/version.js +1 -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/core/lifecycle.js +11 -6
- package/dist-cjs/core/nexus.d.ts +6 -0
- package/dist-cjs/core/nexus.js +103 -22
- package/dist-cjs/doctor/index.d.ts +90 -0
- package/dist-cjs/doctor/index.js +276 -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 +15 -5
- package/dist-cjs/graph/graph.js +72 -20
- 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 +1 -0
- 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/rate-limiter.d.ts +2 -0
- package/dist-cjs/ops/rate-limiter.js +2 -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 +4 -0
- package/dist-cjs/server/assistant.js +8 -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 +24 -1
- package/dist-cjs/server/runs.js +89 -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/tracing/instrument.js +2 -0
- package/dist-cjs/types/config.d.ts +24 -2
- package/dist-cjs/types/graph.d.ts +11 -1
- package/dist-cjs/types/messages.d.ts +5 -0
- package/dist-cjs/types/operations.d.ts +6 -0
- package/dist-cjs/types/response.d.ts +20 -0
- package/dist-cjs/types/server.d.ts +10 -1
- 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 +1 -1
- package/dist-cjs/version.js +1 -1
- package/llms.txt +4 -3
- package/package.json +71 -2
|
@@ -2,9 +2,37 @@ export class MemoryCircuitStateStore {
|
|
|
2
2
|
now;
|
|
3
3
|
states = new Map();
|
|
4
4
|
probes = new Map();
|
|
5
|
+
windows = new Map();
|
|
5
6
|
constructor(now = () => Date.now()) {
|
|
6
7
|
this.now = now;
|
|
7
8
|
}
|
|
9
|
+
observe(providerName, observation) {
|
|
10
|
+
let window = this.windows.get(providerName);
|
|
11
|
+
if (!window) {
|
|
12
|
+
window = { buckets: new Map(), streak: 0 };
|
|
13
|
+
this.windows.set(providerName, window);
|
|
14
|
+
}
|
|
15
|
+
for (const bucket of observation.buckets) {
|
|
16
|
+
const stored = window.buckets.get(bucket.at) ?? { calls: 0, failures: 0 };
|
|
17
|
+
stored.calls += bucket.calls;
|
|
18
|
+
stored.failures += bucket.failures;
|
|
19
|
+
window.buckets.set(bucket.at, stored);
|
|
20
|
+
}
|
|
21
|
+
window.streak = observation.succeeded ? observation.trailingFailures : window.streak + observation.trailingFailures;
|
|
22
|
+
const keepAfter = observation.now - observation.windowMs - observation.bucketMs;
|
|
23
|
+
const since = observation.since ?? Number.NEGATIVE_INFINITY;
|
|
24
|
+
let calls = 0;
|
|
25
|
+
let failures = 0;
|
|
26
|
+
for (const [at, bucket] of window.buckets) {
|
|
27
|
+
if (at <= keepAfter)
|
|
28
|
+
window.buckets.delete(at);
|
|
29
|
+
else if (at >= since) {
|
|
30
|
+
calls += bucket.calls;
|
|
31
|
+
failures += bucket.failures;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return { calls, failures, consecutiveFailures: window.streak };
|
|
35
|
+
}
|
|
8
36
|
read() {
|
|
9
37
|
return [...this.states.values()].map((state) => ({ ...state }));
|
|
10
38
|
}
|
|
@@ -34,14 +62,54 @@ redis.call('HSET', KEYS[1], ARGV[1], ARGV[2])
|
|
|
34
62
|
redis.call('DEL', KEYS[2])
|
|
35
63
|
return 1
|
|
36
64
|
`;
|
|
65
|
+
const OBSERVE_SCRIPT = `
|
|
66
|
+
local key = KEYS[1]
|
|
67
|
+
for i = 6, #ARGV, 3 do
|
|
68
|
+
redis.call('HINCRBY', key, 'c:' .. ARGV[i], ARGV[i + 1])
|
|
69
|
+
redis.call('HINCRBY', key, 'f:' .. ARGV[i], ARGV[i + 2])
|
|
70
|
+
end
|
|
71
|
+
local streak
|
|
72
|
+
if ARGV[1] == '1' then
|
|
73
|
+
redis.call('HSET', key, 'streak', ARGV[2])
|
|
74
|
+
streak = tonumber(ARGV[2])
|
|
75
|
+
else
|
|
76
|
+
streak = tonumber(redis.call('HINCRBY', key, 'streak', ARGV[2]))
|
|
77
|
+
end
|
|
78
|
+
local keepAfter = tonumber(ARGV[3])
|
|
79
|
+
local since = tonumber(ARGV[4])
|
|
80
|
+
local calls, failures = 0, 0
|
|
81
|
+
local fields = redis.call('HGETALL', key)
|
|
82
|
+
for i = 1, #fields, 2 do
|
|
83
|
+
local name = fields[i]
|
|
84
|
+
local kind = string.sub(name, 1, 2)
|
|
85
|
+
if kind == 'c:' or kind == 'f:' then
|
|
86
|
+
local at = tonumber(string.sub(name, 3))
|
|
87
|
+
if at <= keepAfter then
|
|
88
|
+
redis.call('HDEL', key, name)
|
|
89
|
+
elseif at >= since then
|
|
90
|
+
if kind == 'c:' then calls = calls + tonumber(fields[i + 1]) else failures = failures + tonumber(fields[i + 1]) end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
redis.call('PEXPIRE', key, ARGV[5])
|
|
95
|
+
return { calls, failures, streak }
|
|
96
|
+
`;
|
|
37
97
|
export class RedisCircuitStateStore {
|
|
38
98
|
client;
|
|
39
99
|
prefix;
|
|
40
100
|
useEval;
|
|
101
|
+
observe;
|
|
41
102
|
constructor(client, options = {}) {
|
|
42
103
|
this.client = client;
|
|
43
104
|
this.prefix = options.prefix ?? 'nexus-ai-pro:circuits:';
|
|
44
105
|
this.useEval = options.useEval !== false && typeof client.eval === 'function';
|
|
106
|
+
if (this.useEval)
|
|
107
|
+
this.observe = (providerName, observation) => this.observeWithEval(providerName, observation);
|
|
108
|
+
}
|
|
109
|
+
async observeWithEval(providerName, observation) {
|
|
110
|
+
const reply = (await this.client.eval(OBSERVE_SCRIPT, 1, `${this.prefix}window:${providerName}`, observation.succeeded ? '1' : '0', String(observation.trailingFailures), String(observation.now - observation.windowMs - observation.bucketMs), String(observation.since ?? -1), String(observation.windowMs * 2 + observation.bucketMs), ...observation.buckets.flatMap((bucket) => [String(bucket.at), String(bucket.calls), String(bucket.failures)])));
|
|
111
|
+
const [calls, failures, streak] = (reply ?? []).map(Number);
|
|
112
|
+
return { calls: calls ?? 0, failures: failures ?? 0, consecutiveFailures: streak ?? 0 };
|
|
45
113
|
}
|
|
46
114
|
async read() {
|
|
47
115
|
const all = (await this.client.hgetall(this.statesKey())) ?? {};
|
|
@@ -26,6 +26,8 @@ export declare class CircuitCoordinator {
|
|
|
26
26
|
private lastSyncAt;
|
|
27
27
|
/** False after a store failure, until a sync succeeds; the breaker then decides locally. */
|
|
28
28
|
private reachable;
|
|
29
|
+
/** Calls not yet added to the shared window, per provider, with `shareObservations`. */
|
|
30
|
+
private readonly unreported;
|
|
29
31
|
constructor(host: CircuitHost);
|
|
30
32
|
/**
|
|
31
33
|
* Whether this worker may go half-open once a cooldown has elapsed. With a reachable store only
|
|
@@ -35,6 +37,11 @@ export declare class CircuitCoordinator {
|
|
|
35
37
|
/** Starts a background sync when the last one is older than the interval. Never waits. */
|
|
36
38
|
tick(): void;
|
|
37
39
|
sync(): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Counts one call toward the shared window, to be added on the next sync. Cheap and synchronous:
|
|
42
|
+
* a check never waits for the store.
|
|
43
|
+
*/
|
|
44
|
+
observed(providerName: string, failed: boolean): void;
|
|
38
45
|
/** Publishes a transition this worker made. */
|
|
39
46
|
published(providerName: string, entry: CircuitEntry, to: 'open' | 'closed', reason: string): void;
|
|
40
47
|
/** Publishes an operator reset, so every worker closes the circuit rather than only this one. */
|
|
@@ -45,6 +52,14 @@ export declare class CircuitCoordinator {
|
|
|
45
52
|
*/
|
|
46
53
|
reconcile(): void;
|
|
47
54
|
flush(): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Adds this worker's unreported calls to each provider's shared window, then opens a closed circuit
|
|
57
|
+
* whose shared count crossed a threshold. The batch is taken before the first await, so calls made
|
|
58
|
+
* while it is in flight wait for the next sync rather than being lost or counted twice.
|
|
59
|
+
*/
|
|
60
|
+
private report;
|
|
61
|
+
/** Opens a closed circuit whose shared window crossed the breaker's thresholds. */
|
|
62
|
+
private judge;
|
|
48
63
|
/** Takes a decision another worker published, when it is newer than what this worker knows. */
|
|
49
64
|
private adopt;
|
|
50
65
|
/**
|
|
@@ -55,3 +70,5 @@ export declare class CircuitCoordinator {
|
|
|
55
70
|
private publish;
|
|
56
71
|
private failed;
|
|
57
72
|
}
|
|
73
|
+
/** The width of one shared-window bucket: a twelfth of the window, so a bucket rolling out moves the count by little. */
|
|
74
|
+
export declare function bucketWidth(windowMs: number): number;
|
package/dist/ops/circuit-sync.js
CHANGED
|
@@ -4,6 +4,7 @@ export class CircuitCoordinator {
|
|
|
4
4
|
syncing;
|
|
5
5
|
lastSyncAt = Number.NEGATIVE_INFINITY;
|
|
6
6
|
reachable = true;
|
|
7
|
+
unreported = new Map();
|
|
7
8
|
constructor(host) {
|
|
8
9
|
this.host = host;
|
|
9
10
|
}
|
|
@@ -26,6 +27,8 @@ export class CircuitCoordinator {
|
|
|
26
27
|
this.syncing = (async () => {
|
|
27
28
|
try {
|
|
28
29
|
this.lastSyncAt = this.host.now();
|
|
30
|
+
if (this.unreported.size > 0)
|
|
31
|
+
await this.report(store);
|
|
29
32
|
for (const shared of await store.read())
|
|
30
33
|
this.adopt(shared);
|
|
31
34
|
const resetTimeoutMs = this.host.config.resetTimeoutMs ?? 30_000;
|
|
@@ -51,6 +54,29 @@ export class CircuitCoordinator {
|
|
|
51
54
|
})();
|
|
52
55
|
return this.syncing;
|
|
53
56
|
}
|
|
57
|
+
observed(providerName, failed) {
|
|
58
|
+
if (!this.host.config.shareObservations || !this.host.config.store?.observe)
|
|
59
|
+
return;
|
|
60
|
+
const bucketMs = bucketWidth(this.host.config.windowMs ?? 60_000);
|
|
61
|
+
const at = Math.floor(this.host.now() / bucketMs) * bucketMs;
|
|
62
|
+
let pending = this.unreported.get(providerName);
|
|
63
|
+
if (!pending) {
|
|
64
|
+
pending = { buckets: new Map(), succeeded: false, trailing: 0 };
|
|
65
|
+
this.unreported.set(providerName, pending);
|
|
66
|
+
}
|
|
67
|
+
const bucket = pending.buckets.get(at) ?? { calls: 0, failures: 0 };
|
|
68
|
+
bucket.calls += 1;
|
|
69
|
+
if (failed)
|
|
70
|
+
bucket.failures += 1;
|
|
71
|
+
pending.buckets.set(at, bucket);
|
|
72
|
+
if (failed)
|
|
73
|
+
pending.trailing += 1;
|
|
74
|
+
else {
|
|
75
|
+
pending.succeeded = true;
|
|
76
|
+
pending.trailing = 0;
|
|
77
|
+
}
|
|
78
|
+
this.tick();
|
|
79
|
+
}
|
|
54
80
|
published(providerName, entry, to, reason) {
|
|
55
81
|
entry.changedAt = this.stampAfter(entry.changedAt);
|
|
56
82
|
this.publish({
|
|
@@ -72,6 +98,23 @@ export class CircuitCoordinator {
|
|
|
72
98
|
reconcile() {
|
|
73
99
|
for (const name of [...this.host.names()]) {
|
|
74
100
|
const entry = this.host.entry(name);
|
|
101
|
+
if (this.host.config.shareObservations && this.host.config.store?.observe && entry.window.length > 0) {
|
|
102
|
+
const bucketMs = bucketWidth(this.host.config.windowMs ?? 60_000);
|
|
103
|
+
const buckets = new Map();
|
|
104
|
+
for (const call of entry.window) {
|
|
105
|
+
const at = Math.floor(call.at / bucketMs) * bucketMs;
|
|
106
|
+
const bucket = buckets.get(at) ?? { calls: 0, failures: 0 };
|
|
107
|
+
bucket.calls += 1;
|
|
108
|
+
if (call.failed)
|
|
109
|
+
bucket.failures += 1;
|
|
110
|
+
buckets.set(at, bucket);
|
|
111
|
+
}
|
|
112
|
+
this.unreported.set(name, {
|
|
113
|
+
buckets,
|
|
114
|
+
succeeded: entry.window.some((call) => !call.failed),
|
|
115
|
+
trailing: entry.consecutiveFailures,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
75
118
|
if (entry.state === 'open' && entry.changedAt === Number.NEGATIVE_INFINITY) {
|
|
76
119
|
this.published(name, entry, 'open', entry.reason ?? 'opened while shared state was loading');
|
|
77
120
|
}
|
|
@@ -81,6 +124,46 @@ export class CircuitCoordinator {
|
|
|
81
124
|
async flush() {
|
|
82
125
|
await Promise.all([...this.pending]);
|
|
83
126
|
}
|
|
127
|
+
async report(store) {
|
|
128
|
+
if (!store.observe || this.unreported.size === 0)
|
|
129
|
+
return;
|
|
130
|
+
const batches = [...this.unreported];
|
|
131
|
+
this.unreported.clear();
|
|
132
|
+
const windowMs = this.host.config.windowMs ?? 60_000;
|
|
133
|
+
for (const [name, pending] of batches) {
|
|
134
|
+
const entry = this.host.entry(name);
|
|
135
|
+
const window = await store.observe(name, {
|
|
136
|
+
buckets: [...pending.buckets].map(([at, bucket]) => ({ at, calls: bucket.calls, failures: bucket.failures })),
|
|
137
|
+
succeeded: pending.succeeded,
|
|
138
|
+
trailingFailures: pending.trailing,
|
|
139
|
+
windowMs,
|
|
140
|
+
bucketMs: bucketWidth(windowMs),
|
|
141
|
+
now: this.host.now(),
|
|
142
|
+
...(entry.state === 'closed' && Number.isFinite(entry.changedAt) ? { since: entry.changedAt } : {}),
|
|
143
|
+
});
|
|
144
|
+
entry.shared = {
|
|
145
|
+
calls: window.calls,
|
|
146
|
+
failures: window.failures,
|
|
147
|
+
consecutiveFailures: window.consecutiveFailures,
|
|
148
|
+
};
|
|
149
|
+
this.judge(name, entry, window);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
judge(name, entry, window) {
|
|
153
|
+
if (entry.state !== 'closed')
|
|
154
|
+
return;
|
|
155
|
+
const config = this.host.config;
|
|
156
|
+
if (window.consecutiveFailures >= (config.failureThreshold ?? 5)) {
|
|
157
|
+
this.host.transition(name, entry, 'open', 'shared failure threshold reached');
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
const rate = config.failureRateThreshold;
|
|
161
|
+
if (rate !== undefined &&
|
|
162
|
+
window.calls >= (config.minimumThroughput ?? 10) &&
|
|
163
|
+
window.failures / window.calls >= rate) {
|
|
164
|
+
this.host.transition(name, entry, 'open', 'shared failure rate threshold reached');
|
|
165
|
+
}
|
|
166
|
+
}
|
|
84
167
|
adopt(shared) {
|
|
85
168
|
const entry = this.host.entry(shared.providerName);
|
|
86
169
|
if (shared.updatedAt <= entry.changedAt)
|
|
@@ -120,3 +203,6 @@ export class CircuitCoordinator {
|
|
|
120
203
|
}
|
|
121
204
|
}
|
|
122
205
|
}
|
|
206
|
+
export function bucketWidth(windowMs) {
|
|
207
|
+
return Math.max(1, Math.floor(windowMs / 12));
|
|
208
|
+
}
|
|
@@ -10,6 +10,8 @@ export interface RateLimitedRequest {
|
|
|
10
10
|
model?: string;
|
|
11
11
|
/** Caller, for per-user limits. */
|
|
12
12
|
userId?: string;
|
|
13
|
+
/** Tenant, for per-tenant limits. */
|
|
14
|
+
tenantId?: string;
|
|
13
15
|
}
|
|
14
16
|
/** Raised when a caller exceeds its rate limit. */
|
|
15
17
|
export declare class NexusRateLimitError extends Error {
|
package/dist/ops/rate-limiter.js
CHANGED
|
@@ -63,6 +63,8 @@ export class RateLimiter {
|
|
|
63
63
|
getKey(request, config) {
|
|
64
64
|
if (config.key === 'model')
|
|
65
65
|
return `model:${request.model}`;
|
|
66
|
+
if (config.key === 'tenantId')
|
|
67
|
+
return `tenant:${request.tenantId || 'none'}`;
|
|
66
68
|
if (config.key === 'global')
|
|
67
69
|
return 'global';
|
|
68
70
|
return `user:${request.userId || 'anonymous'}`;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import type { CircuitStateStore, SharedCircuitState } from '../ops/circuit-breaker.js';
|
|
1
|
+
import type { CircuitObservation, CircuitStateStore, CircuitWindow, SharedCircuitState } from '../ops/circuit-breaker.js';
|
|
2
|
+
import type { MigrationResult, SchemaMigration } from '../utils/schema-migrations.js';
|
|
2
3
|
import { type PostgresLikeClient } from './client.js';
|
|
4
|
+
import type { PostgresMigrateOptions } from './migrations.js';
|
|
3
5
|
/** Options for the Postgres circuit store. */
|
|
4
6
|
export interface PostgresCircuitStateStoreOptions {
|
|
5
7
|
/** Table name, optionally schema-qualified. Defaults to `nexus_circuits`. */
|
|
@@ -7,8 +9,13 @@ export interface PostgresCircuitStateStoreOptions {
|
|
|
7
9
|
/** Clock for probe leases. Defaults to `Date.now`, the same clock the breaker uses. */
|
|
8
10
|
now?: () => number;
|
|
9
11
|
}
|
|
10
|
-
/** The schema, as statements. */
|
|
12
|
+
/** The schema, as statements: every migration's, in order. */
|
|
11
13
|
export declare function circuitStoreMigration(options?: Pick<PostgresCircuitStateStoreOptions, 'table'>): string[];
|
|
14
|
+
/**
|
|
15
|
+
* The versioned schema, which `migrate()` and `nexus db migrate` apply. Version 1 is the 2.0 table;
|
|
16
|
+
* version 2 adds the shared failure window, so a breaker counts every worker's calls.
|
|
17
|
+
*/
|
|
18
|
+
export declare function circuitStoreMigrations(options?: Pick<PostgresCircuitStateStoreOptions, 'table'>): SchemaMigration[];
|
|
12
19
|
/**
|
|
13
20
|
* Shared circuit state in Postgres.
|
|
14
21
|
*
|
|
@@ -20,10 +27,14 @@ export declare class PostgresCircuitStateStore implements CircuitStateStore {
|
|
|
20
27
|
private readonly client;
|
|
21
28
|
private readonly options;
|
|
22
29
|
private readonly table;
|
|
30
|
+
private readonly windowTable;
|
|
23
31
|
private readonly now;
|
|
24
32
|
constructor(client: PostgresLikeClient, options?: PostgresCircuitStateStoreOptions);
|
|
25
|
-
/**
|
|
26
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Applies this store's pending migrations, recorded in `nexus_schema_migrations`, under a lock.
|
|
35
|
+
* Never runs implicitly. Safe on a database an older release created: what exists is kept.
|
|
36
|
+
*/
|
|
37
|
+
migrate(options?: PostgresMigrateOptions): Promise<MigrationResult>;
|
|
27
38
|
/** Every provider's shared circuit state. */
|
|
28
39
|
read(): Promise<SharedCircuitState[]>;
|
|
29
40
|
/**
|
|
@@ -35,4 +46,10 @@ export declare class PostgresCircuitStateStore implements CircuitStateStore {
|
|
|
35
46
|
* claimant, including when it already holds the claim.
|
|
36
47
|
*/
|
|
37
48
|
claimProbe(providerName: string, owner: string, ttlMs: number): Promise<boolean>;
|
|
49
|
+
/**
|
|
50
|
+
* Adds one worker's calls to a provider's shared window, then sums it. The add, the trim of buckets
|
|
51
|
+
* that rolled out, and the streak update are one statement, so two workers reporting at once both
|
|
52
|
+
* count. Needs version 2 of the schema.
|
|
53
|
+
*/
|
|
54
|
+
observe(providerName: string, observation: CircuitObservation): Promise<CircuitWindow>;
|
|
38
55
|
}
|
|
@@ -1,28 +1,58 @@
|
|
|
1
|
-
import { fromJson, quoteTable
|
|
1
|
+
import { fromJson, quoteTable } from './client.js';
|
|
2
2
|
export function circuitStoreMigration(options = {}) {
|
|
3
|
+
return circuitStoreMigrations(options).flatMap((migration) => [...migration.statements]);
|
|
4
|
+
}
|
|
5
|
+
export function circuitStoreMigrations(options = {}) {
|
|
6
|
+
const name = options.table ?? 'nexus_circuits';
|
|
7
|
+
const component = `circuits:${name}`;
|
|
3
8
|
return [
|
|
4
|
-
|
|
9
|
+
{
|
|
10
|
+
component,
|
|
11
|
+
version: 1,
|
|
12
|
+
name: 'create the circuits table',
|
|
13
|
+
statements: [
|
|
14
|
+
`CREATE TABLE IF NOT EXISTS ${quoteTable(name)} (
|
|
5
15
|
provider text PRIMARY KEY,
|
|
6
16
|
updated_at double precision,
|
|
7
17
|
doc jsonb,
|
|
8
18
|
probe_owner text,
|
|
9
19
|
probe_expires_at double precision
|
|
10
20
|
)`,
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
component,
|
|
25
|
+
version: 2,
|
|
26
|
+
name: 'add the shared failure window',
|
|
27
|
+
statements: [
|
|
28
|
+
`ALTER TABLE ${quoteTable(name)} ADD COLUMN IF NOT EXISTS failure_streak integer NOT NULL DEFAULT 0`,
|
|
29
|
+
`CREATE TABLE IF NOT EXISTS ${quoteTable(`${name}_window`)} (
|
|
30
|
+
provider text NOT NULL,
|
|
31
|
+
bucket double precision NOT NULL,
|
|
32
|
+
calls integer NOT NULL,
|
|
33
|
+
failures integer NOT NULL,
|
|
34
|
+
PRIMARY KEY (provider, bucket)
|
|
35
|
+
)`,
|
|
36
|
+
],
|
|
37
|
+
},
|
|
11
38
|
];
|
|
12
39
|
}
|
|
13
40
|
export class PostgresCircuitStateStore {
|
|
14
41
|
client;
|
|
15
42
|
options;
|
|
16
43
|
table;
|
|
44
|
+
windowTable;
|
|
17
45
|
now;
|
|
18
46
|
constructor(client, options = {}) {
|
|
19
47
|
this.client = client;
|
|
20
48
|
this.options = options;
|
|
21
49
|
this.table = quoteTable(options.table ?? 'nexus_circuits');
|
|
50
|
+
this.windowTable = quoteTable(`${options.table ?? 'nexus_circuits'}_window`);
|
|
22
51
|
this.now = options.now ?? (() => Date.now());
|
|
23
52
|
}
|
|
24
|
-
async migrate() {
|
|
25
|
-
await
|
|
53
|
+
async migrate(options = {}) {
|
|
54
|
+
const { applyPostgresMigrations } = await import('./migrations.js');
|
|
55
|
+
return applyPostgresMigrations(this.client, circuitStoreMigrations(this.options), options);
|
|
26
56
|
}
|
|
27
57
|
async read() {
|
|
28
58
|
const { rows } = await this.client.query(`SELECT doc::text AS doc FROM ${this.table} WHERE doc IS NOT NULL`);
|
|
@@ -43,4 +73,35 @@ export class PostgresCircuitStateStore {
|
|
|
43
73
|
RETURNING provider`, [providerName, owner, now, now + ttlMs]);
|
|
44
74
|
return rows.length > 0;
|
|
45
75
|
}
|
|
76
|
+
async observe(providerName, observation) {
|
|
77
|
+
const keepAfter = observation.now - observation.windowMs - observation.bucketMs;
|
|
78
|
+
const { rows } = await this.client.query(`WITH added AS (
|
|
79
|
+
INSERT INTO ${this.windowTable} AS stored (provider, bucket, calls, failures)
|
|
80
|
+
SELECT $1, item.at, item.calls, item.failures
|
|
81
|
+
FROM jsonb_to_recordset($2::jsonb) AS item(at double precision, calls integer, failures integer)
|
|
82
|
+
ON CONFLICT (provider, bucket) DO UPDATE
|
|
83
|
+
SET calls = stored.calls + EXCLUDED.calls, failures = stored.failures + EXCLUDED.failures
|
|
84
|
+
), trimmed AS (
|
|
85
|
+
DELETE FROM ${this.windowTable} WHERE provider = $1 AND bucket <= $5::double precision
|
|
86
|
+
)
|
|
87
|
+
INSERT INTO ${this.table} AS circuit (provider, failure_streak) VALUES ($1, $3::integer)
|
|
88
|
+
ON CONFLICT (provider) DO UPDATE SET failure_streak = CASE WHEN $4::integer = 1
|
|
89
|
+
THEN EXCLUDED.failure_streak ELSE circuit.failure_streak + EXCLUDED.failure_streak END
|
|
90
|
+
RETURNING failure_streak`, [
|
|
91
|
+
providerName,
|
|
92
|
+
JSON.stringify(observation.buckets),
|
|
93
|
+
observation.trailingFailures,
|
|
94
|
+
observation.succeeded ? 1 : 0,
|
|
95
|
+
keepAfter,
|
|
96
|
+
]);
|
|
97
|
+
const totals = await this.client.query(`SELECT coalesce(sum(calls), 0)::int AS calls, coalesce(sum(failures), 0)::int AS failures
|
|
98
|
+
FROM ${this.windowTable}
|
|
99
|
+
WHERE provider = $1 AND bucket > $2::double precision AND bucket >= $3::double precision`, [providerName, keepAfter, observation.since ?? -1]);
|
|
100
|
+
const sums = totals.rows[0];
|
|
101
|
+
return {
|
|
102
|
+
calls: Number(sums?.calls ?? 0),
|
|
103
|
+
failures: Number(sums?.failures ?? 0),
|
|
104
|
+
consecutiveFailures: Number(rows[0]?.failure_streak ?? 0),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
46
107
|
}
|
|
@@ -37,7 +37,5 @@ export declare function quoteDerived(table: string, suffix: string): string;
|
|
|
37
37
|
* reading text everywhere is the only way to get the same value from every driver.
|
|
38
38
|
*/
|
|
39
39
|
export declare function fromJson<T>(value: unknown): T;
|
|
40
|
-
/** Runs migration statements one at a time, which every driver accepts. */
|
|
41
|
-
export declare function runStatements(client: PostgresLikeClient, statements: readonly string[]): Promise<void>;
|
|
42
40
|
/** Whether an error is Postgres refusing a duplicate key. */
|
|
43
41
|
export declare function isUniqueViolation(error: unknown): boolean;
|
package/dist/postgres/client.js
CHANGED
|
@@ -22,10 +22,6 @@ export function quoteDerived(table, suffix) {
|
|
|
22
22
|
export function fromJson(value) {
|
|
23
23
|
return (typeof value === 'string' ? JSON.parse(value) : value);
|
|
24
24
|
}
|
|
25
|
-
export async function runStatements(client, statements) {
|
|
26
|
-
for (const statement of statements)
|
|
27
|
-
await client.query(statement);
|
|
28
|
-
}
|
|
29
25
|
export function isUniqueViolation(error) {
|
|
30
26
|
return error?.code === '23505';
|
|
31
27
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Dataset, DatasetStore, Experiment, ExperimentStore } from '../types/evaluate.js';
|
|
2
|
+
import type { MigrationResult, SchemaMigration } from '../utils/schema-migrations.js';
|
|
2
3
|
import { type PostgresLikeClient } from './client.js';
|
|
4
|
+
import type { PostgresMigrateOptions } from './migrations.js';
|
|
3
5
|
/** Options for the Postgres evaluation stores. */
|
|
4
6
|
export interface PostgresEvaluationStoreOptions {
|
|
5
7
|
/** Datasets table. Defaults to `nexus_datasets`. */
|
|
@@ -7,6 +9,10 @@ export interface PostgresEvaluationStoreOptions {
|
|
|
7
9
|
/** Experiments table. Defaults to `nexus_experiments`. */
|
|
8
10
|
experimentsTable?: string;
|
|
9
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* The versioned schema, which `migrate()` and `nexus db migrate` apply. Version 1 is the 2.0 schema.
|
|
14
|
+
*/
|
|
15
|
+
export declare function evaluationStoreMigrations(options?: PostgresEvaluationStoreOptions): SchemaMigration[];
|
|
10
16
|
/** The schema for both tables, as statements. */
|
|
11
17
|
export declare function evaluationStoreMigration(options?: PostgresEvaluationStoreOptions): string[];
|
|
12
18
|
/**
|
|
@@ -20,8 +26,11 @@ export declare class PostgresDatasetStore implements DatasetStore {
|
|
|
20
26
|
private readonly options;
|
|
21
27
|
private readonly table;
|
|
22
28
|
constructor(client: PostgresLikeClient, options?: PostgresEvaluationStoreOptions);
|
|
23
|
-
/**
|
|
24
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Applies this store's pending migrations, recorded in `nexus_schema_migrations`, under a lock.
|
|
31
|
+
* Never runs implicitly. Safe on a database an older release created: what exists is kept.
|
|
32
|
+
*/
|
|
33
|
+
migrate(options?: PostgresMigrateOptions): Promise<MigrationResult>;
|
|
25
34
|
/** Stores a dataset version, replacing one with the same name and version. */
|
|
26
35
|
save(dataset: Dataset): Promise<void>;
|
|
27
36
|
/** Returns a version, or the newest when none is given. */
|
|
@@ -38,8 +47,11 @@ export declare class PostgresExperimentStore implements ExperimentStore {
|
|
|
38
47
|
private readonly options;
|
|
39
48
|
private readonly table;
|
|
40
49
|
constructor(client: PostgresLikeClient, options?: PostgresEvaluationStoreOptions);
|
|
41
|
-
/**
|
|
42
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Applies this store's pending migrations, recorded in `nexus_schema_migrations`, under a lock.
|
|
52
|
+
* Never runs implicitly. Safe on a database an older release created: what exists is kept.
|
|
53
|
+
*/
|
|
54
|
+
migrate(options?: PostgresMigrateOptions): Promise<MigrationResult>;
|
|
43
55
|
/** Stores an experiment, replacing one with the same id. */
|
|
44
56
|
save(experiment: Experiment): Promise<void>;
|
|
45
57
|
/** Reads an experiment by id. */
|
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
import { fromJson, quoteDerived, quoteTable
|
|
1
|
+
import { fromJson, quoteDerived, quoteTable } from './client.js';
|
|
2
|
+
export function evaluationStoreMigrations(options = {}) {
|
|
3
|
+
return [
|
|
4
|
+
{
|
|
5
|
+
component: `evaluation:${options.datasetsTable ?? 'nexus_datasets'},${options.experimentsTable ?? 'nexus_experiments'}`,
|
|
6
|
+
version: 1,
|
|
7
|
+
name: 'create the dataset and experiment tables',
|
|
8
|
+
statements: evaluationStoreMigration(options),
|
|
9
|
+
},
|
|
10
|
+
];
|
|
11
|
+
}
|
|
2
12
|
export function evaluationStoreMigration(options = {}) {
|
|
3
13
|
const datasetsName = options.datasetsTable ?? 'nexus_datasets';
|
|
4
14
|
const experimentsName = options.experimentsTable ?? 'nexus_experiments';
|
|
@@ -33,8 +43,9 @@ export class PostgresDatasetStore {
|
|
|
33
43
|
this.options = options;
|
|
34
44
|
this.table = quoteTable(options.datasetsTable ?? 'nexus_datasets');
|
|
35
45
|
}
|
|
36
|
-
async migrate() {
|
|
37
|
-
await
|
|
46
|
+
async migrate(options = {}) {
|
|
47
|
+
const { applyPostgresMigrations } = await import('./migrations.js');
|
|
48
|
+
return applyPostgresMigrations(this.client, evaluationStoreMigrations(this.options), options);
|
|
38
49
|
}
|
|
39
50
|
async save(dataset) {
|
|
40
51
|
await this.client.query(`INSERT INTO ${this.table} (name, version, created_at, doc) VALUES ($1, $2, $3, $4::jsonb)
|
|
@@ -67,8 +78,9 @@ export class PostgresExperimentStore {
|
|
|
67
78
|
this.options = options;
|
|
68
79
|
this.table = quoteTable(options.experimentsTable ?? 'nexus_experiments');
|
|
69
80
|
}
|
|
70
|
-
async migrate() {
|
|
71
|
-
await
|
|
81
|
+
async migrate(options = {}) {
|
|
82
|
+
const { applyPostgresMigrations } = await import('./migrations.js');
|
|
83
|
+
return applyPostgresMigrations(this.client, evaluationStoreMigrations(this.options), options);
|
|
72
84
|
}
|
|
73
85
|
async save(experiment) {
|
|
74
86
|
await this.client.query(`INSERT INTO ${this.table} (id, name, dataset_name, dataset_version, started_at, doc)
|
package/dist/postgres/index.d.ts
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
|
|
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';
|
|
3
|
+
export { circuitStoreMigration, circuitStoreMigrations, PostgresCircuitStateStore, type PostgresCircuitStateStoreOptions, } from './circuits.js';
|
|
2
4
|
export { fromPostgresJs, type PostgresJsLike, type PostgresLikeClient } from './client.js';
|
|
3
|
-
export { evaluationStoreMigration, PostgresDatasetStore, type PostgresEvaluationStoreOptions, PostgresExperimentStore, } from './evaluate.js';
|
|
4
|
-
export {
|
|
5
|
-
export {
|
|
6
|
-
export {
|
|
7
|
-
export {
|
|
8
|
-
export {
|
|
5
|
+
export { evaluationStoreMigration, evaluationStoreMigrations, PostgresDatasetStore, type PostgresEvaluationStoreOptions, PostgresExperimentStore, } from './evaluate.js';
|
|
6
|
+
export { applyPostgresMigrations, type PostgresMigrateOptions, postgresMigrationStatus, } from './migrations.js';
|
|
7
|
+
export { operationStoreMigration, operationStoreMigrations, PostgresOperationStore, type PostgresOperationStoreOptions, } from './operations.js';
|
|
8
|
+
export { PostgresPromptStore, type PostgresPromptStoreOptions, promptStoreMigration, promptStoreMigrations, } from './prompts.js';
|
|
9
|
+
export { PostgresRollupStore, type PostgresRollupStoreOptions, rollupStoreMigration, rollupStoreMigrations, } from './rollups.js';
|
|
10
|
+
export { PostgresStore, type PostgresStoreOptions, storeMigration, storeMigrations } from './store.js';
|
|
11
|
+
export { PostgresTraceStore, type PostgresTraceStoreOptions, traceStoreMigration, traceStoreMigrations, } from './traces.js';
|
|
12
|
+
export { PostgresVectorStore, type PostgresVectorStoreOptions, vectorStoreMigration, vectorStoreMigrations, } from './vectors.js';
|
|
9
13
|
/** The Postgres adapters a migration can include. */
|
|
10
|
-
export type PostgresAdapter = 'operations' | 'store' | 'traces' | 'evaluation' | 'circuits' | 'prompts' | 'vectors';
|
|
11
|
-
/** Options for `postgresMigration()`. */
|
|
14
|
+
export type PostgresAdapter = 'operations' | 'store' | 'traces' | 'evaluation' | 'circuits' | 'prompts' | 'rollups' | 'vectors';
|
|
15
|
+
/** Options for `postgresMigrations()` and `postgresMigration()`. */
|
|
12
16
|
export interface PostgresMigrationOptions {
|
|
13
17
|
/**
|
|
14
18
|
* Adapters to include. Defaults to every one but `vectors`, which needs pgvector and
|
|
@@ -18,10 +22,27 @@ export interface PostgresMigrationOptions {
|
|
|
18
22
|
/** Enables pgvector for the long-term store, and sets the width of the `vectors` table. */
|
|
19
23
|
vectorDimensions?: number;
|
|
20
24
|
}
|
|
25
|
+
/** Options for `postgresMigration()`. */
|
|
26
|
+
export interface PostgresMigrationScriptOptions extends PostgresMigrationOptions {
|
|
27
|
+
/**
|
|
28
|
+
* Also creates `nexus_schema_migrations` and records every migration in the script as applied, so
|
|
29
|
+
* `nexus db status` agrees with a database built by the application's own tooling. Off by default.
|
|
30
|
+
*/
|
|
31
|
+
record?: boolean;
|
|
32
|
+
}
|
|
33
|
+
/** Every adapter, in the order a migration applies them. */
|
|
34
|
+
export declare const POSTGRES_ADAPTERS: readonly PostgresAdapter[];
|
|
35
|
+
/**
|
|
36
|
+
* The versioned migrations of the chosen adapters on their default tables, for
|
|
37
|
+
* `applyPostgresMigrations()`, `postgresMigrationStatus()`, and `nexus db migrate`. A store on a
|
|
38
|
+
* custom table migrates through its own `migrate()`.
|
|
39
|
+
*/
|
|
40
|
+
export declare function postgresMigrations(options?: PostgresMigrationOptions): SchemaMigration[];
|
|
21
41
|
/**
|
|
22
42
|
* The schema for the chosen adapters, as one SQL script.
|
|
23
43
|
*
|
|
24
44
|
* For migration tooling the application already has — Flyway, Prisma, a plain `psql -f` — which is
|
|
25
|
-
* usually where a schema change belongs.
|
|
45
|
+
* usually where a schema change belongs. Every statement is idempotent, so the script runs again
|
|
46
|
+
* safely after an upgrade. `nexus db sql` prints the same script.
|
|
26
47
|
*/
|
|
27
|
-
export declare function postgresMigration(options?:
|
|
48
|
+
export declare function postgresMigration(options?: PostgresMigrationScriptOptions): string;
|