@selvajs/server 0.2.1 → 1.0.0-beta.1

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.
Files changed (46) hide show
  1. package/README.md +23 -16
  2. package/dist/compute/index.d.ts +0 -8
  3. package/dist/compute/index.d.ts.map +1 -1
  4. package/dist/compute/index.js +12 -9
  5. package/dist/compute/index.js.map +1 -1
  6. package/dist/compute/limits.d.ts +38 -54
  7. package/dist/compute/limits.d.ts.map +1 -1
  8. package/dist/compute/limits.js +39 -16
  9. package/dist/compute/limits.js.map +1 -1
  10. package/package.json +6 -12
  11. package/dist/compute/client-cache.d.ts +0 -135
  12. package/dist/compute/client-cache.d.ts.map +0 -1
  13. package/dist/compute/client-cache.js +0 -176
  14. package/dist/compute/client-cache.js.map +0 -1
  15. package/dist/compute/definition-byte-cache.d.ts +0 -85
  16. package/dist/compute/definition-byte-cache.d.ts.map +0 -1
  17. package/dist/compute/definition-byte-cache.js +0 -110
  18. package/dist/compute/definition-byte-cache.js.map +0 -1
  19. package/dist/compute/memory-solve-cache.d.ts +0 -58
  20. package/dist/compute/memory-solve-cache.d.ts.map +0 -1
  21. package/dist/compute/memory-solve-cache.js +0 -0
  22. package/dist/compute/memory-solve-cache.js.map +0 -1
  23. package/dist/compute/solve-cache-envelope.d.ts +0 -53
  24. package/dist/compute/solve-cache-envelope.d.ts.map +0 -1
  25. package/dist/compute/solve-cache-envelope.js +0 -66
  26. package/dist/compute/solve-cache-envelope.js.map +0 -1
  27. package/dist/compute/solve-cache-key.d.ts +0 -64
  28. package/dist/compute/solve-cache-key.d.ts.map +0 -1
  29. package/dist/compute/solve-cache-key.js +0 -51
  30. package/dist/compute/solve-cache-key.js.map +0 -1
  31. package/dist/compute/solve-cache-single-flight.d.ts +0 -42
  32. package/dist/compute/solve-cache-single-flight.d.ts.map +0 -1
  33. package/dist/compute/solve-cache-single-flight.js +0 -50
  34. package/dist/compute/solve-cache-single-flight.js.map +0 -1
  35. package/dist/compute/solve-pipeline.d.ts +0 -221
  36. package/dist/compute/solve-pipeline.d.ts.map +0 -1
  37. package/dist/compute/solve-pipeline.js +0 -419
  38. package/dist/compute/solve-pipeline.js.map +0 -1
  39. package/dist/compute/transform-input.d.ts +0 -20
  40. package/dist/compute/transform-input.d.ts.map +0 -1
  41. package/dist/compute/transform-input.js +0 -62
  42. package/dist/compute/transform-input.js.map +0 -1
  43. package/dist/index.d.ts +0 -27
  44. package/dist/index.d.ts.map +0 -1
  45. package/dist/index.js +0 -27
  46. package/dist/index.js.map +0 -1
@@ -1,176 +0,0 @@
1
- import { GrasshopperClient, enableDebugLogging } from '@selvajs/compute';
2
- /** Derive the opaque cache identity from a resolved server. Identity is the `id`. */
3
- export function serverIdentity(server) {
4
- return server.id;
5
- }
6
- const DEFAULT_MAX_CACHED_CLIENTS = 16;
7
- /**
8
- * Build a per-server warm-client cache. Each cache owns its own LRU `Map` keyed
9
- * on server `id`.
10
- */
11
- export function createClientCache(config) {
12
- const maxCachedClients = config.maxCachedClients ?? DEFAULT_MAX_CACHED_CLIENTS;
13
- const cache = new Map();
14
- if (config.debugVerbose)
15
- enableDebugLogging();
16
- const debugLog = (message) => {
17
- if (config.debug)
18
- config.onDebugLog?.(message);
19
- };
20
- async function build(server, definitionGuid) {
21
- // Holders for per-request results from the client/scheduler callbacks; the
22
- // caller reads them right after each solve resolves to build Server-Timing,
23
- // using the seq counters to detect (and drop) ambiguous concurrent writes.
24
- const rhinoTiming = { last: null, seq: 0 };
25
- const solveMeta = { last: null, seq: 0 };
26
- const clientConfig = {
27
- serverUrl: server.serverUrl,
28
- apiKey: server.apiKey,
29
- // Lib-level debug is the verbose one (full payload logs); keep it on the
30
- // verbose flag so the concise cache logs can run without the noise.
31
- debug: config.debugVerbose,
32
- // Ask Rhino.Compute to cache solve results and return them on identical
33
- // repeats (same definition + inputs), skipping the solve.
34
- cachesolve: config.cachesolve,
35
- // Opt-in: also cache solves that reported GH errors.
36
- cacheerroredsolves: config.cacheerroredsolves,
37
- // DEBUG: the server's per-request timing breakdown, which exposes the two
38
- // SERVER-side caches at once — definition cache (pointer reuse) via
39
- // `decode`, solve cache (cachesolve) via `solve`. Flagged below so the
40
- // contrast is obvious in the logs.
41
- onServerTiming: (t) => {
42
- const decode = t.decode ?? 0;
43
- const solve = t.solve ?? 0;
44
- const encode = t.encode ?? 0;
45
- // Always recorded (cheap): the caller reads this after scheduler.solve.
46
- rhinoTiming.seq += 1;
47
- rhinoTiming.last = { decode, solve, encode };
48
- if (!config.debug)
49
- return;
50
- // Heuristic thresholds: a genuine parse/solve is many ms; a cache hit
51
- // is sub-millisecond. Only meaningful relative to the first (cold) solve.
52
- const defCache = decode <= 1 ? 'HIT (definition reused, no re-upload/parse)' : 'miss (full parse)';
53
- const solveCache = config.cachesolve && solve <= 1
54
- ? 'HIT (cached result, solve skipped)'
55
- : config.cachesolve
56
- ? 'miss (solved fresh)'
57
- : 'off';
58
- debugLog(`[Compute/rhino-cache] decode=${decode}ms solve=${solve}ms encode=${encode}ms ` +
59
- `| definition-cache: ${defCache} | solve-cache (cachesolve): ${solveCache}`);
60
- }
61
- };
62
- // `X-Selva-Definition` on the wire (ADR 0004 D2). Baked at client-create
63
- // time because the scheduler has no per-request header hook — inert for a
64
- // single-member "pool", useful in compute-side access logs immediately.
65
- if (definitionGuid) {
66
- clientConfig.headers = { 'X-Selva-Definition': definitionGuid };
67
- }
68
- const client = await GrasshopperClient.create(clientConfig);
69
- const scheduler = client.createScheduler({
70
- mode: 'queue',
71
- // Queue mode defaults maxConcurrent to 1, which would serialize every
72
- // solve on this server through a single slot while the compute VM's
73
- // other compute.geometry children idle (audit B6) — always pass it.
74
- maxConcurrent: config.maxConcurrentSolves,
75
- // Backpressure (audit B7). The scheduler treats undefined as
76
- // unbounded/no-deadline, so map our `0`-means-off convention to undefined
77
- // rather than passing 0 (which would shed EVERY queued solve).
78
- maxQueueDepth: config.maxQueueDepth || undefined,
79
- queueWaitMs: config.queueWaitMs || undefined,
80
- timeoutMs: config.maxSolveDurationMs,
81
- // L1 response cache: count-capped AND byte-budgeted (audit C2) — entries
82
- // can be as large as the response cap allows, so the count alone would
83
- // let 20 × max-response-size pin gigabytes per warm client. `0` = off.
84
- cache: config.responseCacheMaxBytes > 0
85
- ? { maxEntries: 20, ttlMs: 5 * 60_000, maxBytes: config.responseCacheMaxBytes }
86
- : false,
87
- // Solve large definitions by server cache-key (pointer) instead of
88
- // re-uploading the full binary every solve. On a stale-pointer miss the
89
- // client transparently re-uploads.
90
- reuseServerDefinitionCache: config.reuseServerDefinitionCache,
91
- // DEBUG: observe the in-process response cache. `fromCache === true` means
92
- // this solve was served from the app's own cache — Rhino.Compute was never
93
- // called. `false` means it went to the compute server.
94
- onSettle: (_ctx, result) => {
95
- // Count EVERY settle (success or error) so the caller's attribution
96
- // guard sees all concurrent activity, not just successful writes.
97
- solveMeta.seq += 1;
98
- if (result.status !== 'success')
99
- return;
100
- // Always recorded (cheap): the caller surfaces these on Server-Timing.
101
- solveMeta.last = {
102
- fromCache: result.fromCache === true,
103
- definitionReuploaded: result.definitionReuploaded
104
- };
105
- if (!config.debug)
106
- return;
107
- debugLog(`[Compute/selva-cache] ${result.fromCache ? 'HIT — served from cache (no compute call)' : 'miss — went to Rhino.Compute'} (${Math.round(result.durationMs)}ms)`);
108
- // Definition-cache verdict for a real compute call (not a cache HIT).
109
- if (!result.fromCache) {
110
- debugLog(result.definitionReuploaded === true
111
- ? '[Compute/def-cache] miss — definition RE-UPLOADED (pointer was cold/stale)'
112
- : result.definitionReuploaded === false
113
- ? '[Compute/def-cache] HIT — definition reused from server cache (no upload)'
114
- : '[Compute/def-cache] n/a — reuse disabled or non-reusable definition');
115
- }
116
- // Surface real GH errors when present. Whether an errored solve is cached is
117
- // config-gated by `cacheerroredsolves` (default false → errored solves are
118
- // re-run each time; true → the error result is cached like any other, per R2).
119
- if (!result.fromCache) {
120
- const errs = result.response?.errors;
121
- const errCount = Array.isArray(errs) ? errs.length : 0;
122
- if (errCount > 0) {
123
- const cacheNote = config.cacheerroredsolves
124
- ? 'cached (cacheerroredsolves on)'
125
- : 'not cached (cacheerroredsolves off) — re-run until fixed';
126
- debugLog(`[Compute/rhino-cache] ${errCount} GH error(s); ${cacheNote}. First: ${JSON.stringify(errs[0])}`);
127
- }
128
- }
129
- }
130
- });
131
- return { client, scheduler, rhinoTiming, solveMeta };
132
- }
133
- return {
134
- async getClient(server, opts) {
135
- const key = server.id;
136
- const existing = cache.get(key);
137
- if (existing) {
138
- // Refresh LRU position.
139
- cache.delete(key);
140
- cache.set(key, existing);
141
- return existing;
142
- }
143
- // A build is a Rhino.Compute handshake — expensive, and repeated builds for
144
- // the same id mean churn (LRU thrash or config-rotation evictions).
145
- debugLog(`[Compute/client-cache] miss — building warm client for server ${key}`);
146
- const entry = await build(server, opts?.definitionGuid);
147
- // Evict the least-recently-used entry before inserting when at capacity.
148
- if (cache.size >= maxCachedClients) {
149
- const oldestKey = cache.keys().next().value;
150
- if (oldestKey !== undefined) {
151
- debugLog(`[Compute/client-cache] LRU evicted warm client for server ${oldestKey} (cap ${maxCachedClients})`);
152
- cache.get(oldestKey)?.scheduler.dispose();
153
- cache.delete(oldestKey);
154
- }
155
- }
156
- cache.set(key, entry);
157
- return entry;
158
- },
159
- evict(id) {
160
- const key = id;
161
- const entry = cache.get(key);
162
- if (entry) {
163
- debugLog(`[Compute/client-cache] evicted warm client for server ${key} (config change)`);
164
- entry.scheduler.dispose();
165
- cache.delete(key);
166
- }
167
- },
168
- disposeAll() {
169
- debugLog(`[Compute/client-cache] disposing all ${cache.size} warm client(s)`);
170
- for (const entry of cache.values())
171
- entry.scheduler.dispose();
172
- cache.clear();
173
- }
174
- };
175
- }
176
- //# sourceMappingURL=client-cache.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"client-cache.js","sourceRoot":"","sources":["../../src/compute/client-cache.ts"],"names":[],"mappings":"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"}
@@ -1,85 +0,0 @@
1
- /**
2
- * In-process cache of `.gh` definition bytes, keyed by immutable **version id**.
3
- *
4
- * The solve path used to eagerly `storage.get(fileKey)` on every request — moving
5
- * multi-MB definition bytes off disk/S3 into memory before the scheduler could
6
- * decide it didn't need them (the compute server already holds the definition via
7
- * the pointer/`reuseServerDefinitionCache` fast path). This cache turns that eager
8
- * read into a lazy `DefinitionRef.load()`: the scheduler calls `load()` ONLY when
9
- * an upload is unavoidable, and even then a warm entry serves the bytes without
10
- * touching storage. A pointer-known re-solve therefore moves ZERO definition bytes.
11
- *
12
- * Keying discipline (the whole reason this module exists):
13
- * - The key is the **version id**, an immutable UUID — never a `fileKey`, which
14
- * a delete-latest-then-reupload can REUSE for different content (see the
15
- * monotonic-version-number fix). A reused key would serve one version's bytes
16
- * for another: silent cache poisoning with no diagnostic. Callers pass
17
- * `version.id`, and the returned `DefinitionRef.key` is that same id, so the
18
- * scheduler's own result/pointer cache keys on the same immutable identity.
19
- *
20
- * Eviction:
21
- * - LRU by **total byte budget**, not entry count — definitions range from tens
22
- * of KB to hundreds of MB, so an entry-count cap would either pin gigabytes or
23
- * evict uselessly. `COMPUTE_DEFINITION_BYTE_CACHE_MB` sets the budget; `0`
24
- * disables the cache (every `getOrLoad` calls `load` and caches nothing).
25
- * - No TTL: version ids are immutable, so a cached entry can never go stale.
26
- * - An entry larger than the whole budget is served but never retained (caching
27
- * it would immediately evict everything including itself).
28
- */
29
- /**
30
- * Per-`getOrLoad` outcome, observable AFTER the scheduler has (or hasn't) called
31
- * `load()`. Lets the solve pipeline emit a `def_bytes` Server-Timing verdict:
32
- * - `load` never invoked → the scheduler served a pointer-known solve without
33
- * bytes (`skipped`);
34
- * - `load` invoked, `fromCache` true → warm byte-cache entry (`hit`);
35
- * - `load` invoked, `fromCache` false → fell through to the loader (`miss`).
36
- */
37
- export interface ByteRefOutcome {
38
- /** True once `load()` has been called at least once on this ref. */
39
- loaded: boolean;
40
- /** When `loaded`, whether the bytes came from a warm cache entry. */
41
- fromCache: boolean;
42
- }
43
- /** A definition reference shaped for `@selvajs/compute`'s `DefinitionRef`. */
44
- export interface ByteCacheRef {
45
- /** Immutable identity (a version UUID). Keys the scheduler's caches too. */
46
- key: string;
47
- /** Materialize the bytes — served from cache when warm, else via the loader. */
48
- load: () => Promise<Uint8Array>;
49
- /** Mutable outcome of this ref's `load()` (see {@link ByteRefOutcome}). */
50
- outcome: ByteRefOutcome;
51
- }
52
- /** Hit/miss/eviction counters for observability (Server-Timing, admin debug). */
53
- export interface ByteCacheStats {
54
- /** `load()` served from a warm entry (no loader call). */
55
- hits: number;
56
- /** `load()` fell through to the loader (cold key, or caching disabled). */
57
- misses: number;
58
- /** Entries dropped by the byte-budget LRU. */
59
- evictions: number;
60
- /** Current retained entry count. */
61
- entries: number;
62
- /** Current retained bytes. */
63
- bytes: number;
64
- }
65
- export interface DefinitionByteCache {
66
- /**
67
- * Return a `DefinitionRef` whose `load()` serves `versionId`'s bytes from the
68
- * cache when warm, otherwise calls `load` (and caches the result). The
69
- * `DefinitionRef` is cheap to build and moves no bytes until `load()` runs —
70
- * so handing it to the scheduler for a pointer-known solve costs nothing.
71
- */
72
- getOrLoad(versionId: string, load: () => Promise<Uint8Array>): ByteCacheRef;
73
- /** Snapshot of the counters (see {@link ByteCacheStats}). */
74
- stats(): ByteCacheStats;
75
- /** Drop everything (test seam / eviction on definition delete if ever needed). */
76
- clear(): void;
77
- }
78
- /**
79
- * Build a definition-byte cache with a total-byte LRU budget.
80
- *
81
- * @param maxBytes total retained-byte budget; `0` (or negative) disables caching
82
- * entirely — every `load()` calls the loader and nothing is retained.
83
- */
84
- export declare function createDefinitionByteCache(maxBytes: number): DefinitionByteCache;
85
- //# sourceMappingURL=definition-byte-cache.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"definition-byte-cache.d.ts","sourceRoot":"","sources":["../../src/compute/definition-byte-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC9B,oEAAoE;IACpE,MAAM,EAAE,OAAO,CAAC;IAChB,qEAAqE;IACrE,SAAS,EAAE,OAAO,CAAC;CACnB;AAED,8EAA8E;AAC9E,MAAM,WAAW,YAAY;IAC5B,4EAA4E;IAC5E,GAAG,EAAE,MAAM,CAAC;IACZ,gFAAgF;IAChF,IAAI,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;IAChC,2EAA2E;IAC3E,OAAO,EAAE,cAAc,CAAC;CACxB;AAED,iFAAiF;AACjF,MAAM,WAAW,cAAc;IAC9B,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,mBAAmB;IACnC;;;;;OAKG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,GAAG,YAAY,CAAC;IAC5E,6DAA6D;IAC7D,KAAK,IAAI,cAAc,CAAC;IACxB,kFAAkF;IAClF,KAAK,IAAI,IAAI,CAAC;CACd;AAMD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,mBAAmB,CA2E/E"}
@@ -1,110 +0,0 @@
1
- /**
2
- * In-process cache of `.gh` definition bytes, keyed by immutable **version id**.
3
- *
4
- * The solve path used to eagerly `storage.get(fileKey)` on every request — moving
5
- * multi-MB definition bytes off disk/S3 into memory before the scheduler could
6
- * decide it didn't need them (the compute server already holds the definition via
7
- * the pointer/`reuseServerDefinitionCache` fast path). This cache turns that eager
8
- * read into a lazy `DefinitionRef.load()`: the scheduler calls `load()` ONLY when
9
- * an upload is unavoidable, and even then a warm entry serves the bytes without
10
- * touching storage. A pointer-known re-solve therefore moves ZERO definition bytes.
11
- *
12
- * Keying discipline (the whole reason this module exists):
13
- * - The key is the **version id**, an immutable UUID — never a `fileKey`, which
14
- * a delete-latest-then-reupload can REUSE for different content (see the
15
- * monotonic-version-number fix). A reused key would serve one version's bytes
16
- * for another: silent cache poisoning with no diagnostic. Callers pass
17
- * `version.id`, and the returned `DefinitionRef.key` is that same id, so the
18
- * scheduler's own result/pointer cache keys on the same immutable identity.
19
- *
20
- * Eviction:
21
- * - LRU by **total byte budget**, not entry count — definitions range from tens
22
- * of KB to hundreds of MB, so an entry-count cap would either pin gigabytes or
23
- * evict uselessly. `COMPUTE_DEFINITION_BYTE_CACHE_MB` sets the budget; `0`
24
- * disables the cache (every `getOrLoad` calls `load` and caches nothing).
25
- * - No TTL: version ids are immutable, so a cached entry can never go stale.
26
- * - An entry larger than the whole budget is served but never retained (caching
27
- * it would immediately evict everything including itself).
28
- */
29
- /**
30
- * Build a definition-byte cache with a total-byte LRU budget.
31
- *
32
- * @param maxBytes total retained-byte budget; `0` (or negative) disables caching
33
- * entirely — every `load()` calls the loader and nothing is retained.
34
- */
35
- export function createDefinitionByteCache(maxBytes) {
36
- const budget = Math.max(0, Math.floor(maxBytes));
37
- // Map preserves insertion order → iteration order IS LRU order; re-inserting
38
- // on access moves an entry to the most-recently-used (last) position.
39
- const cache = new Map();
40
- let retainedBytes = 0;
41
- const stats = { hits: 0, misses: 0, evictions: 0 };
42
- function touch(key, entry) {
43
- cache.delete(key);
44
- cache.set(key, entry);
45
- }
46
- function evictToFit() {
47
- // Evict least-recently-used (first in insertion order) until within budget.
48
- while (retainedBytes > budget && cache.size > 0) {
49
- const oldestKey = cache.keys().next().value;
50
- const oldest = cache.get(oldestKey);
51
- cache.delete(oldestKey);
52
- retainedBytes -= oldest.bytes.byteLength;
53
- stats.evictions += 1;
54
- }
55
- }
56
- function store(key, bytes) {
57
- if (budget === 0)
58
- return;
59
- // An entry bigger than the whole budget is never retained — caching it would
60
- // evict everything (including itself) on the next `evictToFit`. Serve it
61
- // through, cache nothing.
62
- if (bytes.byteLength > budget)
63
- return;
64
- const existing = cache.get(key);
65
- if (existing)
66
- retainedBytes -= existing.bytes.byteLength;
67
- cache.set(key, { bytes });
68
- retainedBytes += bytes.byteLength;
69
- evictToFit();
70
- }
71
- return {
72
- getOrLoad(versionId, load) {
73
- const outcome = { loaded: false, fromCache: false };
74
- return {
75
- key: versionId,
76
- outcome,
77
- load: async () => {
78
- const hit = cache.get(versionId);
79
- if (hit) {
80
- touch(versionId, hit);
81
- stats.hits += 1;
82
- outcome.loaded = true;
83
- outcome.fromCache = true;
84
- return hit.bytes;
85
- }
86
- stats.misses += 1;
87
- outcome.loaded = true;
88
- outcome.fromCache = false;
89
- const bytes = await load();
90
- store(versionId, bytes);
91
- return bytes;
92
- }
93
- };
94
- },
95
- stats() {
96
- return {
97
- hits: stats.hits,
98
- misses: stats.misses,
99
- evictions: stats.evictions,
100
- entries: cache.size,
101
- bytes: retainedBytes
102
- };
103
- },
104
- clear() {
105
- cache.clear();
106
- retainedBytes = 0;
107
- }
108
- };
109
- }
110
- //# sourceMappingURL=definition-byte-cache.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"definition-byte-cache.js","sourceRoot":"","sources":["../../src/compute/definition-byte-cache.ts"],"names":[],"mappings":"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"}
@@ -1,58 +0,0 @@
1
- /**
2
- * In-memory `ISolveResultCache` — the first durable L2 backend (H1).
3
- *
4
- * Two eviction dimensions, both required (see CACHING.md H1):
5
- *
6
- * 1. **Per-definition count quota, LRU-within-definition.** Each definition
7
- * gets its own budget of remembered solves (`maxEntriesForDefinition`,
8
- * passed at write time). A slider-heavy definition churns ONLY its own
9
- * entries — it can never evict another definition's. This is what makes a
10
- * wide-input-space definition harmless structurally instead of via an
11
- * off-switch.
12
- * 2. **Global byte backstop, global-LRU.** Entries range KB→100s of MB, so a
13
- * count quota can't bound heap. `maxTotalBytes` evicts the globally
14
- * least-recently-used entry across every definition until total retained
15
- * bytes fit. Authors think in counts; operators think in bytes; both hold.
16
- *
17
- * The key is `(orgId, definitionId, versionId, inputKey)`. `definitionId` scopes
18
- * the count quota; the full tuple addresses the entry. Version keying means a
19
- * publish is a fresh keyspace and there is nothing to invalidate — entries just
20
- * age out under the two budgets.
21
- *
22
- * Best-effort contract: this never throws. A `get` miss and a `set` drop are both
23
- * normal. Correctness never depends on a hit.
24
- */
25
- import type { ISolveResultCache } from '@selvajs/platform';
26
- /** Observability counters for the admin/debug surface (parallels ByteCacheStats). */
27
- export interface SolveCacheStats {
28
- /** `get` served a live entry. */
29
- hits: number;
30
- /** `get` found nothing. */
31
- misses: number;
32
- /** `set` stored a new (or replaced) entry. */
33
- writes: number;
34
- /** Entries dropped by the per-definition count quota. */
35
- quotaEvictions: number;
36
- /** Entries dropped by the global byte backstop. */
37
- byteEvictions: number;
38
- /** Current retained entry count across all definitions. */
39
- entries: number;
40
- /** Current retained bytes across all definitions. */
41
- bytes: number;
42
- }
43
- /** A memory backend with its own stats, for wiring + observability. */
44
- export interface MemorySolveResultCache extends ISolveResultCache {
45
- stats(): SolveCacheStats;
46
- /** Drop everything (test seam). */
47
- clear(): void;
48
- }
49
- /**
50
- * Build an in-memory L2 solve cache.
51
- *
52
- * @param maxTotalBytes global retained-byte backstop; `0` (or negative) disables
53
- * the backstop (per-definition counts are then the only bound — not recommended
54
- * in-process). An entry larger than the whole backstop is stored-then-immediately
55
- * evicted (served through, never retained) — same rule as the byte cache.
56
- */
57
- export declare function createMemorySolveResultCache(maxTotalBytes: number): MemorySolveResultCache;
58
- //# sourceMappingURL=memory-solve-cache.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"memory-solve-cache.d.ts","sourceRoot":"","sources":["../../src/compute/memory-solve-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EACX,iBAAiB,EAIjB,MAAM,mBAAmB,CAAC;AAE3B,qFAAqF;AACrF,MAAM,WAAW,eAAe;IAC/B,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,cAAc,EAAE,MAAM,CAAC;IACvB,mDAAmD;IACnD,aAAa,EAAE,MAAM,CAAC;IACtB,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAC;CACd;AAED,uEAAuE;AACvE,MAAM,WAAW,sBAAuB,SAAQ,iBAAiB;IAChE,KAAK,IAAI,eAAe,CAAC;IACzB,mCAAmC;IACnC,KAAK,IAAI,IAAI,CAAC;CACd;AAOD;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,aAAa,EAAE,MAAM,GAAG,sBAAsB,CAoI1F"}
Binary file
@@ -1 +0,0 @@
1
- {"version":3,"file":"memory-solve-cache.js","sourceRoot":"","sources":["../../src/compute/memory-solve-cache.ts"],"names":[],"mappings":"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"}
@@ -1,53 +0,0 @@
1
- /**
2
- * L2 cache entry format (R6). An entry is the gzipped response body plus a tiny
3
- * metadata header, so a hit is near-CPU-free: no `JSON.stringify`, no re-solve —
4
- * gzip clients get the stored bytes verbatim, and the header carries just enough
5
- * to rebuild the `ok` outcome (error/warning counts for the metric, uncompressed
6
- * length for the `Content-Length` on a gunzip fallback).
7
- *
8
- * Wire layout (opaque to the `ISolveResultCache` backend, which sees only bytes):
9
- *
10
- * [ 4 bytes: header length N, big-endian uint32 ]
11
- * [ N bytes: UTF-8 JSON EnvelopeHeader ]
12
- * [ rest: gzipped JSON response body ]
13
- *
14
- * The `algo` echo (M3) is already stripped at the source in the package's
15
- * `runSolve`, so the body never carries the base64 definition — entries stay
16
- * small without a strip step here.
17
- */
18
- /** Metadata stored beside the gzipped body. Small; parsed on every hit. */
19
- export interface EnvelopeHeader {
20
- /** Grasshopper runtime error count, for the solve metric. */
21
- errorCount: number;
22
- /** Grasshopper runtime warning count, for the solve metric. */
23
- warningCount: number;
24
- /** Uncompressed JSON body length in bytes (Content-Length for a gunzip fallback). */
25
- serializedBytes: number;
26
- /**
27
- * SHA-256 hex of the canonical input preimage (H2 defense-in-depth). A hit
28
- * verifies this equals the requesting key's hash before serving — a wide-hash
29
- * collision that produced the same storage key still can't serve the wrong
30
- * geometry.
31
- */
32
- inputHash: string;
33
- }
34
- /**
35
- * Encode a cache entry from the gzipped body + header. The body MUST already be
36
- * gzipped (the pipeline gzips before storing so every hit serves compressed
37
- * bytes; a rare non-gzip client gunzips on read).
38
- */
39
- export declare function encodeSolveCacheEntry(header: EnvelopeHeader, gzippedBody: Uint8Array): Uint8Array;
40
- /** A decoded entry: the parsed header + the still-gzipped body slice. */
41
- export interface DecodedSolveCacheEntry {
42
- header: EnvelopeHeader;
43
- gzippedBody: Uint8Array;
44
- }
45
- /**
46
- * Decode a cache entry. Returns `null` on any malformed input (truncated, bad
47
- * length prefix, non-JSON header) — a corrupt entry is treated as a miss, never
48
- * an error, matching the best-effort cache contract.
49
- */
50
- export declare function decodeSolveCacheEntry(bytes: Uint8Array): DecodedSolveCacheEntry | null;
51
- /** Gunzip a stored body back to the JSON string, for a non-gzip client (rare). */
52
- export declare function gunzipEntryBody(gzippedBody: Uint8Array): string;
53
- //# sourceMappingURL=solve-cache-envelope.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"solve-cache-envelope.d.ts","sourceRoot":"","sources":["../../src/compute/solve-cache-envelope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,2EAA2E;AAC3E,MAAM,WAAW,cAAc;IAC9B,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAC;IACrB,qFAAqF;IACrF,eAAe,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,GAAG,UAAU,CAUjG;AAED,yEAAyE;AACzE,MAAM,WAAW,sBAAsB;IACtC,MAAM,EAAE,cAAc,CAAC;IACvB,WAAW,EAAE,UAAU,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,UAAU,GAAG,sBAAsB,GAAG,IAAI,CA2BtF;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,WAAW,EAAE,UAAU,GAAG,MAAM,CAE/D"}
@@ -1,66 +0,0 @@
1
- /**
2
- * L2 cache entry format (R6). An entry is the gzipped response body plus a tiny
3
- * metadata header, so a hit is near-CPU-free: no `JSON.stringify`, no re-solve —
4
- * gzip clients get the stored bytes verbatim, and the header carries just enough
5
- * to rebuild the `ok` outcome (error/warning counts for the metric, uncompressed
6
- * length for the `Content-Length` on a gunzip fallback).
7
- *
8
- * Wire layout (opaque to the `ISolveResultCache` backend, which sees only bytes):
9
- *
10
- * [ 4 bytes: header length N, big-endian uint32 ]
11
- * [ N bytes: UTF-8 JSON EnvelopeHeader ]
12
- * [ rest: gzipped JSON response body ]
13
- *
14
- * The `algo` echo (M3) is already stripped at the source in the package's
15
- * `runSolve`, so the body never carries the base64 definition — entries stay
16
- * small without a strip step here.
17
- */
18
- import { gunzipSync } from 'node:zlib';
19
- /**
20
- * Encode a cache entry from the gzipped body + header. The body MUST already be
21
- * gzipped (the pipeline gzips before storing so every hit serves compressed
22
- * bytes; a rare non-gzip client gunzips on read).
23
- */
24
- export function encodeSolveCacheEntry(header, gzippedBody) {
25
- const headerJson = Buffer.from(JSON.stringify(header), 'utf8');
26
- const out = Buffer.allocUnsafe(4 + headerJson.byteLength + gzippedBody.byteLength);
27
- out.writeUInt32BE(headerJson.byteLength, 0);
28
- headerJson.copy(out, 4);
29
- Buffer.from(gzippedBody.buffer, gzippedBody.byteOffset, gzippedBody.byteLength).copy(out, 4 + headerJson.byteLength);
30
- return out;
31
- }
32
- /**
33
- * Decode a cache entry. Returns `null` on any malformed input (truncated, bad
34
- * length prefix, non-JSON header) — a corrupt entry is treated as a miss, never
35
- * an error, matching the best-effort cache contract.
36
- */
37
- export function decodeSolveCacheEntry(bytes) {
38
- if (bytes.byteLength < 4)
39
- return null;
40
- const buf = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength);
41
- const headerLen = buf.readUInt32BE(0);
42
- const headerEnd = 4 + headerLen;
43
- if (headerEnd > buf.byteLength)
44
- return null;
45
- let header;
46
- try {
47
- header = JSON.parse(buf.toString('utf8', 4, headerEnd));
48
- }
49
- catch {
50
- return null;
51
- }
52
- if (typeof header?.errorCount !== 'number' ||
53
- typeof header?.warningCount !== 'number' ||
54
- typeof header?.serializedBytes !== 'number' ||
55
- typeof header?.inputHash !== 'string') {
56
- return null;
57
- }
58
- // Slice (view, no copy) of the gzipped remainder.
59
- const gzippedBody = new Uint8Array(bytes.buffer, bytes.byteOffset + headerEnd, bytes.byteLength - headerEnd);
60
- return { header, gzippedBody };
61
- }
62
- /** Gunzip a stored body back to the JSON string, for a non-gzip client (rare). */
63
- export function gunzipEntryBody(gzippedBody) {
64
- return gunzipSync(gzippedBody).toString('utf8');
65
- }
66
- //# sourceMappingURL=solve-cache-envelope.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"solve-cache-envelope.js","sourceRoot":"","sources":["../../src/compute/solve-cache-envelope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAmBvC;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAsB,EAAE,WAAuB;IACpF,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;IAC/D,MAAM,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,UAAU,CAAC,UAAU,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;IACnF,GAAG,CAAC,aAAa,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IAC5C,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACxB,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,UAAU,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC,IAAI,CACnF,GAAG,EACH,CAAC,GAAG,UAAU,CAAC,UAAU,CACzB,CAAC;IACF,OAAO,GAAG,CAAC;AACZ,CAAC;AAQD;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAiB;IACtD,IAAI,KAAK,CAAC,UAAU,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAC1E,MAAM,SAAS,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,SAAS,GAAG,CAAC,GAAG,SAAS,CAAC;IAChC,IAAI,SAAS,GAAG,GAAG,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAC5C,IAAI,MAAsB,CAAC;IAC3B,IAAI,CAAC;QACJ,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,SAAS,CAAC,CAAmB,CAAC;IAC3E,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC;IACb,CAAC;IACD,IACC,OAAO,MAAM,EAAE,UAAU,KAAK,QAAQ;QACtC,OAAO,MAAM,EAAE,YAAY,KAAK,QAAQ;QACxC,OAAO,MAAM,EAAE,eAAe,KAAK,QAAQ;QAC3C,OAAO,MAAM,EAAE,SAAS,KAAK,QAAQ,EACpC,CAAC;QACF,OAAO,IAAI,CAAC;IACb,CAAC;IACD,kDAAkD;IAClD,MAAM,WAAW,GAAG,IAAI,UAAU,CACjC,KAAK,CAAC,MAAM,EACZ,KAAK,CAAC,UAAU,GAAG,SAAS,EAC5B,KAAK,CAAC,UAAU,GAAG,SAAS,CAC5B,CAAC;IACF,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;AAChC,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,eAAe,CAAC,WAAuB;IACtD,OAAO,UAAU,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AACjD,CAAC"}