@selvajs/server 1.0.0-beta.1 → 1.0.0-beta.3

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.
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Idempotency store for the solve endpoint: a repeat of the same request within
3
+ * the TTL replays the first response instead of re-solving.
4
+ *
5
+ * **This absorbs client retries; it is not a result cache.** The TTL is short
6
+ * and the store is process-local, so a retry that lands on another instance
7
+ * (or after the TTL) re-solves. That is acceptable — a duplicate solve costs
8
+ * compute, not correctness. What it must never do is return one caller's result
9
+ * to another, hence the caller identity in the key.
10
+ *
11
+ * Concurrency matters more than the hit rate. A client that retries on timeout
12
+ * usually retries *while the first solve is still running*, so the store holds a
13
+ * **promise**, reserved before the work starts: the second request awaits the
14
+ * first rather than starting a second solve. A reservation that rejects is
15
+ * dropped, so a failed solve is retryable rather than a cached error.
16
+ *
17
+ * Bounded the same way as the rate limiter: amortized sweep plus a hard cap, both
18
+ * driven by `run` rather than a timer — a timer would keep the event loop alive
19
+ * and give this module a lifecycle its callers don't have.
20
+ */
21
+ export interface IdempotencyStoreConfig {
22
+ /** How long a completed response stays replayable, in ms. */
23
+ ttlMs: number;
24
+ /**
25
+ * Max retained entries. Once live entries exceed this, the ones nearest
26
+ * expiry are evicted. Evicting only costs a re-solve on a retry, so size this
27
+ * above the plausible number of in-flight + recent keys.
28
+ */
29
+ maxKeys?: number;
30
+ /**
31
+ * How often (ms) to sweep expired entries, amortized onto `run`. Defaults to
32
+ * `ttlMs`. `0` disables the sweep, leaving only the cap (test seam).
33
+ */
34
+ sweepIntervalMs?: number;
35
+ }
36
+ /** Default {@link IdempotencyStoreConfig.maxKeys}. */
37
+ export declare const DEFAULT_IDEMPOTENCY_MAX_KEYS = 10000;
38
+ export interface IdempotencyOutcome<T> {
39
+ value: T;
40
+ /** True when this call awaited an existing entry rather than running `fn`. */
41
+ replayed: boolean;
42
+ }
43
+ export interface IdempotencyStore<T> {
44
+ /**
45
+ * Run `fn` under `key`, or join/replay the entry already stored there.
46
+ *
47
+ * The entry is reserved before `fn` starts, so a concurrent retry awaits the
48
+ * first run instead of starting its own. A rejection drops the reservation.
49
+ */
50
+ run(key: string, fn: () => Promise<T>): Promise<IdempotencyOutcome<T>>;
51
+ /** Test seam — wipes in-memory state. Production code never calls this. */
52
+ reset(): void;
53
+ /** Retained entry count, including any not yet swept. For tests/observability. */
54
+ size(): number;
55
+ readonly config: Readonly<IdempotencyStoreConfig>;
56
+ }
57
+ /**
58
+ * Build a process-local idempotency store. `T` is whatever the caller replays;
59
+ * the solve route stores a serialized response snapshot rather than a `Response`,
60
+ * because a `Response` body can only be read once.
61
+ */
62
+ export declare function createIdempotencyStore<T>(config: IdempotencyStoreConfig): IdempotencyStore<T>;
63
+ //# sourceMappingURL=idempotency.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idempotency.d.ts","sourceRoot":"","sources":["../../src/compute/idempotency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,sBAAsB;IACtC,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,sDAAsD;AACtD,eAAO,MAAM,4BAA4B,QAAS,CAAC;AAEnD,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACpC,KAAK,EAAE,CAAC,CAAC;IACT,8EAA8E;IAC9E,QAAQ,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC;IAClC;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC;IACvE,2EAA2E;IAC3E,KAAK,IAAI,IAAI,CAAC;IACd,kFAAkF;IAClF,IAAI,IAAI,MAAM,CAAC;IACf,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,sBAAsB,CAAC,CAAC;CAClD;AAYD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,MAAM,EAAE,sBAAsB,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAwE7F"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Idempotency store for the solve endpoint: a repeat of the same request within
3
+ * the TTL replays the first response instead of re-solving.
4
+ *
5
+ * **This absorbs client retries; it is not a result cache.** The TTL is short
6
+ * and the store is process-local, so a retry that lands on another instance
7
+ * (or after the TTL) re-solves. That is acceptable — a duplicate solve costs
8
+ * compute, not correctness. What it must never do is return one caller's result
9
+ * to another, hence the caller identity in the key.
10
+ *
11
+ * Concurrency matters more than the hit rate. A client that retries on timeout
12
+ * usually retries *while the first solve is still running*, so the store holds a
13
+ * **promise**, reserved before the work starts: the second request awaits the
14
+ * first rather than starting a second solve. A reservation that rejects is
15
+ * dropped, so a failed solve is retryable rather than a cached error.
16
+ *
17
+ * Bounded the same way as the rate limiter: amortized sweep plus a hard cap, both
18
+ * driven by `run` rather than a timer — a timer would keep the event loop alive
19
+ * and give this module a lifecycle its callers don't have.
20
+ */
21
+ /** Default {@link IdempotencyStoreConfig.maxKeys}. */
22
+ export const DEFAULT_IDEMPOTENCY_MAX_KEYS = 10_000;
23
+ /**
24
+ * Build a process-local idempotency store. `T` is whatever the caller replays;
25
+ * the solve route stores a serialized response snapshot rather than a `Response`,
26
+ * because a `Response` body can only be read once.
27
+ */
28
+ export function createIdempotencyStore(config) {
29
+ const ttlMs = Math.max(0, Math.floor(config.ttlMs));
30
+ const maxKeys = Math.max(1, Math.floor(config.maxKeys ?? DEFAULT_IDEMPOTENCY_MAX_KEYS));
31
+ const sweepIntervalMs = Math.max(0, Math.floor(config.sweepIntervalMs ?? ttlMs));
32
+ const resolvedConfig = Object.freeze({
33
+ ...config,
34
+ ttlMs,
35
+ maxKeys,
36
+ sweepIntervalMs
37
+ });
38
+ const entries = new Map();
39
+ let nextSweepAt = Number.POSITIVE_INFINITY;
40
+ function maybeSweep(now, headroom = 0) {
41
+ const budget = Math.max(0, maxKeys - headroom);
42
+ const dueForSweep = sweepIntervalMs > 0 && now >= nextSweepAt;
43
+ if (!dueForSweep && entries.size <= budget)
44
+ return;
45
+ for (const [key, entry] of entries) {
46
+ if (entry.expiresAt !== null && now > entry.expiresAt)
47
+ entries.delete(key);
48
+ }
49
+ if (sweepIntervalMs > 0)
50
+ nextSweepAt = now + sweepIntervalMs;
51
+ if (entries.size > budget) {
52
+ // In-flight entries sort last: evicting one would orphan the retries
53
+ // awaiting it, so they are given up only when nothing else is left.
54
+ const byExpiryAsc = [...entries.entries()].sort((a, b) => (a[1].expiresAt ?? Infinity) - (b[1].expiresAt ?? Infinity));
55
+ for (let i = 0; i < byExpiryAsc.length - budget; i++)
56
+ entries.delete(byExpiryAsc[i][0]);
57
+ }
58
+ }
59
+ return {
60
+ config: resolvedConfig,
61
+ async run(key, fn) {
62
+ const now = Date.now();
63
+ const existing = entries.get(key);
64
+ if (existing && (existing.expiresAt === null || now <= existing.expiresAt)) {
65
+ return { value: await existing.promise, replayed: true };
66
+ }
67
+ maybeSweep(now, entries.has(key) ? 0 : 1);
68
+ const promise = fn();
69
+ const entry = { promise, expiresAt: null };
70
+ entries.set(key, entry);
71
+ if (sweepIntervalMs > 0 && nextSweepAt === Number.POSITIVE_INFINITY) {
72
+ nextSweepAt = now + sweepIntervalMs;
73
+ }
74
+ try {
75
+ const value = await promise;
76
+ entry.expiresAt = Date.now() + ttlMs;
77
+ return { value, replayed: false };
78
+ }
79
+ catch (err) {
80
+ // A failed solve is retryable — drop the reservation rather than
81
+ // replaying the error to every retry for the whole TTL. Only drop our
82
+ // own entry: a later `run` may already have replaced it.
83
+ if (entries.get(key) === entry)
84
+ entries.delete(key);
85
+ throw err;
86
+ }
87
+ },
88
+ reset() {
89
+ entries.clear();
90
+ nextSweepAt = Number.POSITIVE_INFINITY;
91
+ },
92
+ size() {
93
+ return entries.size;
94
+ }
95
+ };
96
+ }
97
+ //# sourceMappingURL=idempotency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idempotency.js","sourceRoot":"","sources":["../../src/compute/idempotency.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  export { resolveComputeLimits, readPositiveInt, readNonNegativeInt, readBool, type ComputeLimits, type EnvRecord } from './limits.js';
2
2
  export { createComputeRateLimiter, DEFAULT_MAX_KEYS, type ComputeRateLimiter, type ComputeRateLimiterConfig, type RateLimitResult } from './rate-limit.js';
3
+ export { createIdempotencyStore, DEFAULT_IDEMPOTENCY_MAX_KEYS, type IdempotencyStore, type IdempotencyStoreConfig, type IdempotencyOutcome } from './idempotency.js';
3
4
  export { isSafeRemoteDefinitionUrl, assertSafeRemoteDefinitionUrl } from './safe-url.js';
4
5
  export { createRemoteDefinitionFetcher, readBodyWithCap, type RemoteDefinitionFetcher, type RemoteDefinitionConfig } from './remote-definition.js';
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/compute/index.ts"],"names":[],"mappings":"AAaA,OAAO,EACN,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,QAAQ,EACR,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,MAAM,aAAa,CAAC;AAErB,OAAO,EACN,wBAAwB,EACxB,gBAAgB,EAChB,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,eAAe,EACpB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,yBAAyB,EAAE,6BAA6B,EAAE,MAAM,eAAe,CAAC;AAEzF,OAAO,EACN,6BAA6B,EAC7B,eAAe,EACf,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/compute/index.ts"],"names":[],"mappings":"AAaA,OAAO,EACN,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,QAAQ,EACR,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,MAAM,aAAa,CAAC;AAErB,OAAO,EACN,wBAAwB,EACxB,gBAAgB,EAChB,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,eAAe,EACpB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACN,sBAAsB,EACtB,4BAA4B,EAC5B,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,yBAAyB,EAAE,6BAA6B,EAAE,MAAM,eAAe,CAAC;AAEzF,OAAO,EACN,6BAA6B,EAC7B,eAAe,EACf,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,MAAM,wBAAwB,CAAC"}
@@ -12,6 +12,7 @@
12
12
  // depend on `@selvajs/solve`.
13
13
  export { resolveComputeLimits, readPositiveInt, readNonNegativeInt, readBool } from './limits.js';
14
14
  export { createComputeRateLimiter, DEFAULT_MAX_KEYS } from './rate-limit.js';
15
+ export { createIdempotencyStore, DEFAULT_IDEMPOTENCY_MAX_KEYS } from './idempotency.js';
15
16
  export { isSafeRemoteDefinitionUrl, assertSafeRemoteDefinitionUrl } from './safe-url.js';
16
17
  export { createRemoteDefinitionFetcher, readBodyWithCap } from './remote-definition.js';
17
18
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/compute/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,EAAE;AACF,kGAAkG;AAClG,mGAAmG;AACnG,oBAAoB;AACpB,EAAE;AACF,6FAA6F;AAC7F,qGAAqG;AACrG,mGAAmG;AACnG,oGAAoG;AACpG,kGAAkG;AAClG,8BAA8B;AAE9B,OAAO,EACN,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,QAAQ,EAGR,MAAM,aAAa,CAAC;AAErB,OAAO,EACN,wBAAwB,EACxB,gBAAgB,EAIhB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,yBAAyB,EAAE,6BAA6B,EAAE,MAAM,eAAe,CAAC;AAEzF,OAAO,EACN,6BAA6B,EAC7B,eAAe,EAGf,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/compute/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,EAAE;AACF,kGAAkG;AAClG,mGAAmG;AACnG,oBAAoB;AACpB,EAAE;AACF,6FAA6F;AAC7F,qGAAqG;AACrG,mGAAmG;AACnG,oGAAoG;AACpG,kGAAkG;AAClG,8BAA8B;AAE9B,OAAO,EACN,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,QAAQ,EAGR,MAAM,aAAa,CAAC;AAErB,OAAO,EACN,wBAAwB,EACxB,gBAAgB,EAIhB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACN,sBAAsB,EACtB,4BAA4B,EAI5B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,yBAAyB,EAAE,6BAA6B,EAAE,MAAM,eAAe,CAAC;AAEzF,OAAO,EACN,6BAA6B,EAC7B,eAAe,EAGf,MAAM,wBAAwB,CAAC"}
@@ -50,7 +50,7 @@ export interface ComputeLimits {
50
50
  * caps produces 502s, not longer solves.
51
51
  */
52
52
  solveDeadlineMs: number;
53
- /** Fixed-window cap on /api/compute: window length + max requests per window. */
53
+ /** Fixed-window cap on /api/v1/compute: window length + max requests per window. */
54
54
  rateLimitWindowMs: number;
55
55
  rateLimitMaxRequests: number;
56
56
  /**
@@ -63,7 +63,7 @@ export interface ComputeLimits {
63
63
  maxGhFileSize: number;
64
64
  maxImageFileSize: number;
65
65
  /**
66
- * /api/compute JSON *request* body cap (inputs + values, not the .gh). A
66
+ * /api/v1/compute JSON *request* body cap (inputs + values, not the .gh). A
67
67
  * `file`-widget input embeds geometry as base64 in `values`; must stay <=
68
68
  * the adapter-node global BODY_SIZE_LIMIT or the global backstop rejects first.
69
69
  * Defaults to 210 MB: the client allows a 150 MB raw file, base64 inflates it
@@ -72,7 +72,7 @@ export interface ComputeLimits {
72
72
  */
73
73
  computeRequestMaxBytes: number;
74
74
  /**
75
- * /api/compute JSON *response* cap. A `file`-typed output is base64-embedded
75
+ * /api/v1/compute JSON *response* cap. A `file`-typed output is base64-embedded
76
76
  * in the response; guards V8's ~512 MB single-string wall (a `JSON.stringify`
77
77
  * `RangeError`) and browser-tab OOM. Defensive backstop → clear 413 instead of
78
78
  * an opaque crash (real fix is out-of-band streaming, ADR 0003).
@@ -1 +1 @@
1
- {"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../../src/compute/limits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAc,KAAK,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAI7D,gFAAgF;AAChF,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAS3D;;;GAGG;AACH,wBAAgB,eAAe,CAC9B,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,OAAc,GACpB,MAAM,CAcR;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CACjC,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,OAAc,GACpB,MAAM,CAcR;AAwBD;;;GAGG;AACH,wBAAgB,QAAQ,CACvB,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,OAAO,EACjB,MAAM,GAAE,OAAc,GACpB,OAAO,CAaT;AAED,iDAAiD;AACjD,MAAM,WAAW,aAAa;IAC7B;;;;;;;;;OASG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB,iFAAiF;IACjF,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,MAAM,CAAC;IAC7B;;;;;;OAMG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;;;;;OAOG;IACH,sBAAsB,EAAE,MAAM,CAAC;IAC/B;;;;;;;;;OASG;IACH,uBAAuB,EAAE,MAAM,CAAC;IAChC,yEAAyE;IACzE,wBAAwB,EAAE,MAAM,CAAC;IACjC,wEAAwE;IACxE,8BAA8B,EAAE,MAAM,CAAC;IACvC;;;;;;;OAOG;IACH,0BAA0B,EAAE,MAAM,CAAC;IACnC;;;;;;OAMG;IACH,2BAA2B,EAAE,OAAO,CAAC;IACrC;;;;OAIG;IACH,uBAAuB,EAAE,OAAO,CAAC;IACjC;;;;;OAKG;IACH,yBAAyB,EAAE,OAAO,CAAC;IACnC;;;;;;;;;;OAUG;IACH,oBAAoB,EAAE,MAAM,CAAC;IAC7B;;;;;;;OAOG;IACH,kBAAkB,EAAE,MAAM,CAAC;IAC3B;;;;;;OAMG;IACH,2BAA2B,EAAE,MAAM,CAAC;IACpC;;;;;;;;;;;;OAYG;IACH,sBAAsB,EAAE,MAAM,CAAC;CAC/B;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,GAAE,OAAc,GAAG,aAAa,CAoD1F"}
1
+ {"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../../src/compute/limits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAc,KAAK,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAI7D,gFAAgF;AAChF,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAS3D;;;GAGG;AACH,wBAAgB,eAAe,CAC9B,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,OAAc,GACpB,MAAM,CAcR;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CACjC,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,OAAc,GACpB,MAAM,CAcR;AAwBD;;;GAGG;AACH,wBAAgB,QAAQ,CACvB,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,OAAO,EACjB,MAAM,GAAE,OAAc,GACpB,OAAO,CAaT;AAED,iDAAiD;AACjD,MAAM,WAAW,aAAa;IAC7B;;;;;;;;;OASG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB,oFAAoF;IACpF,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,MAAM,CAAC;IAC7B;;;;;;OAMG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;;;;;OAOG;IACH,sBAAsB,EAAE,MAAM,CAAC;IAC/B;;;;;;;;;OASG;IACH,uBAAuB,EAAE,MAAM,CAAC;IAChC,yEAAyE;IACzE,wBAAwB,EAAE,MAAM,CAAC;IACjC,wEAAwE;IACxE,8BAA8B,EAAE,MAAM,CAAC;IACvC;;;;;;;OAOG;IACH,0BAA0B,EAAE,MAAM,CAAC;IACnC;;;;;;OAMG;IACH,2BAA2B,EAAE,OAAO,CAAC;IACrC;;;;OAIG;IACH,uBAAuB,EAAE,OAAO,CAAC;IACjC;;;;;OAKG;IACH,yBAAyB,EAAE,OAAO,CAAC;IACnC;;;;;;;;;;OAUG;IACH,oBAAoB,EAAE,MAAM,CAAC;IAC7B;;;;;;;OAOG;IACH,kBAAkB,EAAE,MAAM,CAAC;IAC3B;;;;;;OAMG;IACH,2BAA2B,EAAE,MAAM,CAAC;IACpC;;;;;;;;;;;;OAYG;IACH,sBAAsB,EAAE,MAAM,CAAC;CAC/B;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,GAAE,OAAc,GAAG,aAAa,CAoD1F"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@selvajs/server",
3
- "version": "1.0.0-beta.1",
3
+ "version": "1.0.0-beta.3",
4
4
  "description": "Transport-agnostic server building blocks for apps built on the Selva engine (limits, rate limiting, SSRF guard, remote-definition fetch, definition service + render loader); the solve core lives in @selvajs/solve/server",
5
5
  "license": "MIT",
6
6
  "author": "VektorNode",