@selvajs/solve 2.0.0-beta.8 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -11
- package/dist/abort-CNJ8Sn4g.js +13 -0
- package/dist/abort-CNJ8Sn4g.js.map +1 -0
- package/dist/client.d.ts +34 -135
- package/dist/client.js +968 -1
- package/dist/client.js.map +1 -1
- package/dist/{outcome-DsNmx27P.d.ts → outcome-Bk9mnMi0.d.ts} +9 -28
- package/dist/outcome-DNrffAXp.js +169 -0
- package/dist/outcome-DNrffAXp.js.map +1 -0
- package/dist/server.d.ts +98 -230
- package/dist/server.js +984 -1
- package/dist/server.js.map +1 -1
- package/dist/shared.d.ts +2 -2
- package/dist/shared.js +1 -1
- package/package.json +16 -41
- package/dist/client.cjs +0 -2
- package/dist/client.cjs.map +0 -1
- package/dist/client.d.cts +0 -429
- package/dist/outcome-BOrAeRAQ.js +0 -2
- package/dist/outcome-BOrAeRAQ.js.map +0 -1
- package/dist/outcome-DUHQoZqq.cjs +0 -2
- package/dist/outcome-DUHQoZqq.cjs.map +0 -1
- package/dist/outcome-DsNmx27P.d.cts +0 -92
- package/dist/server.cjs +0 -2
- package/dist/server.cjs.map +0 -1
- package/dist/server.d.cts +0 -419
- package/dist/shared.cjs +0 -1
- package/dist/shared.d.cts +0 -3
- package/dist/solve-input-CUjVGYPC.d.cts +0 -11
package/dist/server.d.ts
CHANGED
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
import { t as SolveInput } from "./solve-input-CUjVGYPC.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { UISchema } from "@selvajs/schemas";
|
|
3
|
+
import { GrasshopperClient, GrasshopperComputeResponse, SelvaEventTarget, SolveScheduler } from "@selvajs/compute/grasshopper";
|
|
4
|
+
import { DefinitionRef, DefinitionRef as DefinitionRef$1, ServerTiming, SolveDefinition } from "@selvajs/compute/core";
|
|
5
|
+
/** Rhino.Compute's own default `--timeout`, for a server that can't report its own. */
|
|
6
|
+
export declare const DEFAULT_SOLVE_DEADLINE_MS = 100000;
|
|
5
7
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
+
* Ceiling on any solve deadline, whatever the server reports. Bounds how long a request, its
|
|
9
|
+
* live-event token and a delegated session stay open; past an hour a solve belongs in a job.
|
|
8
10
|
*/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
export declare const MAX_SOLVE_DEADLINE_MS: number;
|
|
12
|
+
/** What Selva holds a solve to on one compute server. */
|
|
13
|
+
interface SolveLimits {
|
|
14
|
+
solveDeadlineMs: number;
|
|
15
|
+
/** `null` when the server didn't say: its own 413 is then the only check. */
|
|
16
|
+
maxRequestBytes: number | null;
|
|
17
|
+
/**
|
|
18
|
+
* Send a pointer to the server's cached definition instead of the `.gh`. Only on a server that
|
|
19
|
+
* answers a stale pointer with `definition_not_cached`: one that doesn't returns empty geometry.
|
|
20
|
+
*/
|
|
21
|
+
reuseDefinitionCache: boolean;
|
|
22
|
+
}
|
|
12
23
|
/** Minimal resolved-server shape the cache needs (a subset of the app's `ComputeServerConfig`). */
|
|
13
24
|
interface ResolvedServer {
|
|
14
25
|
id: string;
|
|
@@ -16,10 +27,11 @@ interface ResolvedServer {
|
|
|
16
27
|
/** Sent as the `RhinoComputeKey` header. */
|
|
17
28
|
apiKey?: string;
|
|
18
29
|
}
|
|
19
|
-
export declare function serverIdentity(server: Pick<ResolvedServer, 'id'>): ServerIdentity;
|
|
20
30
|
interface CachedClient {
|
|
21
31
|
client: GrasshopperClient;
|
|
22
32
|
scheduler: SolveScheduler;
|
|
33
|
+
/** Read from the server when the client was built; a changed server rebuilds the client. */
|
|
34
|
+
limits: SolveLimits;
|
|
23
35
|
}
|
|
24
36
|
/**
|
|
25
37
|
* Debug verbosity: `false` is silent, `true` gives concise cache/timing logs
|
|
@@ -27,70 +39,6 @@ interface CachedClient {
|
|
|
27
39
|
* dumps (incl. geometry) — a superset of `true`, not an independent setting.
|
|
28
40
|
*/
|
|
29
41
|
type ClientCacheDebug = boolean | 'verbose';
|
|
30
|
-
/** Config injected by the consuming app, so this module stays env-agnostic and testable. */
|
|
31
|
-
interface ClientCacheConfig {
|
|
32
|
-
/** Per-solve timeout forwarded to the scheduler (`ComputeLimits.solveDeadlineMs`). */
|
|
33
|
-
solveDeadlineMs: number;
|
|
34
|
-
cachesolve: boolean;
|
|
35
|
-
/** Only meaningful with `cachesolve`. */
|
|
36
|
-
cacheerroredsolves: boolean;
|
|
37
|
-
/** Reference large definitions by server cache key instead of re-uploading. */
|
|
38
|
-
reuseServerDefinitionCache: boolean;
|
|
39
|
-
/**
|
|
40
|
-
* Max solves that may wait in the FIFO queue, excluding in-flight solves
|
|
41
|
-
* (capped at `maxConcurrent`, itself driven by the server's probed child
|
|
42
|
-
* count). `0` = unbounded (`ComputeLimits.computeMaxQueueDepth`); a full
|
|
43
|
-
* queue rejects new solves with `QUEUE_FULL`.
|
|
44
|
-
*/
|
|
45
|
-
maxQueueDepth: number;
|
|
46
|
-
/**
|
|
47
|
-
* Max ms a solve may sit queued before executing; `0` = no deadline
|
|
48
|
-
* (`ComputeLimits.computeQueueWaitMs`). Too long a wait rejects with
|
|
49
|
-
* `QUEUE_TIMEOUT`.
|
|
50
|
-
*/
|
|
51
|
-
queueWaitMs: number;
|
|
52
|
-
/**
|
|
53
|
-
* Byte budget for this client's in-process solve cache. Applies per warm
|
|
54
|
-
* client — worst-case heap is this × `maxWarmComputeServers`. `0` disables
|
|
55
|
-
* the cache (`ComputeLimits.computeSolveCacheBytes`, env `COMPUTE_SOLVE_CACHE_MB`).
|
|
56
|
-
*/
|
|
57
|
-
responseCacheMaxBytes: number;
|
|
58
|
-
/**
|
|
59
|
-
* Largest compute response body read; past it the download is cancelled (`too_large`).
|
|
60
|
-
* Default: no limit.
|
|
61
|
-
*/
|
|
62
|
-
maxResponseBytes?: number;
|
|
63
|
-
debug: ClientCacheDebug;
|
|
64
|
-
/** Max distinct warm compute servers before the LRU evicts the oldest. Default 16. */
|
|
65
|
-
maxWarmComputeServers?: number;
|
|
66
|
-
/** Sink for the debug lines. `onDebugLog` only fires when `debug` is not `false`. */
|
|
67
|
-
onDebugLog?: (message: string) => void;
|
|
68
|
-
}
|
|
69
|
-
interface ClientCache {
|
|
70
|
-
/**
|
|
71
|
-
* Get (or create) the warm client + scheduler for a resolved compute server,
|
|
72
|
-
* keyed by its `id`. `definitionGuid`, when present, is stamped as the
|
|
73
|
-
* `X-Selva-Definition` header on this client's outbound solve/IO requests —
|
|
74
|
-
* inert routing/telemetry metadata until a pool router exists.
|
|
75
|
-
*/
|
|
76
|
-
getClient(server: ResolvedServer, opts?: {
|
|
77
|
-
definitionGuid?: string;
|
|
78
|
-
}): Promise<CachedClient>;
|
|
79
|
-
/** Dispose and drop the warm client for `id`, so the next request rebuilds against fresh connection details. */
|
|
80
|
-
evict(id: string | ServerIdentity): void;
|
|
81
|
-
/** Solve-cache counters summed across every warm client. Counters die with the client that owns them, so totals can fall over time. */
|
|
82
|
-
solveCacheStats(): SolveCacheStats;
|
|
83
|
-
/**
|
|
84
|
-
* Drop every retained solve result, keeping the warm clients (and their
|
|
85
|
-
* connections and server-side definition pointers) intact. Nothing expires
|
|
86
|
-
* these on its own — the byte budget is the only other pressure — so this is
|
|
87
|
-
* the operator's release valve when a definition's inputs no longer describe
|
|
88
|
-
* its output, e.g. it reads an external source that has since changed.
|
|
89
|
-
*/
|
|
90
|
-
clearSolveCaches(): void;
|
|
91
|
-
/** Dispose every warm client. Test seam / shutdown hook. */
|
|
92
|
-
disposeAll(): void;
|
|
93
|
-
}
|
|
94
42
|
interface SolveCacheStats {
|
|
95
43
|
warmClients: number;
|
|
96
44
|
entries: number;
|
|
@@ -100,7 +48,6 @@ interface SolveCacheStats {
|
|
|
100
48
|
/** Entries dropped under size/byte pressure (not replacement or manual clears). */
|
|
101
49
|
evictions: number;
|
|
102
50
|
}
|
|
103
|
-
export declare function createClientCache(config: ClientCacheConfig): ClientCache;
|
|
104
51
|
/**
|
|
105
52
|
* In-process cache of `.gh` definition bytes, keyed by immutable **version id**.
|
|
106
53
|
*
|
|
@@ -133,7 +80,7 @@ interface ByteRefOutcome {
|
|
|
133
80
|
/** A definition reference shaped for `@selvajs/compute`'s `DefinitionRef`. */
|
|
134
81
|
interface ByteCacheRef {
|
|
135
82
|
key: string;
|
|
136
|
-
load: () => Promise<Uint8Array>;
|
|
83
|
+
load: (signal?: AbortSignal) => Promise<Uint8Array>;
|
|
137
84
|
outcome: ByteRefOutcome;
|
|
138
85
|
}
|
|
139
86
|
interface ByteCacheStats {
|
|
@@ -143,65 +90,23 @@ interface ByteCacheStats {
|
|
|
143
90
|
entries: number;
|
|
144
91
|
bytes: number;
|
|
145
92
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
93
|
+
/** A pre-solve prep sub-phase: `[label, ms]`, surfaced as a `p_*` Server-Timing entry. */
|
|
94
|
+
type PrepMark = [string, number];
|
|
95
|
+
interface CacheVerdict {
|
|
96
|
+
fromCache: boolean;
|
|
97
|
+
definitionReuploaded?: boolean;
|
|
150
98
|
}
|
|
151
99
|
/**
|
|
152
|
-
*
|
|
153
|
-
*
|
|
100
|
+
* skipped = scheduler never materialized bytes (pointer-known solve, the whole point of this
|
|
101
|
+
* path); hit = warm byte cache; miss = fell through to storage.
|
|
154
102
|
*/
|
|
155
|
-
|
|
103
|
+
type DefBytesVerdict = 'skipped' | 'hit' | 'miss';
|
|
156
104
|
/** Compute-response contract version. Bump (and document the change) whenever the envelope's shape changes in a way a consumer could observe. */
|
|
157
105
|
export declare const COMPUTE_CONTRACT_VERSION: 1;
|
|
158
106
|
export declare const COMPUTE_VERSION_HEADER = "X-Selva-Compute-Version";
|
|
159
|
-
|
|
160
|
-
interface SolvePipelineArgs {
|
|
161
|
-
/**
|
|
162
|
-
* Raw `.gh` bytes, or a byte-cache `DefinitionRef` whose bytes the scheduler
|
|
163
|
-
* materializes only when an upload is unavoidable — a pointer-known solve
|
|
164
|
-
* moves zero bytes.
|
|
165
|
-
*/
|
|
166
|
-
definitionSource: SolveDefinition$1;
|
|
167
|
-
/** Mutable load outcome for a `DefinitionRef` source, so the `def_bytes` Server-Timing verdict can be emitted. Omit for raw-bytes solves. */
|
|
168
|
-
byteRefOutcome?: ByteRefOutcome;
|
|
169
|
-
/** Persisted input params; only those with a `paramType` are sent to the solve. */
|
|
170
|
-
inputs: PipelineInput[];
|
|
171
|
-
/**
|
|
172
|
-
* A tree the caller already built with {@link buildSolveInputTree}; skips the
|
|
173
|
-
* pipeline's own build and solves this object directly.
|
|
174
|
-
*
|
|
175
|
-
* A caller coalescing concurrent solves needs this: a single-flight key
|
|
176
|
-
* derived from raw `{inputs, values}` would split two requests that transform
|
|
177
|
-
* to the same tree, which is the identity the scheduler actually caches on.
|
|
178
|
-
*/
|
|
179
|
-
inputTree?: DataTree[];
|
|
180
|
-
/** User-chosen values keyed by input id; missing keys fall back to the schema default. */
|
|
181
|
-
values: Record<string, unknown>;
|
|
182
|
-
client: CachedClient;
|
|
183
|
-
responseMaxBytes: number;
|
|
184
|
-
/** Only phrases the timeout message — the scheduler enforces the deadline itself. */
|
|
185
|
-
solveDeadlineMs: number;
|
|
186
|
-
/** Client's `Accept-Encoding`; gzip is applied only when it advertises `gzip`. */
|
|
187
|
-
acceptEncoding: string;
|
|
188
|
-
/** Per-solve live-event callback the compute server hands to the definition; absent when the caller opened no stream. */
|
|
189
|
-
selvaEvents?: SelvaEventTarget;
|
|
190
|
-
/**
|
|
191
|
-
* Forwarded to the scheduler so a client disconnect cancels the upstream
|
|
192
|
-
* compute call. Its `aborted` flag also distinguishes a client disconnect
|
|
193
|
-
* from the scheduler's own deadline firing.
|
|
194
|
-
*/
|
|
195
|
-
signal: AbortSignal;
|
|
196
|
-
/** Wall-clock origin (`performance.now()` at the top of the request) so `load`/`total` phase timings line up with the caller's pre-solve prep. */
|
|
197
|
-
loadStartMs: number;
|
|
198
|
-
/** Pre-solve "load" phase duration the caller already measured (auth + DB + fetch). */
|
|
199
|
-
defLoadMs: number;
|
|
200
|
-
/** Pre-solve prep sub-phase marks (`[label, ms]`), surfaced verbatim as `p_*` Server-Timing entries. */
|
|
201
|
-
prepMarks?: [string, number][];
|
|
202
|
-
}
|
|
203
|
-
/** Phase timings the pipeline measured; the caller uses them for debug logging. */
|
|
107
|
+
/** What the `Server-Timing` header carries for one caller, as data: read this, don't parse that. */
|
|
204
108
|
interface SolvePhaseMetrics {
|
|
109
|
+
defLoadMs: number;
|
|
205
110
|
treeBuildMs: number;
|
|
206
111
|
solveMs: number;
|
|
207
112
|
serializeMs: number;
|
|
@@ -210,6 +115,11 @@ interface SolvePhaseMetrics {
|
|
|
210
115
|
serializedBytes: number;
|
|
211
116
|
/** Null when compression was skipped. */
|
|
212
117
|
compressedBytes: number | null;
|
|
118
|
+
/** The compute server's own timing; null when it reports none. */
|
|
119
|
+
rhino: ServerTiming | null;
|
|
120
|
+
settle: CacheVerdict;
|
|
121
|
+
/** Absent for raw-bytes solves. */
|
|
122
|
+
defBytes?: DefBytesVerdict;
|
|
213
123
|
}
|
|
214
124
|
/** A ready-to-send response: body + headers + the solve result + phase metrics. */
|
|
215
125
|
interface SolveEnvelope {
|
|
@@ -220,20 +130,21 @@ interface SolveEnvelope {
|
|
|
220
130
|
result: GrasshopperComputeResponse;
|
|
221
131
|
metrics: SolvePhaseMetrics;
|
|
222
132
|
}
|
|
133
|
+
/** Whether an `Accept-Encoding` header takes gzip. `gzip;q=0` is a client refusing it. */
|
|
134
|
+
export declare function acceptsGzip(acceptEncoding: string): boolean;
|
|
223
135
|
/**
|
|
224
|
-
* `ok` carries the envelope; every other variant names an expected failure
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
* `durationMs` on error variants is the solve wall time up to the failure, for
|
|
228
|
-
* the metric record.
|
|
136
|
+
* `ok` carries the envelope; every other variant names an expected failure:
|
|
137
|
+
* `SolveEngine.toWebResponse` maps each to a status. `durationMs` on error variants is the solve
|
|
138
|
+
* wall time up to the failure, for the metric record.
|
|
229
139
|
*/
|
|
230
|
-
type
|
|
140
|
+
type SolveEngineOutcome = {
|
|
231
141
|
kind: 'ok';
|
|
232
142
|
envelope: SolveEnvelope;
|
|
233
143
|
solveMs: number;
|
|
234
144
|
errorCount: number;
|
|
235
145
|
warningCount: number;
|
|
236
|
-
} |
|
|
146
|
+
} | SolveFailure;
|
|
147
|
+
type SolveFailure = {
|
|
237
148
|
kind: 'timeout';
|
|
238
149
|
durationMs: number;
|
|
239
150
|
message: string;
|
|
@@ -243,11 +154,21 @@ type SolveOutcome = {
|
|
|
243
154
|
} | {
|
|
244
155
|
kind: 'too_large';
|
|
245
156
|
} |
|
|
246
|
-
/**
|
|
157
|
+
/** The compute server refused the request body (its `RHINO_COMPUTE_MAX_REQUEST_SIZE`). */
|
|
158
|
+
{
|
|
159
|
+
kind: 'request_too_large';
|
|
160
|
+
durationMs: number;
|
|
161
|
+
message: string;
|
|
162
|
+
} |
|
|
163
|
+
/**
|
|
164
|
+
* Retryable: no result, through no fault of the request, and `retryAfterSeconds` is a backoff
|
|
165
|
+
* hint. Scheduler backpressure rejected the solve before it ran (`queue_full`,
|
|
166
|
+
* `queue_timeout`), or its client was shut down under it (`interrupted`).
|
|
167
|
+
*/
|
|
247
168
|
{
|
|
248
169
|
kind: 'shed';
|
|
249
170
|
durationMs: number;
|
|
250
|
-
reason: 'queue_full' | 'queue_timeout';
|
|
171
|
+
reason: 'queue_full' | 'queue_timeout' | 'interrupted';
|
|
251
172
|
retryAfterSeconds: number;
|
|
252
173
|
message: string;
|
|
253
174
|
} | {
|
|
@@ -255,73 +176,13 @@ type SolveOutcome = {
|
|
|
255
176
|
durationMs: number;
|
|
256
177
|
error: unknown;
|
|
257
178
|
};
|
|
258
|
-
export declare function runSolvePipeline(args: SolvePipelineArgs): Promise<SolveOutcome>;
|
|
259
|
-
/**
|
|
260
|
-
* Re-key a coalesced envelope to a single waiter's `Accept-Encoding`.
|
|
261
|
-
*
|
|
262
|
-
* The single-flight coalescer runs ONE pipeline execution for N identical
|
|
263
|
-
* concurrent solves and hands every waiter the same {@link SolveEnvelope},
|
|
264
|
-
* baked from the FIRST caller's `Accept-Encoding`. A later waiter with a
|
|
265
|
-
* different `Accept-Encoding` would otherwise get a body labelled with the
|
|
266
|
-
* wrong encoding — `Vary` can't help here, since it's one shared object, not a
|
|
267
|
-
* cache lookup. Encoding is deliberately left out of the coalesce key so mixed
|
|
268
|
-
* clients still coalesce; this adapts the shared result to each waiter instead.
|
|
269
|
-
*
|
|
270
|
-
* Only the correctness-critical direction is adapted: a gzip envelope served to
|
|
271
|
-
* a non-gzip waiter is gunzipped back to JSON. The reverse (plain JSON to a
|
|
272
|
-
* gzip-capable waiter) is left uncompressed — correct, just not maximally small.
|
|
273
|
-
*/
|
|
274
|
-
export declare function adaptEnvelopeToEncoding(envelope: SolveEnvelope, acceptEncoding: string): {
|
|
275
|
-
body: string | Uint8Array;
|
|
276
|
-
headers: Record<string, string>;
|
|
277
|
-
};
|
|
278
|
-
/** The input tree a solve sends: each input's value, or its schema default when it has none. */
|
|
279
|
-
export declare function buildSolveInputTree(inputs: SolveInput[], values: Record<string, unknown>): DataTree[];
|
|
280
|
-
/**
|
|
281
|
-
* In-process single-flight — dogpile protection for every solve.
|
|
282
|
-
*
|
|
283
|
-
* Always on, not gated behind a result cache being configured: the dogpile is worst
|
|
284
|
-
* when nothing else is caching, since N concurrent identical solves each pay a full
|
|
285
|
-
* Rhino round trip (the scheduler doesn't coalesce in-flight requests itself, and
|
|
286
|
-
* Rhino's `cachesolve` still costs a round trip per repeat). An earlier version
|
|
287
|
-
* gated this on cache config and so disabled it in exactly the deployments most
|
|
288
|
-
* exposed to a cold-key stampede — hot public definition plus a deploy.
|
|
289
|
-
*
|
|
290
|
-
* Per app instance, above `ISolveResultCache`. No cross-instance lease (Redis
|
|
291
|
-
* `SET NX`) yet.
|
|
292
|
-
*
|
|
293
|
-
* The shared promise resolves to one value for every waiter, so `work` must return
|
|
294
|
-
* something safe to share by reference — the solve pipeline's envelope qualifies
|
|
295
|
-
* because the app serializes it per response.
|
|
296
|
-
*/
|
|
297
|
-
interface SolveCacheSingleFlight {
|
|
298
|
-
/**
|
|
299
|
-
* Coalesces concurrent calls under the same key: the first caller runs `work`,
|
|
300
|
-
* later callers for that key await the same promise, and the key frees as soon
|
|
301
|
-
* as it settles.
|
|
302
|
-
*
|
|
303
|
-
* `onWaiterJoined` fires only on the owner's call, only while `work` is still
|
|
304
|
-
* running, each time another caller joins. Ownership changes what the owner's
|
|
305
|
-
* abort signal should mean: a solo run can cancel on its own client's
|
|
306
|
-
* disconnect, but a shared run can't without 499-ing every waiter.
|
|
307
|
-
*/
|
|
308
|
-
run<T>(key: string, work: () => Promise<T>, onWaiterJoined?: () => void): Promise<T>;
|
|
309
|
-
inFlight(): number;
|
|
310
|
-
}
|
|
311
|
-
interface SolveCacheSingleFlightOptions {
|
|
312
|
-
onJoin?: (key: string) => void;
|
|
313
|
-
}
|
|
314
|
-
export declare function createSolveCacheSingleFlight(options?: SolveCacheSingleFlightOptions): SolveCacheSingleFlight;
|
|
315
179
|
/**
|
|
316
180
|
* Subset of `ComputeLimits` (`@selvajs/server/compute`) the engine needs.
|
|
317
181
|
* Pass the resolved object through as-is — extra fields are ignored.
|
|
318
182
|
*/
|
|
319
183
|
interface SolveEngineLimits {
|
|
320
|
-
solveDeadlineMs: number;
|
|
321
184
|
computeResponseMaxBytes: number;
|
|
322
|
-
computeReuseDefinitionCache: boolean;
|
|
323
185
|
computeServerCachesolve: boolean;
|
|
324
|
-
computeCacheErroredSolves: boolean;
|
|
325
186
|
computeMaxQueueDepth: number;
|
|
326
187
|
computeQueueWaitMs: number;
|
|
327
188
|
computeDefinitionCacheBytes: number;
|
|
@@ -329,26 +190,20 @@ interface SolveEngineLimits {
|
|
|
329
190
|
}
|
|
330
191
|
interface SolveEngineOptions {
|
|
331
192
|
limits: SolveEngineLimits;
|
|
332
|
-
|
|
333
|
-
/** Max distinct warm compute servers before the LRU evicts the oldest. Default 16. */
|
|
193
|
+
/** Max distinct warm compute servers before the LRU evicts the oldest. */
|
|
334
194
|
maxWarmComputeServers?: number;
|
|
335
195
|
/** Concise cache/timing logs when truthy; `'verbose'` also dumps full lib-level requests/responses. Default off. */
|
|
336
196
|
debug?: ClientCacheDebug;
|
|
197
|
+
/** Sink for the debug lines. Without it they go nowhere. */
|
|
337
198
|
onDebugLog?: (message: string) => void;
|
|
338
199
|
/** Fired when a caller joins an already-in-flight solve instead of running its own. */
|
|
339
200
|
onSolveCoalesced?: (key: string) => void;
|
|
340
201
|
}
|
|
341
202
|
/**
|
|
342
|
-
*
|
|
343
|
-
*
|
|
344
|
-
* obtained ahead of time from `engine.definitionRef()` (e.g. to read bytes for
|
|
345
|
-
* schema extraction before solving) is passed through as-is — detected by its
|
|
346
|
-
* `outcome` field, which a plain `DefinitionRef` never has.
|
|
203
|
+
* A `ByteCacheRef` obtained ahead of time from `engine.definitionRef()` (e.g. to
|
|
204
|
+
* read bytes for schema extraction before solving) is passed through as-is.
|
|
347
205
|
*/
|
|
348
|
-
type SolveEngineDefinitionSource = Uint8Array | string | DefinitionRef$1 | ByteCacheRef
|
|
349
|
-
versionId: string;
|
|
350
|
-
load: () => Promise<Uint8Array>;
|
|
351
|
-
};
|
|
206
|
+
type SolveEngineDefinitionSource = Uint8Array | string | DefinitionRef$1 | ByteCacheRef;
|
|
352
207
|
interface SolveEngineSolveArgs {
|
|
353
208
|
server: ResolvedServer;
|
|
354
209
|
definitionSource: SolveEngineDefinitionSource;
|
|
@@ -359,27 +214,26 @@ interface SolveEngineSolveArgs {
|
|
|
359
214
|
* Ignored for the other source forms.
|
|
360
215
|
*/
|
|
361
216
|
definitionKey?: string;
|
|
362
|
-
|
|
217
|
+
/**
|
|
218
|
+
* The definition's inputs, from the schema you stored, never from the request: `id`, `nickname`,
|
|
219
|
+
* `paramType` and the bounds decide what reaches the definition, so a body that supplies them
|
|
220
|
+
* can drop a limit or fill a slot your host reserved.
|
|
221
|
+
*/
|
|
222
|
+
inputs: SolveInput[];
|
|
363
223
|
values: Record<string, unknown>;
|
|
364
224
|
signal: AbortSignal;
|
|
365
225
|
acceptEncoding?: string;
|
|
366
|
-
/**
|
|
226
|
+
/**
|
|
227
|
+
* Stamped as `X-Selva-Definition` when this solve builds the server's warm client. The header
|
|
228
|
+
* is fixed per client, so later solves on that server carry the first definition's guid.
|
|
229
|
+
*/
|
|
367
230
|
definitionGuid?: string;
|
|
368
231
|
loadStartMs?: number;
|
|
369
232
|
defLoadMs?: number;
|
|
370
|
-
prepMarks?: [
|
|
371
|
-
/**
|
|
372
|
-
* Per-solve live-event callback. A coalesced waiter shares the first caller's
|
|
373
|
-
* compute call, so only that caller's target reaches the definition; the
|
|
374
|
-
* others still get the server-emitted start/end events on their own stream.
|
|
375
|
-
*/
|
|
233
|
+
prepMarks?: PrepMark[];
|
|
234
|
+
/** Per-solve live-event callback. A solve carrying one runs its own compute call, never a shared one. */
|
|
376
235
|
selvaEvents?: SelvaEventTarget;
|
|
377
236
|
}
|
|
378
|
-
interface FrameworkAgnosticResponse {
|
|
379
|
-
status: number;
|
|
380
|
-
headers: Record<string, string>;
|
|
381
|
-
body: string | Uint8Array;
|
|
382
|
-
}
|
|
383
237
|
interface SolveEngineStats {
|
|
384
238
|
client: SolveCacheStats;
|
|
385
239
|
definitionBytes: ByteCacheStats;
|
|
@@ -392,11 +246,17 @@ export declare class SolveEngine {
|
|
|
392
246
|
private readonly clientCache;
|
|
393
247
|
private readonly byteCache;
|
|
394
248
|
private readonly singleFlight;
|
|
249
|
+
private readonly clientGenerations;
|
|
250
|
+
private lastClientGeneration;
|
|
395
251
|
constructor(options: SolveEngineOptions);
|
|
396
252
|
getClient(server: ResolvedServer, opts?: {
|
|
397
253
|
definitionGuid?: string;
|
|
398
254
|
}): Promise<CachedClient>;
|
|
399
|
-
definitionRef(versionId: string, load: () => Promise<Uint8Array>): ByteCacheRef;
|
|
255
|
+
definitionRef(versionId: string, load: (signal: AbortSignal) => Promise<Uint8Array>): ByteCacheRef;
|
|
256
|
+
/**
|
|
257
|
+
* Drops the warm client for `id`; call it when the server's URL or key changes. Solves already
|
|
258
|
+
* running finish on the old connection details first, so a revoked key stays in use until then.
|
|
259
|
+
*/
|
|
400
260
|
evictServer(id: string): void;
|
|
401
261
|
clearSolveCaches(): void;
|
|
402
262
|
/**
|
|
@@ -405,15 +265,23 @@ export declare class SolveEngine {
|
|
|
405
265
|
*/
|
|
406
266
|
clearDefinitionCache(): void;
|
|
407
267
|
stats(): SolveEngineStats;
|
|
408
|
-
solve(args: SolveEngineSolveArgs): Promise<
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
268
|
+
solve(args: SolveEngineSolveArgs): Promise<SolveEngineOutcome>;
|
|
269
|
+
/**
|
|
270
|
+
* The response for an outcome; the mapping from outcome to status lives here. Throws
|
|
271
|
+
* `compute_error`'s error: what it means for the caller is the host's to decide.
|
|
272
|
+
*/
|
|
273
|
+
toWebResponse(outcome: SolveEngineOutcome): Response;
|
|
274
|
+
/**
|
|
275
|
+
* Part of the coalesce key: after an eviction the id stays and the client changes, and a new
|
|
276
|
+
* caller joining a draining flight would get an answer from the old URL or key.
|
|
277
|
+
*/
|
|
278
|
+
private clientGeneration;
|
|
416
279
|
private resolveDefinitionSource;
|
|
417
280
|
}
|
|
418
|
-
|
|
281
|
+
/**
|
|
282
|
+
* What `SolveEngine.solve` takes as `inputs`, from a schema the host stored. The bounds live on
|
|
283
|
+
* the number widgets in the layout, not on `schema.inputs`, so without them nothing clamps.
|
|
284
|
+
*/
|
|
285
|
+
export declare function solveInputsFromSchema(schema: UISchema): SolveInput[];
|
|
286
|
+
export type { ByteCacheRef, ByteCacheStats, ByteRefOutcome, CachedClient, DefinitionRef, ResolvedServer, SolveCacheStats, SolveDefinition, SolveEngineDefinitionSource, SolveEngineLimits, SolveEngineOptions, SolveEngineOutcome, SolveEngineSolveArgs, SolveEngineStats, SolveEnvelope, SolveInput, SolveLimits, SolvePhaseMetrics };
|
|
419
287
|
//# sourceMappingURL=server.d.ts.map
|