gavio 0.1.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 +95 -0
- package/dist/cjs/context.js +47 -0
- package/dist/cjs/errors.js +57 -0
- package/dist/cjs/gateway.js +127 -0
- package/dist/cjs/ids.js +60 -0
- package/dist/cjs/index.js +49 -0
- package/dist/cjs/interceptors/audit/index.js +12 -0
- package/dist/cjs/interceptors/audit/interceptor.js +77 -0
- package/dist/cjs/interceptors/audit/record.js +107 -0
- package/dist/cjs/interceptors/audit/sink.js +3 -0
- package/dist/cjs/interceptors/audit/sinks/index.js +5 -0
- package/dist/cjs/interceptors/audit/sinks/stdout.js +33 -0
- package/dist/cjs/interceptors/base.js +7 -0
- package/dist/cjs/interceptors/cache/backend.js +9 -0
- package/dist/cjs/interceptors/cache/backends/index.js +5 -0
- package/dist/cjs/interceptors/cache/backends/memory.js +53 -0
- package/dist/cjs/interceptors/cache/index.js +9 -0
- package/dist/cjs/interceptors/chain.js +57 -0
- package/dist/cjs/interceptors/index.js +18 -0
- package/dist/cjs/interceptors/pii/context.js +25 -0
- package/dist/cjs/interceptors/pii/guard.js +161 -0
- package/dist/cjs/interceptors/pii/index.js +28 -0
- package/dist/cjs/interceptors/pii/match.js +21 -0
- package/dist/cjs/interceptors/pii/scanner.js +31 -0
- package/dist/cjs/interceptors/pii/scanners/bsn.js +41 -0
- package/dist/cjs/interceptors/pii/scanners/credit-card.js +51 -0
- package/dist/cjs/interceptors/pii/scanners/email.js +26 -0
- package/dist/cjs/interceptors/pii/scanners/iban.js +58 -0
- package/dist/cjs/interceptors/pii/scanners/index.js +45 -0
- package/dist/cjs/interceptors/pii/scanners/ip-address.js +36 -0
- package/dist/cjs/interceptors/pii/scanners/phone.js +37 -0
- package/dist/cjs/interceptors/pii/scanners/secret.js +46 -0
- package/dist/cjs/interceptors/pii/scanners/ssn.js +28 -0
- package/dist/cjs/interceptors/reliability/fallback.js +53 -0
- package/dist/cjs/interceptors/reliability/index.js +11 -0
- package/dist/cjs/interceptors/reliability/retry.js +69 -0
- package/dist/cjs/interceptors/reliability/timeout.js +41 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/pricing.js +70 -0
- package/dist/cjs/providers/anthropic.js +80 -0
- package/dist/cjs/providers/base.js +30 -0
- package/dist/cjs/providers/http.js +42 -0
- package/dist/cjs/providers/index.js +34 -0
- package/dist/cjs/providers/mock.js +54 -0
- package/dist/cjs/providers/openai.js +63 -0
- package/dist/cjs/request.js +60 -0
- package/dist/cjs/response.js +55 -0
- package/dist/cjs/testing/harness.js +70 -0
- package/dist/cjs/testing/index.js +8 -0
- package/dist/cjs/types.js +61 -0
- package/dist/esm/context.d.ts +33 -0
- package/dist/esm/context.js +43 -0
- package/dist/esm/errors.d.ts +36 -0
- package/dist/esm/errors.js +44 -0
- package/dist/esm/gateway.d.ts +54 -0
- package/dist/esm/gateway.js +123 -0
- package/dist/esm/ids.d.ts +11 -0
- package/dist/esm/ids.js +56 -0
- package/dist/esm/index.d.ts +25 -0
- package/dist/esm/index.js +20 -0
- package/dist/esm/interceptors/audit/index.d.ts +7 -0
- package/dist/esm/interceptors/audit/index.js +3 -0
- package/dist/esm/interceptors/audit/interceptor.d.ts +11 -0
- package/dist/esm/interceptors/audit/interceptor.js +72 -0
- package/dist/esm/interceptors/audit/record.d.ts +66 -0
- package/dist/esm/interceptors/audit/record.js +103 -0
- package/dist/esm/interceptors/audit/sink.d.ts +8 -0
- package/dist/esm/interceptors/audit/sink.js +2 -0
- package/dist/esm/interceptors/audit/sinks/index.d.ts +2 -0
- package/dist/esm/interceptors/audit/sinks/index.js +1 -0
- package/dist/esm/interceptors/audit/sinks/stdout.d.ts +8 -0
- package/dist/esm/interceptors/audit/sinks/stdout.js +30 -0
- package/dist/esm/interceptors/base.d.ts +37 -0
- package/dist/esm/interceptors/base.js +4 -0
- package/dist/esm/interceptors/cache/backend.d.ts +14 -0
- package/dist/esm/interceptors/cache/backend.js +8 -0
- package/dist/esm/interceptors/cache/backends/index.d.ts +2 -0
- package/dist/esm/interceptors/cache/backends/index.js +1 -0
- package/dist/esm/interceptors/cache/backends/memory.d.ts +7 -0
- package/dist/esm/interceptors/cache/backends/memory.js +50 -0
- package/dist/esm/interceptors/cache/index.d.ts +7 -0
- package/dist/esm/interceptors/cache/index.js +5 -0
- package/dist/esm/interceptors/chain.d.ts +17 -0
- package/dist/esm/interceptors/chain.js +53 -0
- package/dist/esm/interceptors/index.d.ts +8 -0
- package/dist/esm/interceptors/index.js +7 -0
- package/dist/esm/interceptors/pii/context.d.ts +15 -0
- package/dist/esm/interceptors/pii/context.js +21 -0
- package/dist/esm/interceptors/pii/guard.d.ts +30 -0
- package/dist/esm/interceptors/pii/guard.js +157 -0
- package/dist/esm/interceptors/pii/index.d.ts +10 -0
- package/dist/esm/interceptors/pii/index.js +7 -0
- package/dist/esm/interceptors/pii/match.d.ts +26 -0
- package/dist/esm/interceptors/pii/match.js +17 -0
- package/dist/esm/interceptors/pii/scanner.d.ts +32 -0
- package/dist/esm/interceptors/pii/scanner.js +26 -0
- package/dist/esm/interceptors/pii/scanners/bsn.d.ts +5 -0
- package/dist/esm/interceptors/pii/scanners/bsn.js +37 -0
- package/dist/esm/interceptors/pii/scanners/credit-card.d.ts +4 -0
- package/dist/esm/interceptors/pii/scanners/credit-card.js +47 -0
- package/dist/esm/interceptors/pii/scanners/email.d.ts +3 -0
- package/dist/esm/interceptors/pii/scanners/email.js +23 -0
- package/dist/esm/interceptors/pii/scanners/iban.d.ts +5 -0
- package/dist/esm/interceptors/pii/scanners/iban.js +54 -0
- package/dist/esm/interceptors/pii/scanners/index.d.ts +13 -0
- package/dist/esm/interceptors/pii/scanners/index.js +30 -0
- package/dist/esm/interceptors/pii/scanners/ip-address.d.ts +3 -0
- package/dist/esm/interceptors/pii/scanners/ip-address.js +33 -0
- package/dist/esm/interceptors/pii/scanners/phone.d.ts +6 -0
- package/dist/esm/interceptors/pii/scanners/phone.js +34 -0
- package/dist/esm/interceptors/pii/scanners/secret.d.ts +9 -0
- package/dist/esm/interceptors/pii/scanners/secret.js +43 -0
- package/dist/esm/interceptors/pii/scanners/ssn.d.ts +3 -0
- package/dist/esm/interceptors/pii/scanners/ssn.js +25 -0
- package/dist/esm/interceptors/reliability/fallback.d.ts +9 -0
- package/dist/esm/interceptors/reliability/fallback.js +50 -0
- package/dist/esm/interceptors/reliability/index.d.ts +7 -0
- package/dist/esm/interceptors/reliability/index.js +4 -0
- package/dist/esm/interceptors/reliability/retry.d.ts +13 -0
- package/dist/esm/interceptors/reliability/retry.js +66 -0
- package/dist/esm/interceptors/reliability/timeout.d.ts +9 -0
- package/dist/esm/interceptors/reliability/timeout.js +37 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/pricing.d.ts +19 -0
- package/dist/esm/pricing.js +65 -0
- package/dist/esm/providers/anthropic.d.ts +30 -0
- package/dist/esm/providers/anthropic.js +77 -0
- package/dist/esm/providers/base.d.ts +23 -0
- package/dist/esm/providers/base.js +28 -0
- package/dist/esm/providers/http.d.ts +8 -0
- package/dist/esm/providers/http.js +39 -0
- package/dist/esm/providers/index.d.ts +15 -0
- package/dist/esm/providers/index.js +25 -0
- package/dist/esm/providers/mock.d.ts +31 -0
- package/dist/esm/providers/mock.js +51 -0
- package/dist/esm/providers/openai.d.ts +26 -0
- package/dist/esm/providers/openai.js +60 -0
- package/dist/esm/request.d.ts +36 -0
- package/dist/esm/request.js +56 -0
- package/dist/esm/response.d.ts +38 -0
- package/dist/esm/response.js +51 -0
- package/dist/esm/testing/harness.d.ts +37 -0
- package/dist/esm/testing/harness.js +66 -0
- package/dist/esm/testing/index.d.ts +5 -0
- package/dist/esm/testing/index.js +3 -0
- package/dist/esm/types.d.ts +58 -0
- package/dist/esm/types.js +56 -0
- package/package.json +115 -0
- package/src/context.ts +57 -0
- package/src/errors.ts +47 -0
- package/src/gateway.ts +174 -0
- package/src/ids.ts +69 -0
- package/src/index.ts +52 -0
- package/src/interceptors/audit/index.ts +7 -0
- package/src/interceptors/audit/interceptor.ts +93 -0
- package/src/interceptors/audit/record.ts +138 -0
- package/src/interceptors/audit/sink.ts +10 -0
- package/src/interceptors/audit/sinks/index.ts +2 -0
- package/src/interceptors/audit/sinks/stdout.ts +42 -0
- package/src/interceptors/base.ts +58 -0
- package/src/interceptors/cache/backend.ts +15 -0
- package/src/interceptors/cache/backends/index.ts +2 -0
- package/src/interceptors/cache/backends/memory.ts +68 -0
- package/src/interceptors/cache/index.ts +8 -0
- package/src/interceptors/chain.ts +65 -0
- package/src/interceptors/index.ts +9 -0
- package/src/interceptors/pii/context.ts +24 -0
- package/src/interceptors/pii/guard.ts +201 -0
- package/src/interceptors/pii/index.ts +21 -0
- package/src/interceptors/pii/match.ts +43 -0
- package/src/interceptors/pii/scanner.ts +54 -0
- package/src/interceptors/pii/scanners/bsn.ts +44 -0
- package/src/interceptors/pii/scanners/credit-card.ts +52 -0
- package/src/interceptors/pii/scanners/email.ts +31 -0
- package/src/interceptors/pii/scanners/iban.ts +60 -0
- package/src/interceptors/pii/scanners/index.ts +35 -0
- package/src/interceptors/pii/scanners/ip-address.ts +41 -0
- package/src/interceptors/pii/scanners/phone.ts +46 -0
- package/src/interceptors/pii/scanners/secret.ts +51 -0
- package/src/interceptors/pii/scanners/ssn.ts +33 -0
- package/src/interceptors/reliability/fallback.ts +66 -0
- package/src/interceptors/reliability/index.ts +8 -0
- package/src/interceptors/reliability/retry.ts +97 -0
- package/src/interceptors/reliability/timeout.ts +53 -0
- package/src/pricing.ts +72 -0
- package/src/providers/anthropic.ts +113 -0
- package/src/providers/base.ts +52 -0
- package/src/providers/http.ts +50 -0
- package/src/providers/index.ts +39 -0
- package/src/providers/mock.ts +73 -0
- package/src/providers/openai.ts +94 -0
- package/src/request.ts +76 -0
- package/src/response.ts +73 -0
- package/src/testing/harness.ts +98 -0
- package/src/testing/index.ts +6 -0
- package/src/types.ts +83 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/** Gateway — the entry point. Wires interceptors around a provider adapter. */
|
|
2
|
+
import { InterceptorContext } from './context.js';
|
|
3
|
+
import { ConfigurationError } from './errors.js';
|
|
4
|
+
import { auditInterceptor, isAuditInterceptor } from './interceptors/audit/index.js';
|
|
5
|
+
import { isExecutorPolicy } from './interceptors/base.js';
|
|
6
|
+
import { InterceptorChain } from './interceptors/chain.js';
|
|
7
|
+
import { PricingProvider } from './pricing.js';
|
|
8
|
+
import { buildAdapter } from './providers/index.js';
|
|
9
|
+
import { mockProvider } from './providers/mock.js';
|
|
10
|
+
import { GavioRequest } from './request.js';
|
|
11
|
+
import { Provider, coerceProvider } from './types.js';
|
|
12
|
+
const DEFAULT_MODELS = {
|
|
13
|
+
openai: 'gpt-4o',
|
|
14
|
+
anthropic: 'claude-sonnet-4-6',
|
|
15
|
+
mock: 'mock',
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Routes a request through the interceptor pipeline to a provider.
|
|
19
|
+
*
|
|
20
|
+
* Construct with `new Gateway({ provider, model })` then chain `.use(...)` and
|
|
21
|
+
* `.withAdapter(...)`. A single instance is safe to reuse — per-request state
|
|
22
|
+
* lives in an {@link InterceptorContext} created fresh for every call.
|
|
23
|
+
*/
|
|
24
|
+
export class Gateway {
|
|
25
|
+
providerHint;
|
|
26
|
+
modelHint;
|
|
27
|
+
adapterOverride;
|
|
28
|
+
devMode;
|
|
29
|
+
dryRunMode;
|
|
30
|
+
pricing;
|
|
31
|
+
interceptors = [];
|
|
32
|
+
constructor(options = {}) {
|
|
33
|
+
this.providerHint = options.provider ? coerceProvider(options.provider) : undefined;
|
|
34
|
+
this.modelHint = options.model;
|
|
35
|
+
this.adapterOverride = options.adapter;
|
|
36
|
+
this.devMode = options.devMode ?? false;
|
|
37
|
+
this.dryRunMode = options.dryRun ?? false;
|
|
38
|
+
this.pricing = options.pricing ?? new PricingProvider();
|
|
39
|
+
}
|
|
40
|
+
/** Register an interceptor or executor policy. First-registered = outermost. */
|
|
41
|
+
use(interceptor) {
|
|
42
|
+
this.interceptors.push(interceptor);
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
/** Supply a provider adapter explicitly (overrides `provider`). */
|
|
46
|
+
withAdapter(adapter) {
|
|
47
|
+
this.adapterOverride = adapter;
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
get model() {
|
|
51
|
+
return this.modelHint ?? this.resolveModel(this.resolveAdapter());
|
|
52
|
+
}
|
|
53
|
+
get providerName() {
|
|
54
|
+
return this.resolveAdapter().providerName;
|
|
55
|
+
}
|
|
56
|
+
async complete(opts) {
|
|
57
|
+
const adapter = this.resolveAdapter();
|
|
58
|
+
const model = opts.model ?? this.modelHint ?? this.resolveModel(adapter);
|
|
59
|
+
const request = new GavioRequest({
|
|
60
|
+
messages: opts.messages,
|
|
61
|
+
model,
|
|
62
|
+
provider: coerceProvider(adapter.providerName),
|
|
63
|
+
agentId: opts.agentId ?? null,
|
|
64
|
+
parentTraceId: opts.parentTraceId ?? null,
|
|
65
|
+
sessionId: opts.sessionId ?? null,
|
|
66
|
+
options: opts.options ?? {},
|
|
67
|
+
metadata: opts.metadata ?? {},
|
|
68
|
+
});
|
|
69
|
+
const ctx = new InterceptorContext({
|
|
70
|
+
traceId: request.traceId,
|
|
71
|
+
agentId: request.agentId,
|
|
72
|
+
parentTraceId: request.parentTraceId,
|
|
73
|
+
sessionId: request.sessionId,
|
|
74
|
+
dryRun: this.dryRunMode,
|
|
75
|
+
});
|
|
76
|
+
const { chain, executor } = this.buildPipeline(adapter, ctx);
|
|
77
|
+
return chain.execute(request, ctx, executor);
|
|
78
|
+
}
|
|
79
|
+
async healthCheck() {
|
|
80
|
+
return this.resolveAdapter().healthCheck();
|
|
81
|
+
}
|
|
82
|
+
buildPipeline(adapter, ctx) {
|
|
83
|
+
let interceptors = [...this.interceptors];
|
|
84
|
+
// Dev mode auto-wires a stdout audit sink if none was added.
|
|
85
|
+
if (this.devMode && !interceptors.some(isAuditInterceptor)) {
|
|
86
|
+
interceptors = [auditInterceptor(), ...interceptors];
|
|
87
|
+
}
|
|
88
|
+
const policies = interceptors.filter(isExecutorPolicy);
|
|
89
|
+
const regular = interceptors.filter((i) => !isExecutorPolicy(i));
|
|
90
|
+
const chain = new InterceptorChain(regular);
|
|
91
|
+
let executor = (request) => adapter.complete(request);
|
|
92
|
+
// Wrap so the first-registered policy ends up outermost.
|
|
93
|
+
for (let i = policies.length - 1; i >= 0; i--) {
|
|
94
|
+
executor = this.wrapPolicy(policies[i], executor, ctx);
|
|
95
|
+
}
|
|
96
|
+
return { chain, executor };
|
|
97
|
+
}
|
|
98
|
+
wrapPolicy(policy, inner, ctx) {
|
|
99
|
+
return async (request) => {
|
|
100
|
+
if (ctx.dryRun && policy.dryRunSafe === false) {
|
|
101
|
+
return inner(request);
|
|
102
|
+
}
|
|
103
|
+
return policy.around(request, ctx, inner);
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
resolveAdapter() {
|
|
107
|
+
if (this.adapterOverride !== undefined)
|
|
108
|
+
return this.adapterOverride;
|
|
109
|
+
if (this.devMode) {
|
|
110
|
+
this.adapterOverride = mockProvider({ pricing: this.pricing });
|
|
111
|
+
return this.adapterOverride;
|
|
112
|
+
}
|
|
113
|
+
if (this.providerHint === undefined) {
|
|
114
|
+
throw new ConfigurationError('No provider configured. Pass { provider }, { adapter }, call .withAdapter(...), ' +
|
|
115
|
+
'or set { devMode: true }.');
|
|
116
|
+
}
|
|
117
|
+
this.adapterOverride = buildAdapter(this.providerHint, this.pricing);
|
|
118
|
+
return this.adapterOverride;
|
|
119
|
+
}
|
|
120
|
+
resolveModel(adapter) {
|
|
121
|
+
return DEFAULT_MODELS[adapter.providerName] ?? 'mock';
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UUID v7 generation — time-sortable, unique identifiers for traces.
|
|
3
|
+
*
|
|
4
|
+
* UUID v7 layout (RFC 9562): 48-bit Unix millisecond timestamp, 4-bit version,
|
|
5
|
+
* 12 bits used here as a per-millisecond monotonic sequence (rand_a), 2-bit
|
|
6
|
+
* variant, 62 bits of randomness. Ported directly from the Python `_ids.py`.
|
|
7
|
+
*/
|
|
8
|
+
/** Return a new UUID version 7 (time-ordered, monotonic within a process). */
|
|
9
|
+
export declare function uuid7(): string;
|
|
10
|
+
/** Return a fresh trace id as a string. */
|
|
11
|
+
export declare function newTraceId(): string;
|
package/dist/esm/ids.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UUID v7 generation — time-sortable, unique identifiers for traces.
|
|
3
|
+
*
|
|
4
|
+
* UUID v7 layout (RFC 9562): 48-bit Unix millisecond timestamp, 4-bit version,
|
|
5
|
+
* 12 bits used here as a per-millisecond monotonic sequence (rand_a), 2-bit
|
|
6
|
+
* variant, 62 bits of randomness. Ported directly from the Python `_ids.py`.
|
|
7
|
+
*/
|
|
8
|
+
import { randomBytes } from 'node:crypto';
|
|
9
|
+
let lastMs = -1;
|
|
10
|
+
let seq = 0; // 12-bit per-millisecond sequence in rand_a, for monotonicity
|
|
11
|
+
/**
|
|
12
|
+
* Return a [unix_ms, sequence] pair that is monotonically non-decreasing.
|
|
13
|
+
*
|
|
14
|
+
* Within a single millisecond the 12-bit sequence increments so IDs stay
|
|
15
|
+
* strictly ordered (RFC 9562 method 1). If the sequence overflows, the
|
|
16
|
+
* timestamp is nudged forward. JavaScript is single-threaded per event loop,
|
|
17
|
+
* so no lock is required.
|
|
18
|
+
*/
|
|
19
|
+
function nextTimestampAndSeq() {
|
|
20
|
+
const nowMs = Date.now();
|
|
21
|
+
if (nowMs > lastMs) {
|
|
22
|
+
lastMs = nowMs;
|
|
23
|
+
seq = randomBytes(2).readUInt16BE(0) & 0x0fff;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
seq += 1;
|
|
27
|
+
if (seq > 0x0fff) {
|
|
28
|
+
lastMs += 1;
|
|
29
|
+
seq = 0;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return [lastMs, seq];
|
|
33
|
+
}
|
|
34
|
+
function toHex(value, width) {
|
|
35
|
+
return value.toString(16).padStart(width, '0');
|
|
36
|
+
}
|
|
37
|
+
/** Return a new UUID version 7 (time-ordered, monotonic within a process). */
|
|
38
|
+
export function uuid7() {
|
|
39
|
+
const [unixMs, randA] = nextTimestampAndSeq();
|
|
40
|
+
// 48-bit millisecond timestamp occupies bits 80..127. Use BigInt for the
|
|
41
|
+
// shift — JS bitwise ops are 32-bit and would truncate Date.now() (~1.75e12).
|
|
42
|
+
const ms = BigInt(unixMs) & 0xffffffffffffn;
|
|
43
|
+
const randBuf = randomBytes(8);
|
|
44
|
+
const randB = randBuf.readBigUInt64BE(0) & 0x3fffffffffffffffn; // 62 bits
|
|
45
|
+
const value = (ms << 80n) |
|
|
46
|
+
(0x7n << 76n) | // version 7
|
|
47
|
+
(BigInt(randA) << 64n) |
|
|
48
|
+
(2n << 62n) | // variant
|
|
49
|
+
randB;
|
|
50
|
+
const hex = toHex(value, 32);
|
|
51
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
52
|
+
}
|
|
53
|
+
/** Return a fresh trace id as a string. */
|
|
54
|
+
export function newTraceId() {
|
|
55
|
+
return uuid7();
|
|
56
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gavio — the open standard AI gateway for production systems.
|
|
3
|
+
*
|
|
4
|
+
* Public API surface (v0.1.0):
|
|
5
|
+
*
|
|
6
|
+
* import { Gateway, GavioRequest, GavioResponse, Provider } from 'gavio'
|
|
7
|
+
*
|
|
8
|
+
* See https://gavio.io for documentation. MIT licensed.
|
|
9
|
+
*/
|
|
10
|
+
export declare const VERSION = "0.1.0";
|
|
11
|
+
export { Gateway } from './gateway.js';
|
|
12
|
+
export type { GatewayOptions, CompleteOptions } from './gateway.js';
|
|
13
|
+
export { GavioRequest } from './request.js';
|
|
14
|
+
export type { GavioRequestInit } from './request.js';
|
|
15
|
+
export { GavioResponse } from './response.js';
|
|
16
|
+
export type { GavioResponseInit } from './response.js';
|
|
17
|
+
export { InterceptorContext } from './context.js';
|
|
18
|
+
export type { InterceptorContextInit } from './context.js';
|
|
19
|
+
export { uuid7, newTraceId } from './ids.js';
|
|
20
|
+
export { PricingProvider, estimateTokens } from './pricing.js';
|
|
21
|
+
export { Provider, CacheType, PiiMode, Sensitivity, GuardrailOutcome, TokenUsage, coerceProvider, } from './types.js';
|
|
22
|
+
export type { Message } from './types.js';
|
|
23
|
+
export type { Interceptor, Executor, ExecutorPolicy } from './interceptors/base.js';
|
|
24
|
+
export { InterceptorChain } from './interceptors/chain.js';
|
|
25
|
+
export { GavioError, ConfigurationError, ProviderError, ProviderUnavailableError, RateLimitError, ServerError, TimeoutError, PiiBlockedError, BudgetExceededError, GuardrailViolationError, } from './errors.js';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gavio — the open standard AI gateway for production systems.
|
|
3
|
+
*
|
|
4
|
+
* Public API surface (v0.1.0):
|
|
5
|
+
*
|
|
6
|
+
* import { Gateway, GavioRequest, GavioResponse, Provider } from 'gavio'
|
|
7
|
+
*
|
|
8
|
+
* See https://gavio.io for documentation. MIT licensed.
|
|
9
|
+
*/
|
|
10
|
+
export const VERSION = '0.1.0';
|
|
11
|
+
export { Gateway } from './gateway.js';
|
|
12
|
+
export { GavioRequest } from './request.js';
|
|
13
|
+
export { GavioResponse } from './response.js';
|
|
14
|
+
export { InterceptorContext } from './context.js';
|
|
15
|
+
export { uuid7, newTraceId } from './ids.js';
|
|
16
|
+
export { PricingProvider, estimateTokens } from './pricing.js';
|
|
17
|
+
export { Provider, CacheType, PiiMode, Sensitivity, GuardrailOutcome, TokenUsage, coerceProvider, } from './types.js';
|
|
18
|
+
export { InterceptorChain } from './interceptors/chain.js';
|
|
19
|
+
// errors
|
|
20
|
+
export { GavioError, ConfigurationError, ProviderError, ProviderUnavailableError, RateLimitError, ServerError, TimeoutError, PiiBlockedError, BudgetExceededError, GuardrailViolationError, } from './errors.js';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { auditInterceptor, isAuditInterceptor, AUDIT_NAME } from './interceptor.js';
|
|
2
|
+
export type { AuditInterceptorOptions } from './interceptor.js';
|
|
3
|
+
export { AuditRecord, SCHEMA_VERSION } from './record.js';
|
|
4
|
+
export type { AuditRecordInit } from './record.js';
|
|
5
|
+
export type { AuditSink } from './sink.js';
|
|
6
|
+
export { stdoutSink } from './sinks/stdout.js';
|
|
7
|
+
export type { StdoutSinkOptions } from './sinks/stdout.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** auditInterceptor (F-OBS-01) — captures a full record of every call. */
|
|
2
|
+
import type { Interceptor } from '../base.js';
|
|
3
|
+
import type { AuditSink } from './sink.js';
|
|
4
|
+
export declare const AUDIT_NAME = "audit";
|
|
5
|
+
export interface AuditInterceptorOptions {
|
|
6
|
+
sink?: AuditSink | 'stdout';
|
|
7
|
+
}
|
|
8
|
+
/** Factory: build an audit interceptor. */
|
|
9
|
+
export declare function auditInterceptor(options?: AuditInterceptorOptions): Interceptor;
|
|
10
|
+
/** True if an interceptor is the audit interceptor (used by dev-mode auto-wiring). */
|
|
11
|
+
export declare function isAuditInterceptor(i: Interceptor): boolean;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/** auditInterceptor (F-OBS-01) — captures a full record of every call. */
|
|
2
|
+
import { AuditRecord } from './record.js';
|
|
3
|
+
import { stdoutSink } from './sinks/stdout.js';
|
|
4
|
+
const PROMPT_HASH_KEY = 'audit_prompt_hash';
|
|
5
|
+
export const AUDIT_NAME = 'audit';
|
|
6
|
+
/**
|
|
7
|
+
* Build an AuditRecord per request and write it to a sink.
|
|
8
|
+
*
|
|
9
|
+
* Register this as the outermost interceptor so its `after` runs last and sees
|
|
10
|
+
* the final, fully-processed response. It hashes the (already PII-redacted)
|
|
11
|
+
* prompt in `before` and the response in `after` — content is never stored,
|
|
12
|
+
* only digests and metadata.
|
|
13
|
+
*/
|
|
14
|
+
class AuditInterceptor {
|
|
15
|
+
name = AUDIT_NAME;
|
|
16
|
+
dryRunSafe = true; // auditing is observation-only, so it always runs
|
|
17
|
+
sink;
|
|
18
|
+
constructor(options = {}) {
|
|
19
|
+
this.sink = resolveSink(options.sink);
|
|
20
|
+
}
|
|
21
|
+
async before(request, ctx) {
|
|
22
|
+
ctx.state[PROMPT_HASH_KEY] = AuditRecord.hashText(request.promptText());
|
|
23
|
+
return request;
|
|
24
|
+
}
|
|
25
|
+
async after(response, ctx) {
|
|
26
|
+
const record = new AuditRecord({
|
|
27
|
+
traceId: response.traceId,
|
|
28
|
+
parentTraceId: ctx.parentTraceId,
|
|
29
|
+
agentId: ctx.agentId,
|
|
30
|
+
sessionId: ctx.sessionId,
|
|
31
|
+
timestampUtc: AuditRecord.nowUtc(),
|
|
32
|
+
provider: response.provider,
|
|
33
|
+
model: response.model,
|
|
34
|
+
modelVersion: response.modelVersion,
|
|
35
|
+
promptHash: ctx.state[PROMPT_HASH_KEY] ?? '',
|
|
36
|
+
responseHash: AuditRecord.hashText(response.content),
|
|
37
|
+
tokenUsage: response.usage,
|
|
38
|
+
costUsd: response.costUsd,
|
|
39
|
+
latencyMs: response.latencyMs,
|
|
40
|
+
piiEntityTypes: [...ctx.piiEntityTypes],
|
|
41
|
+
piiEntityCounts: { ...ctx.piiEntityCounts },
|
|
42
|
+
interceptorsFired: [...ctx.interceptorsFired],
|
|
43
|
+
cacheHit: response.cacheHit,
|
|
44
|
+
cacheType: response.cacheType,
|
|
45
|
+
guardrailOutcome: ctx.guardrailOutcome,
|
|
46
|
+
riskScore: ctx.riskScore,
|
|
47
|
+
});
|
|
48
|
+
response.audit = record;
|
|
49
|
+
try {
|
|
50
|
+
await this.sink.write(record);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// Auditing must never break the call.
|
|
54
|
+
// eslint-disable-next-line no-console
|
|
55
|
+
console.error(`[gavio:audit] sink write failed for trace ${record.traceId}`);
|
|
56
|
+
}
|
|
57
|
+
return response;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function resolveSink(sink) {
|
|
61
|
+
if (sink === undefined || sink === 'stdout')
|
|
62
|
+
return stdoutSink();
|
|
63
|
+
return sink;
|
|
64
|
+
}
|
|
65
|
+
/** Factory: build an audit interceptor. */
|
|
66
|
+
export function auditInterceptor(options = {}) {
|
|
67
|
+
return new AuditInterceptor(options);
|
|
68
|
+
}
|
|
69
|
+
/** True if an interceptor is the audit interceptor (used by dev-mode auto-wiring). */
|
|
70
|
+
export function isAuditInterceptor(i) {
|
|
71
|
+
return i.name === AUDIT_NAME;
|
|
72
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/** AuditRecord — the immutable, per-request audit entry. */
|
|
2
|
+
import { TokenUsage } from '../../types.js';
|
|
3
|
+
export declare const SCHEMA_VERSION = "1.0";
|
|
4
|
+
export interface AuditRecordInit {
|
|
5
|
+
traceId: string;
|
|
6
|
+
provider: string;
|
|
7
|
+
model: string;
|
|
8
|
+
timestampUtc: string;
|
|
9
|
+
parentTraceId?: string | null;
|
|
10
|
+
agentId?: string | null;
|
|
11
|
+
sessionId?: string | null;
|
|
12
|
+
modelVersion?: string;
|
|
13
|
+
promptHash?: string;
|
|
14
|
+
responseHash?: string;
|
|
15
|
+
tokenUsage?: TokenUsage;
|
|
16
|
+
costUsd?: number;
|
|
17
|
+
latencyMs?: number;
|
|
18
|
+
piiEntityTypes?: string[];
|
|
19
|
+
piiEntityCounts?: Record<string, number>;
|
|
20
|
+
interceptorsFired?: string[];
|
|
21
|
+
cacheHit?: boolean;
|
|
22
|
+
cacheType?: string | null;
|
|
23
|
+
guardrailOutcome?: string | null;
|
|
24
|
+
riskScore?: number | null;
|
|
25
|
+
previousHash?: string;
|
|
26
|
+
schemaVersion?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* One append-only audit entry. Carries metadata only — never raw content.
|
|
30
|
+
*
|
|
31
|
+
* `promptHash` / `responseHash` are SHA-256 digests so the entry is verifiable
|
|
32
|
+
* without storing sensitive text. `previousHash` is reserved for the v0.2.0
|
|
33
|
+
* hash-chain (F-OBS-02); empty in v0.1.0.
|
|
34
|
+
*/
|
|
35
|
+
export declare class AuditRecord {
|
|
36
|
+
traceId: string;
|
|
37
|
+
provider: string;
|
|
38
|
+
model: string;
|
|
39
|
+
timestampUtc: string;
|
|
40
|
+
parentTraceId: string | null;
|
|
41
|
+
agentId: string | null;
|
|
42
|
+
sessionId: string | null;
|
|
43
|
+
modelVersion: string;
|
|
44
|
+
promptHash: string;
|
|
45
|
+
responseHash: string;
|
|
46
|
+
tokenUsage: TokenUsage;
|
|
47
|
+
costUsd: number;
|
|
48
|
+
latencyMs: number;
|
|
49
|
+
piiEntityTypes: string[];
|
|
50
|
+
piiEntityCounts: Record<string, number>;
|
|
51
|
+
interceptorsFired: string[];
|
|
52
|
+
cacheHit: boolean;
|
|
53
|
+
cacheType: string | null;
|
|
54
|
+
guardrailOutcome: string | null;
|
|
55
|
+
riskScore: number | null;
|
|
56
|
+
previousHash: string;
|
|
57
|
+
schemaVersion: string;
|
|
58
|
+
constructor(init: AuditRecordInit);
|
|
59
|
+
static nowUtc(): string;
|
|
60
|
+
static hashText(text: string): string;
|
|
61
|
+
toJSON(): Record<string, unknown>;
|
|
62
|
+
/** Stable JSON with sorted keys — used for the v0.2.0 hash chain. */
|
|
63
|
+
toCanonicalJson(): string;
|
|
64
|
+
/** Hash of this record's content — used to build the v0.2.0 chain. */
|
|
65
|
+
contentHash(): string;
|
|
66
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/** AuditRecord — the immutable, per-request audit entry. */
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { TokenUsage } from '../../types.js';
|
|
4
|
+
export const SCHEMA_VERSION = '1.0';
|
|
5
|
+
function sha256(text) {
|
|
6
|
+
return createHash('sha256').update(text, 'utf-8').digest('hex');
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* One append-only audit entry. Carries metadata only — never raw content.
|
|
10
|
+
*
|
|
11
|
+
* `promptHash` / `responseHash` are SHA-256 digests so the entry is verifiable
|
|
12
|
+
* without storing sensitive text. `previousHash` is reserved for the v0.2.0
|
|
13
|
+
* hash-chain (F-OBS-02); empty in v0.1.0.
|
|
14
|
+
*/
|
|
15
|
+
export class AuditRecord {
|
|
16
|
+
traceId;
|
|
17
|
+
provider;
|
|
18
|
+
model;
|
|
19
|
+
timestampUtc;
|
|
20
|
+
parentTraceId;
|
|
21
|
+
agentId;
|
|
22
|
+
sessionId;
|
|
23
|
+
modelVersion;
|
|
24
|
+
promptHash;
|
|
25
|
+
responseHash;
|
|
26
|
+
tokenUsage;
|
|
27
|
+
costUsd;
|
|
28
|
+
latencyMs;
|
|
29
|
+
piiEntityTypes;
|
|
30
|
+
piiEntityCounts;
|
|
31
|
+
interceptorsFired;
|
|
32
|
+
cacheHit;
|
|
33
|
+
cacheType;
|
|
34
|
+
guardrailOutcome;
|
|
35
|
+
riskScore;
|
|
36
|
+
previousHash;
|
|
37
|
+
schemaVersion;
|
|
38
|
+
constructor(init) {
|
|
39
|
+
this.traceId = init.traceId;
|
|
40
|
+
this.provider = init.provider;
|
|
41
|
+
this.model = init.model;
|
|
42
|
+
this.timestampUtc = init.timestampUtc;
|
|
43
|
+
this.parentTraceId = init.parentTraceId ?? null;
|
|
44
|
+
this.agentId = init.agentId ?? null;
|
|
45
|
+
this.sessionId = init.sessionId ?? null;
|
|
46
|
+
this.modelVersion = init.modelVersion ?? '';
|
|
47
|
+
this.promptHash = init.promptHash ?? '';
|
|
48
|
+
this.responseHash = init.responseHash ?? '';
|
|
49
|
+
this.tokenUsage = init.tokenUsage ?? new TokenUsage();
|
|
50
|
+
this.costUsd = init.costUsd ?? 0.0;
|
|
51
|
+
this.latencyMs = init.latencyMs ?? 0;
|
|
52
|
+
this.piiEntityTypes = init.piiEntityTypes ?? [];
|
|
53
|
+
this.piiEntityCounts = init.piiEntityCounts ?? {};
|
|
54
|
+
this.interceptorsFired = init.interceptorsFired ?? [];
|
|
55
|
+
this.cacheHit = init.cacheHit ?? false;
|
|
56
|
+
this.cacheType = init.cacheType ?? null;
|
|
57
|
+
this.guardrailOutcome = init.guardrailOutcome ?? null;
|
|
58
|
+
this.riskScore = init.riskScore ?? null;
|
|
59
|
+
this.previousHash = init.previousHash ?? '';
|
|
60
|
+
this.schemaVersion = init.schemaVersion ?? SCHEMA_VERSION;
|
|
61
|
+
}
|
|
62
|
+
static nowUtc() {
|
|
63
|
+
return new Date().toISOString();
|
|
64
|
+
}
|
|
65
|
+
static hashText(text) {
|
|
66
|
+
return sha256(text);
|
|
67
|
+
}
|
|
68
|
+
toJSON() {
|
|
69
|
+
return {
|
|
70
|
+
traceId: this.traceId,
|
|
71
|
+
parentTraceId: this.parentTraceId,
|
|
72
|
+
agentId: this.agentId,
|
|
73
|
+
sessionId: this.sessionId,
|
|
74
|
+
provider: this.provider,
|
|
75
|
+
model: this.model,
|
|
76
|
+
modelVersion: this.modelVersion,
|
|
77
|
+
timestampUtc: this.timestampUtc,
|
|
78
|
+
promptHash: this.promptHash,
|
|
79
|
+
responseHash: this.responseHash,
|
|
80
|
+
tokenUsage: this.tokenUsage.toJSON(),
|
|
81
|
+
costUsd: this.costUsd,
|
|
82
|
+
latencyMs: this.latencyMs,
|
|
83
|
+
piiEntityTypes: this.piiEntityTypes,
|
|
84
|
+
piiEntityCounts: this.piiEntityCounts,
|
|
85
|
+
interceptorsFired: this.interceptorsFired,
|
|
86
|
+
cacheHit: this.cacheHit,
|
|
87
|
+
cacheType: this.cacheType,
|
|
88
|
+
guardrailOutcome: this.guardrailOutcome,
|
|
89
|
+
riskScore: this.riskScore,
|
|
90
|
+
previousHash: this.previousHash,
|
|
91
|
+
schemaVersion: this.schemaVersion,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/** Stable JSON with sorted keys — used for the v0.2.0 hash chain. */
|
|
95
|
+
toCanonicalJson() {
|
|
96
|
+
const data = this.toJSON();
|
|
97
|
+
return JSON.stringify(data, Object.keys(data).sort());
|
|
98
|
+
}
|
|
99
|
+
/** Hash of this record's content — used to build the v0.2.0 chain. */
|
|
100
|
+
contentHash() {
|
|
101
|
+
return sha256(this.toCanonicalJson());
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** AuditSink — the extensible destination for audit records. */
|
|
2
|
+
import type { AuditRecord } from './record.js';
|
|
3
|
+
/** Where audit records go. Implement `write` to add a backend. */
|
|
4
|
+
export interface AuditSink {
|
|
5
|
+
write(record: AuditRecord): Promise<void>;
|
|
6
|
+
/** Flush/close any resources. Optional. */
|
|
7
|
+
close?(): Promise<void>;
|
|
8
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { stdoutSink } from './stdout.js';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** stdoutSink — human-readable audit output for development (F-OBS-05). */
|
|
2
|
+
import type { AuditSink } from '../sink.js';
|
|
3
|
+
export interface StdoutSinkOptions {
|
|
4
|
+
pretty?: boolean;
|
|
5
|
+
write?: (line: string) => void;
|
|
6
|
+
}
|
|
7
|
+
/** Print each audit record to stdout. Zero dependencies. */
|
|
8
|
+
export declare function stdoutSink(options?: StdoutSinkOptions): AuditSink;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** stdoutSink — human-readable audit output for development (F-OBS-05). */
|
|
2
|
+
/** Print each audit record to stdout. Zero dependencies. */
|
|
3
|
+
export function stdoutSink(options = {}) {
|
|
4
|
+
const pretty = options.pretty ?? true;
|
|
5
|
+
// eslint-disable-next-line no-console
|
|
6
|
+
const emit = options.write ?? ((line) => console.log(line));
|
|
7
|
+
return {
|
|
8
|
+
async write(record) {
|
|
9
|
+
const data = record.toJSON();
|
|
10
|
+
emit(pretty ? formatPretty(data) : JSON.stringify(data));
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function formatPretty(data) {
|
|
15
|
+
const usage = data['tokenUsage'];
|
|
16
|
+
const piiTypes = data['piiEntityTypes'];
|
|
17
|
+
const pii = piiTypes.length > 0 ? piiTypes : ['none'];
|
|
18
|
+
const interceptors = data['interceptorsFired'];
|
|
19
|
+
const traceId = String(data['traceId']);
|
|
20
|
+
const cost = Number(data['costUsd']);
|
|
21
|
+
return ('[gavio:audit] ' +
|
|
22
|
+
`trace=${traceId.slice(0, 18)}… ` +
|
|
23
|
+
`${String(data['provider'])}/${String(data['model'])} ` +
|
|
24
|
+
`tokens=${usage.totalTokens} ` +
|
|
25
|
+
`cost=$${cost.toFixed(6)} ` +
|
|
26
|
+
`latency=${String(data['latencyMs'])}ms ` +
|
|
27
|
+
`cache=${data['cacheHit'] ? 'HIT' : 'miss'} ` +
|
|
28
|
+
`pii=${pii.join(',')} ` +
|
|
29
|
+
`interceptors=[${interceptors.join(',')}]`);
|
|
30
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** The Interceptor interface — the unit of composition in Gavio. */
|
|
2
|
+
import type { InterceptorContext } from '../context.js';
|
|
3
|
+
import type { GavioRequest } from '../request.js';
|
|
4
|
+
import type { GavioResponse } from '../response.js';
|
|
5
|
+
/**
|
|
6
|
+
* A pre/post hook around the provider call.
|
|
7
|
+
*
|
|
8
|
+
* `before` runs in registration order on the request; `after` runs in reverse
|
|
9
|
+
* order on the response (onion model). Either may be omitted. Throwing from
|
|
10
|
+
* `before` aborts the call.
|
|
11
|
+
*/
|
|
12
|
+
export interface Interceptor {
|
|
13
|
+
/** Unique name used in audit logs and metrics. */
|
|
14
|
+
readonly name: string;
|
|
15
|
+
/** Pre-interceptor: runs before the provider call. */
|
|
16
|
+
before?(request: GavioRequest, ctx: InterceptorContext): Promise<GavioRequest> | GavioRequest;
|
|
17
|
+
/** Post-interceptor: runs after the provider call. */
|
|
18
|
+
after?(response: GavioResponse, ctx: InterceptorContext): Promise<GavioResponse> | GavioResponse;
|
|
19
|
+
/** Called if the provider call or a downstream interceptor throws. */
|
|
20
|
+
onError?(error: Error, ctx: InterceptorContext): void | Promise<void>;
|
|
21
|
+
/** If true (default), participates in dry-run mode (logs only). */
|
|
22
|
+
readonly dryRunSafe?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/** A function that takes the final request and returns a response (the provider call). */
|
|
25
|
+
export type Executor = (request: GavioRequest) => Promise<GavioResponse>;
|
|
26
|
+
/**
|
|
27
|
+
* Base class for executor-wrapping reliability policies.
|
|
28
|
+
*
|
|
29
|
+
* Retry, timeout, and fallback can't be expressed as plain before/after hooks:
|
|
30
|
+
* they need to re-invoke (or race) the executor. They implement `around` so the
|
|
31
|
+
* Gateway composes them *around* the provider call, innermost-last.
|
|
32
|
+
*/
|
|
33
|
+
export interface ExecutorPolicy extends Interceptor {
|
|
34
|
+
readonly isExecutorPolicy: true;
|
|
35
|
+
around(request: GavioRequest, ctx: InterceptorContext, callNext: Executor): Promise<GavioResponse>;
|
|
36
|
+
}
|
|
37
|
+
export declare function isExecutorPolicy(i: Interceptor): i is ExecutorPolicy;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CacheBackend — the key/value contract behind the cache interceptors.
|
|
3
|
+
*
|
|
4
|
+
* The full SemanticCache interceptor lands in v0.2.0 (F-CACHE-01/02). v0.1.0
|
|
5
|
+
* ships the backend interface and the in-memory backend so dev mode has a
|
|
6
|
+
* working, dependency-free cache substrate.
|
|
7
|
+
*/
|
|
8
|
+
/** A minimal async key/value store. */
|
|
9
|
+
export interface CacheBackend {
|
|
10
|
+
get(key: string): Promise<unknown | null>;
|
|
11
|
+
set(key: string, value: unknown, ttlSeconds?: number | null): Promise<void>;
|
|
12
|
+
delete(key: string): Promise<void>;
|
|
13
|
+
clear(): Promise<void>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CacheBackend — the key/value contract behind the cache interceptors.
|
|
3
|
+
*
|
|
4
|
+
* The full SemanticCache interceptor lands in v0.2.0 (F-CACHE-01/02). v0.1.0
|
|
5
|
+
* ships the backend interface and the in-memory backend so dev mode has a
|
|
6
|
+
* working, dependency-free cache substrate.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { memoryCacheBackend } from './memory.js';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** In-memory cache backend (F-CACHE-03) — default zero-dependency dev backend. */
|
|
2
|
+
import type { CacheBackend } from '../backend.js';
|
|
3
|
+
export interface MemoryCacheBackendOptions {
|
|
4
|
+
maxSize?: number;
|
|
5
|
+
}
|
|
6
|
+
/** Factory: build an in-memory cache backend. */
|
|
7
|
+
export declare function memoryCacheBackend(options?: MemoryCacheBackendOptions): CacheBackend;
|