@apifuse/provider-sdk 2.2.0-beta.60 → 2.2.0-beta.62
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/AUTHORING.md +17 -16
- package/CHANGELOG.md +8 -0
- package/bin/apifuse-dev.ts +5 -7
- package/bin/apifuse-pack-types.ts +26 -0
- package/bin/apifuse-perf.ts +4 -6
- package/bin/apifuse-record.ts +4 -7
- package/bin/apifuse-submit-check.ts +2 -2
- package/dist/define.d.ts +3 -2
- package/dist/define.js +1 -1
- package/dist/dev.js +3 -1
- package/dist/engine.d.ts +7 -6
- package/dist/engine.js +3 -4
- package/dist/error-resolution.js +21 -4
- package/dist/errors.d.ts +3 -0
- package/dist/errors.js +9 -0
- package/dist/handle-meta.d.ts +55 -0
- package/dist/handle-meta.js +57 -0
- package/dist/handle.d.ts +208 -0
- package/dist/handle.js +299 -0
- package/dist/i18n/catalog.js +21 -1
- package/dist/index.d.ts +7 -4
- package/dist/index.js +6 -3
- package/dist/lint.d.ts +3 -0
- package/dist/lint.js +372 -47
- package/dist/provider.d.ts +5 -3
- package/dist/provider.js +4 -2
- package/dist/runtime/handle-wordlist.d.ts +43 -0
- package/dist/runtime/{choice-wordlist.js → handle-wordlist.js} +127 -9
- package/dist/runtime/handle.d.ts +71 -0
- package/dist/runtime/handle.js +900 -0
- package/dist/runtime/http-telemetry-binding.d.ts +10 -0
- package/dist/runtime/http-telemetry-binding.js +152 -0
- package/dist/runtime/http-telemetry-guard.d.ts +6 -0
- package/dist/runtime/http-telemetry-guard.js +150 -0
- package/dist/runtime/http-telemetry.d.ts +104 -0
- package/dist/runtime/http-telemetry.js +190 -0
- package/dist/runtime/http.d.ts +31 -0
- package/dist/runtime/http.js +222 -146
- package/dist/runtime/native-network.d.ts +10 -1
- package/dist/runtime/native-network.js +230 -29
- package/dist/runtime/native-telemetry.d.ts +142 -0
- package/dist/runtime/native-telemetry.js +231 -0
- package/dist/runtime/state.d.ts +4 -1
- package/dist/runtime/state.js +32 -17
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.js +2 -0
- package/dist/server/sensitive-values.d.ts +1 -1
- package/dist/server/sensitive-values.js +0 -3
- package/dist/server/serve-implementation.d.ts +6 -11
- package/dist/server/serve-implementation.js +119 -52
- package/dist/testing/run.js +10 -7
- package/dist/types.d.ts +4 -107
- package/package.json +1 -1
- package/src/define.ts +4 -3
- package/src/dev.ts +3 -1
- package/src/engine.ts +5 -6
- package/src/error-resolution.ts +21 -4
- package/src/errors.ts +13 -0
- package/src/handle-meta.ts +93 -0
- package/src/handle.ts +612 -0
- package/src/i18n/catalog.ts +23 -1
- package/src/index.ts +45 -13
- package/src/lint.ts +437 -55
- package/src/provider.ts +19 -20
- package/src/runtime/{choice-wordlist.ts → handle-wordlist.ts} +130 -9
- package/src/runtime/handle.ts +1172 -0
- package/src/runtime/http-telemetry-binding.ts +162 -0
- package/src/runtime/http-telemetry-guard.ts +155 -0
- package/src/runtime/http-telemetry.ts +292 -0
- package/src/runtime/http.ts +295 -173
- package/src/runtime/native-network.ts +281 -33
- package/src/runtime/native-telemetry.ts +366 -0
- package/src/runtime/state.ts +44 -16
- package/src/server/index.ts +30 -0
- package/src/server/sensitive-values.ts +0 -3
- package/src/server/serve-implementation.ts +127 -89
- package/src/testing/run.ts +11 -7
- package/src/types.ts +4 -137
- package/dist/choice-token.d.ts +0 -24
- package/dist/choice-token.js +0 -74
- package/dist/runtime/choice-wordlist.d.ts +0 -9
- package/dist/runtime/choice.d.ts +0 -27
- package/dist/runtime/choice.js +0 -801
- package/src/choice-token.ts +0 -165
- package/src/runtime/choice.ts +0 -1197
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { Buffer } from "node:buffer";
|
|
2
|
+
import { closedEnum } from "./request-telemetry.js";
|
|
3
|
+
const MAX_SAMPLES = 24;
|
|
4
|
+
function integer(value) {
|
|
5
|
+
return Math.max(0, Math.floor(Number.isFinite(value) ? value : 0));
|
|
6
|
+
}
|
|
7
|
+
function saturatingAdd(a, b) {
|
|
8
|
+
if (!Number.isFinite(a) || !Number.isFinite(b))
|
|
9
|
+
return Number.MAX_SAFE_INTEGER;
|
|
10
|
+
return Math.min(Number.MAX_SAFE_INTEGER, integer(a) + integer(b));
|
|
11
|
+
}
|
|
12
|
+
function boundedText(value, redact) {
|
|
13
|
+
let result;
|
|
14
|
+
try {
|
|
15
|
+
result = redact ? redact(value) : value;
|
|
16
|
+
if (typeof result !== "string")
|
|
17
|
+
return "[REDACTION_FAILED]";
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return "[REDACTION_FAILED]";
|
|
21
|
+
}
|
|
22
|
+
// Do not slice caller text: a substring may retain the entire vendor response.
|
|
23
|
+
const length = Math.min(result.length, 300);
|
|
24
|
+
const units = Buffer.alloc(length * 2);
|
|
25
|
+
for (let index = 0; index < length; index++)
|
|
26
|
+
units.writeUInt16LE(result.charCodeAt(index), index * 2);
|
|
27
|
+
return units.toString("utf16le");
|
|
28
|
+
}
|
|
29
|
+
function diagnostics(value, redact) {
|
|
30
|
+
const result = {};
|
|
31
|
+
for (const key of [
|
|
32
|
+
"host",
|
|
33
|
+
"serverName",
|
|
34
|
+
"protocol",
|
|
35
|
+
"sessionId",
|
|
36
|
+
"expiresAt",
|
|
37
|
+
"errorName",
|
|
38
|
+
"errorMessage",
|
|
39
|
+
"causeName",
|
|
40
|
+
"causeMessage",
|
|
41
|
+
"systemCode",
|
|
42
|
+
]) {
|
|
43
|
+
if (value[key] !== undefined)
|
|
44
|
+
result[key] = boundedText(value[key], redact);
|
|
45
|
+
}
|
|
46
|
+
for (const key of ["port", "timeoutMs", "idleTimeoutMs", "status", "socksReplyCode"]) {
|
|
47
|
+
if (value[key] !== undefined)
|
|
48
|
+
result[key] = integer(value[key]);
|
|
49
|
+
}
|
|
50
|
+
if (value.sticky !== undefined)
|
|
51
|
+
result.sticky = value.sticky;
|
|
52
|
+
if (value.missingFields)
|
|
53
|
+
result.missingFields = value.missingFields
|
|
54
|
+
.slice(0, MAX_SAMPLES)
|
|
55
|
+
.map((field) => boundedText(field, redact));
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
function copyDiagnostics(value) {
|
|
59
|
+
return { ...value, ...(value.missingFields ? { missingFields: [...value.missingFields] } : {}) };
|
|
60
|
+
}
|
|
61
|
+
export class NativeTelemetryCollector {
|
|
62
|
+
key = "native";
|
|
63
|
+
#redact;
|
|
64
|
+
#recorded = false;
|
|
65
|
+
#attempts = 0;
|
|
66
|
+
#connectMs = 0;
|
|
67
|
+
#tunnelMs = 0;
|
|
68
|
+
#vendorSkips = 0;
|
|
69
|
+
#vendorSkipReasons = new Map();
|
|
70
|
+
#lifecycle = {
|
|
71
|
+
drain: 0,
|
|
72
|
+
drain_acknowledged: 0,
|
|
73
|
+
drain_error: 0,
|
|
74
|
+
drain_missing_handler: 0,
|
|
75
|
+
idle: 0,
|
|
76
|
+
expiry: 0,
|
|
77
|
+
};
|
|
78
|
+
#bytesIn = 0;
|
|
79
|
+
#bytesOut = 0;
|
|
80
|
+
#lastErrorCode;
|
|
81
|
+
#lastErrorDiagnostics;
|
|
82
|
+
#attemptSamples = [];
|
|
83
|
+
#attemptSamplesDropped = 0;
|
|
84
|
+
#vendorSkipSamples = [];
|
|
85
|
+
#vendorSkipSamplesDropped = 0;
|
|
86
|
+
constructor(options = {}) {
|
|
87
|
+
this.#redact = options.redact;
|
|
88
|
+
}
|
|
89
|
+
recordConnect(event) {
|
|
90
|
+
this.#recorded = true;
|
|
91
|
+
const ms = saturatingAdd(0, event.ms);
|
|
92
|
+
const tunnelMs = saturatingAdd(0, event.tunnelMs);
|
|
93
|
+
this.#attempts = saturatingAdd(this.#attempts, 1);
|
|
94
|
+
this.#connectMs = saturatingAdd(this.#connectMs, ms);
|
|
95
|
+
this.#tunnelMs = saturatingAdd(this.#tunnelMs, tunnelMs);
|
|
96
|
+
if (event.errorCode)
|
|
97
|
+
this.recordError({ errorCode: event.errorCode, diagnostics: event.diagnostics });
|
|
98
|
+
if (this.#attemptSamples.length < MAX_SAMPLES) {
|
|
99
|
+
this.#attemptSamples.push({
|
|
100
|
+
n: this.#attempts,
|
|
101
|
+
kind: event.kind,
|
|
102
|
+
outcome: event.outcome,
|
|
103
|
+
ms,
|
|
104
|
+
tunnelMs,
|
|
105
|
+
proxyUsed: event.proxyUsed,
|
|
106
|
+
...(event.vendor ? { vendor: event.vendor } : {}),
|
|
107
|
+
...(event.errorCode ? { errorCode: event.errorCode } : {}),
|
|
108
|
+
...(event.diagnostics ? { diagnostics: diagnostics(event.diagnostics, this.#redact) } : {}),
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
else
|
|
112
|
+
this.#attemptSamplesDropped = saturatingAdd(this.#attemptSamplesDropped, 1);
|
|
113
|
+
}
|
|
114
|
+
recordVendorSkip(event) {
|
|
115
|
+
this.#recorded = true;
|
|
116
|
+
this.#vendorSkips = saturatingAdd(this.#vendorSkips, 1);
|
|
117
|
+
this.#vendorSkipReasons.set(event.reason, saturatingAdd(this.#vendorSkipReasons.get(event.reason) ?? 0, 1));
|
|
118
|
+
if (this.#vendorSkipSamples.length < MAX_SAMPLES) {
|
|
119
|
+
this.#vendorSkipSamples.push({
|
|
120
|
+
vendor: event.vendor,
|
|
121
|
+
reason: event.reason,
|
|
122
|
+
...(event.diagnostics ? { diagnostics: diagnostics(event.diagnostics, this.#redact) } : {}),
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
else
|
|
126
|
+
this.#vendorSkipSamplesDropped = saturatingAdd(this.#vendorSkipSamplesDropped, 1);
|
|
127
|
+
}
|
|
128
|
+
recordLifecycle(event) {
|
|
129
|
+
this.#recorded = true;
|
|
130
|
+
this.#lifecycle[event.kind] = saturatingAdd(this.#lifecycle[event.kind], 1);
|
|
131
|
+
if (event.errorCode)
|
|
132
|
+
this.recordError({ errorCode: event.errorCode, diagnostics: event.diagnostics });
|
|
133
|
+
}
|
|
134
|
+
recordBytes(event) {
|
|
135
|
+
this.#recorded = true;
|
|
136
|
+
if (event.direction === "in")
|
|
137
|
+
this.#bytesIn = saturatingAdd(this.#bytesIn, event.bytes);
|
|
138
|
+
else
|
|
139
|
+
this.#bytesOut = saturatingAdd(this.#bytesOut, event.bytes);
|
|
140
|
+
}
|
|
141
|
+
recordError(event) {
|
|
142
|
+
this.#recorded = true;
|
|
143
|
+
this.#lastErrorCode = event.errorCode;
|
|
144
|
+
this.#lastErrorDiagnostics = event.diagnostics
|
|
145
|
+
? diagnostics(event.diagnostics, this.#redact)
|
|
146
|
+
: undefined;
|
|
147
|
+
}
|
|
148
|
+
toLogPayload() {
|
|
149
|
+
if (!this.#recorded)
|
|
150
|
+
return undefined;
|
|
151
|
+
return {
|
|
152
|
+
attempts: this.#attempts,
|
|
153
|
+
connectMs: this.#connectMs,
|
|
154
|
+
tunnelMs: this.#tunnelMs,
|
|
155
|
+
vendorSkips: this.#vendorSkips,
|
|
156
|
+
vendorSkipReasons: [...this.#vendorSkipReasons].map(([reason, count]) => ({ reason, count })),
|
|
157
|
+
drain: this.#lifecycle.drain,
|
|
158
|
+
drainAcknowledged: this.#lifecycle.drain_acknowledged,
|
|
159
|
+
drainErrors: this.#lifecycle.drain_error,
|
|
160
|
+
drainMissingHandler: this.#lifecycle.drain_missing_handler,
|
|
161
|
+
idle: this.#lifecycle.idle,
|
|
162
|
+
expiry: this.#lifecycle.expiry,
|
|
163
|
+
bytesIn: this.#bytesIn,
|
|
164
|
+
bytesOut: this.#bytesOut,
|
|
165
|
+
...(this.#lastErrorCode ? { lastErrorCode: this.#lastErrorCode } : {}),
|
|
166
|
+
...(this.#lastErrorDiagnostics
|
|
167
|
+
? { lastErrorDiagnostics: copyDiagnostics(this.#lastErrorDiagnostics) }
|
|
168
|
+
: {}),
|
|
169
|
+
...(this.#attemptSamples.length
|
|
170
|
+
? {
|
|
171
|
+
attemptSamples: this.#attemptSamples.map((sample) => ({
|
|
172
|
+
...sample,
|
|
173
|
+
...(sample.diagnostics ? { diagnostics: copyDiagnostics(sample.diagnostics) } : {}),
|
|
174
|
+
})),
|
|
175
|
+
}
|
|
176
|
+
: {}),
|
|
177
|
+
...(this.#attemptSamplesDropped
|
|
178
|
+
? { attemptSamplesDropped: this.#attemptSamplesDropped }
|
|
179
|
+
: {}),
|
|
180
|
+
...(this.#vendorSkipSamples.length
|
|
181
|
+
? {
|
|
182
|
+
vendorSkipSamples: this.#vendorSkipSamples.map((sample) => ({
|
|
183
|
+
...sample,
|
|
184
|
+
...(sample.diagnostics ? { diagnostics: copyDiagnostics(sample.diagnostics) } : {}),
|
|
185
|
+
})),
|
|
186
|
+
}
|
|
187
|
+
: {}),
|
|
188
|
+
...(this.#vendorSkipSamplesDropped
|
|
189
|
+
? { vendorSkipSamplesDropped: this.#vendorSkipSamplesDropped }
|
|
190
|
+
: {}),
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
toHeaderPayload(log) {
|
|
194
|
+
return {
|
|
195
|
+
attempts: log.attempts,
|
|
196
|
+
connectMs: log.connectMs,
|
|
197
|
+
tunnelMs: log.tunnelMs,
|
|
198
|
+
vendorSkips: log.vendorSkips,
|
|
199
|
+
vendorSkipReasons: log.vendorSkipReasons.map(({ reason, count }) => ({
|
|
200
|
+
reason: closedEnum(reason),
|
|
201
|
+
count,
|
|
202
|
+
})),
|
|
203
|
+
drain: log.drain,
|
|
204
|
+
drainAcknowledged: log.drainAcknowledged,
|
|
205
|
+
drainErrors: log.drainErrors,
|
|
206
|
+
drainMissingHandler: log.drainMissingHandler,
|
|
207
|
+
idle: log.idle,
|
|
208
|
+
expiry: log.expiry,
|
|
209
|
+
bytesIn: log.bytesIn,
|
|
210
|
+
bytesOut: log.bytesOut,
|
|
211
|
+
...(log.lastErrorCode ? { lastErrorCode: closedEnum(log.lastErrorCode) } : {}),
|
|
212
|
+
...(log.attemptSamples
|
|
213
|
+
? {
|
|
214
|
+
attemptSamples: log.attemptSamples.map((sample) => ({
|
|
215
|
+
n: sample.n,
|
|
216
|
+
kind: closedEnum(sample.kind),
|
|
217
|
+
outcome: closedEnum(sample.outcome),
|
|
218
|
+
ms: sample.ms,
|
|
219
|
+
tunnelMs: sample.tunnelMs,
|
|
220
|
+
proxyUsed: sample.proxyUsed,
|
|
221
|
+
...(sample.errorCode ? { errorCode: closedEnum(sample.errorCode) } : {}),
|
|
222
|
+
})),
|
|
223
|
+
}
|
|
224
|
+
: {}),
|
|
225
|
+
...(log.attemptSamplesDropped ? { attemptSamplesDropped: log.attemptSamplesDropped } : {}),
|
|
226
|
+
...(log.vendorSkipSamplesDropped
|
|
227
|
+
? { vendorSkipSamplesDropped: log.vendorSkipSamplesDropped }
|
|
228
|
+
: {}),
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
}
|
package/dist/runtime/state.d.ts
CHANGED
|
@@ -15,6 +15,9 @@ export declare function createProviderRuntimeStateFromEnv(options?: {
|
|
|
15
15
|
readonly providerId?: string;
|
|
16
16
|
readonly allowMemoryFallback?: boolean;
|
|
17
17
|
}): ProviderRuntimeState;
|
|
18
|
-
export declare function createMemoryProviderRuntimeState(
|
|
18
|
+
export declare function createMemoryProviderRuntimeState(options?: {
|
|
19
|
+
/** Clock for expiry and timestamps; defaults to `Date.now`. */
|
|
20
|
+
readonly now?: () => number;
|
|
21
|
+
}): ProviderRuntimeState;
|
|
19
22
|
export declare function createUnsupportedProviderRuntimeState(): ProviderRuntimeState;
|
|
20
23
|
export {};
|
package/dist/runtime/state.js
CHANGED
|
@@ -60,9 +60,12 @@ if not indexed and redis.call("ZCARD", KEYS[2]) >= max_entries then
|
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
if current_decoded and type(current_decoded.createdAt) == "string" then
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
envelope
|
|
63
|
+
-- Preserve the original createdAt by patching the encoded envelope in place.
|
|
64
|
+
-- The envelope puts its metadata before "value", so the first match is the
|
|
65
|
+
-- envelope's own key, never a provider value; re-encoding with cjson would
|
|
66
|
+
-- silently turn [] inside the value into {}.
|
|
67
|
+
local preserved = string.gsub(current_decoded.createdAt, "%%", "%%%%")
|
|
68
|
+
envelope = (string.gsub(envelope, '"createdAt":"[^"]*"', '"createdAt":"' .. preserved .. '"', 1))
|
|
66
69
|
end
|
|
67
70
|
redis.call("SET", KEYS[1], envelope, "PXAT", expires_at)
|
|
68
71
|
redis.call("ZADD", KEYS[2], expires_at, KEYS[1])
|
|
@@ -197,7 +200,11 @@ function isStateTombstone(raw) {
|
|
|
197
200
|
}
|
|
198
201
|
function redisEnvelope(value, version, createdAt, expiresAt) {
|
|
199
202
|
const updatedAt = new Date().toISOString();
|
|
200
|
-
|
|
203
|
+
// Metadata precedes `value` on purpose: the compare-and-set Lua script patches
|
|
204
|
+
// `createdAt` in the encoded string (first occurrence) instead of decoding and
|
|
205
|
+
// re-encoding with cjson, which would turn empty arrays inside `value` into
|
|
206
|
+
// objects. Keep the key order stable.
|
|
207
|
+
return { version, expiresAt, createdAt, updatedAt, value };
|
|
201
208
|
}
|
|
202
209
|
class RedisProviderStateNamespace {
|
|
203
210
|
backend;
|
|
@@ -404,10 +411,12 @@ class UnsupportedProviderRuntimeState {
|
|
|
404
411
|
}
|
|
405
412
|
class MemoryProviderStateNamespace {
|
|
406
413
|
options;
|
|
414
|
+
now;
|
|
407
415
|
// biome-ignore lint/suspicious/noExplicitAny: in-memory state stores heterogeneous generic values by key.
|
|
408
416
|
values = new Map();
|
|
409
|
-
constructor(options) {
|
|
417
|
+
constructor(options, now = Date.now) {
|
|
410
418
|
this.options = options;
|
|
419
|
+
this.now = now;
|
|
411
420
|
}
|
|
412
421
|
enforceValueSize(value) {
|
|
413
422
|
const bytes = Buffer.byteLength(JSON.stringify(value), "utf8");
|
|
@@ -426,7 +435,7 @@ class MemoryProviderStateNamespace {
|
|
|
426
435
|
throw new UnsupportedProviderStateError(`Provider runtime state namespace quota exceeded (${this.options.maxEntries + 1} > ${this.options.maxEntries})`);
|
|
427
436
|
}
|
|
428
437
|
}
|
|
429
|
-
pruneExpired(nowMs =
|
|
438
|
+
pruneExpired(nowMs = this.now()) {
|
|
430
439
|
for (const [key, row] of this.values.entries()) {
|
|
431
440
|
if (row.expiresAt && Date.parse(row.expiresAt) <= nowMs) {
|
|
432
441
|
this.values.delete(key);
|
|
@@ -445,9 +454,9 @@ class MemoryProviderStateNamespace {
|
|
|
445
454
|
async set(key, value, options) {
|
|
446
455
|
this.pruneExpired();
|
|
447
456
|
this.enforceWritePolicy(key, value, options?.ttl);
|
|
448
|
-
const now = new Date().toISOString();
|
|
457
|
+
const now = new Date(this.now()).toISOString();
|
|
449
458
|
const current = this.values.get(key);
|
|
450
|
-
const expiresAt = resolveMemoryStateExpiresAt(options?.ttl ?? this.options.defaultTtl);
|
|
459
|
+
const expiresAt = resolveMemoryStateExpiresAt(options?.ttl ?? this.options.defaultTtl, this.now());
|
|
451
460
|
const row = {
|
|
452
461
|
key,
|
|
453
462
|
value,
|
|
@@ -469,12 +478,12 @@ class MemoryProviderStateNamespace {
|
|
|
469
478
|
return { ok: false, current: current ?? null };
|
|
470
479
|
}
|
|
471
480
|
this.enforceWritePolicy(key, value, options?.ttl);
|
|
472
|
-
const now = new Date().toISOString();
|
|
481
|
+
const now = new Date(this.now()).toISOString();
|
|
473
482
|
const stored = {
|
|
474
483
|
key,
|
|
475
484
|
value,
|
|
476
485
|
version: expectedVersion + 1,
|
|
477
|
-
expiresAt: resolveMemoryStateExpiresAt(options?.ttl ?? this.options.defaultTtl),
|
|
486
|
+
expiresAt: resolveMemoryStateExpiresAt(options?.ttl ?? this.options.defaultTtl, this.now()),
|
|
478
487
|
createdAt: current?.createdAt ?? now,
|
|
479
488
|
updatedAt: now,
|
|
480
489
|
};
|
|
@@ -491,7 +500,10 @@ class MemoryProviderStateNamespace {
|
|
|
491
500
|
class MemoryProviderRuntimeState {
|
|
492
501
|
backend;
|
|
493
502
|
scopeDiscriminator;
|
|
494
|
-
constructor(backend = {
|
|
503
|
+
constructor(backend = {
|
|
504
|
+
namespaces: new Map(),
|
|
505
|
+
now: Date.now,
|
|
506
|
+
}, scopeDiscriminator = MISSING_CONNECTION_SCOPE_DISCRIMINATOR) {
|
|
495
507
|
this.backend = backend;
|
|
496
508
|
this.scopeDiscriminator = scopeDiscriminator;
|
|
497
509
|
}
|
|
@@ -504,15 +516,15 @@ class MemoryProviderRuntimeState {
|
|
|
504
516
|
const existing = this.backend.namespaces.get(namespaceIdentity);
|
|
505
517
|
if (existing)
|
|
506
518
|
return existing;
|
|
507
|
-
const created = new MemoryProviderStateNamespace(options);
|
|
519
|
+
const created = new MemoryProviderStateNamespace(options, this.backend.now);
|
|
508
520
|
this.backend.namespaces.set(namespaceIdentity, created);
|
|
509
521
|
return created;
|
|
510
522
|
}
|
|
511
523
|
}
|
|
512
|
-
function resolveMemoryStateExpiresAt(ttl) {
|
|
524
|
+
function resolveMemoryStateExpiresAt(ttl, nowMs = Date.now()) {
|
|
513
525
|
const match = /^(\d+)(ms|s|m|h|d)$/.exec(ttl ?? "1h");
|
|
514
526
|
if (!match)
|
|
515
|
-
return new Date(
|
|
527
|
+
return new Date(nowMs + 3_600_000).toISOString();
|
|
516
528
|
const amount = Number(match[1]);
|
|
517
529
|
const unit = match[2];
|
|
518
530
|
const multiplier = unit === "ms"
|
|
@@ -524,7 +536,7 @@ function resolveMemoryStateExpiresAt(ttl) {
|
|
|
524
536
|
: unit === "h"
|
|
525
537
|
? 3_600_000
|
|
526
538
|
: 86_400_000;
|
|
527
|
-
return new Date(
|
|
539
|
+
return new Date(nowMs + amount * multiplier).toISOString();
|
|
528
540
|
}
|
|
529
541
|
export function createRedisProviderRuntimeState(options) {
|
|
530
542
|
return new RedisProviderRuntimeState(options);
|
|
@@ -542,8 +554,11 @@ export function createProviderRuntimeStateFromEnv(options = {}) {
|
|
|
542
554
|
}
|
|
543
555
|
return createUnsupportedProviderRuntimeState();
|
|
544
556
|
}
|
|
545
|
-
export function createMemoryProviderRuntimeState() {
|
|
546
|
-
return new MemoryProviderRuntimeState(
|
|
557
|
+
export function createMemoryProviderRuntimeState(options) {
|
|
558
|
+
return new MemoryProviderRuntimeState({
|
|
559
|
+
namespaces: new Map(),
|
|
560
|
+
now: options?.now ?? Date.now,
|
|
561
|
+
});
|
|
547
562
|
}
|
|
548
563
|
export function createUnsupportedProviderRuntimeState() {
|
|
549
564
|
return new UnsupportedProviderRuntimeState();
|
package/dist/server/index.d.ts
CHANGED
|
@@ -12,3 +12,6 @@ export { collectSelfTestSensitiveValues, redactSelfTestText, SELF_TEST_MAX_TEXT_
|
|
|
12
12
|
export { DEFAULT_SELF_TEST_PORT, deriveSelfTestToken, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_ENV, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_PREVIOUS_ENV, PROVIDER_RUNTIME_SELF_TEST_PORT_ENV, resolveSelfTestMasterSecrets, type SelfTestMasterSecrets, verifySelfTestAuthorization, } from "./self-test-token.js";
|
|
13
13
|
export type { AuthFlowRequest, AuthFlowResponse, AuthFlowSuccessResponse, ConnectionMode, OperationConnection, OperationErrorResponse, OperationRequest, OperationResponse, OperationSuccessResponse, } from "./types.js";
|
|
14
14
|
export { AuthFlowRequestSchema, AuthFlowSuccessResponseSchema, ConnectionModeSchema, ErrorEnvelopeSchema, OperationConnectionSchema, OperationErrorResponseSchema, OperationRequestSchema, OperationSuccessResponseSchema, } from "./types.js";
|
|
15
|
+
export { HttpTelemetryCollector, type HttpTelemetrySink, type HttpTelemetryRequestSink, type HttpAttemptTelemetryEvent, type HttpAttemptSample, type HttpTelemetryErrorCode, type HttpTelemetryRetryPayload, type HttpTelemetryLogPayload, type HttpTelemetryHeaderPayload, } from "../runtime/http-telemetry.js";
|
|
16
|
+
export type { HttpRetrySummary } from "../types.js";
|
|
17
|
+
export { NativeTelemetryCollector, type NativeAttemptSample, type NativeConnectTelemetryEvent, type NativeLifecycleTelemetryEvent, type NativeTelemetryDiagnostics, type NativeTelemetryErrorCode, type NativeTelemetryHeaderPayload, type NativeTelemetryKind, type NativeTelemetryLifecycleKind, type NativeTelemetryLogPayload, type NativeTelemetryOutcome, type NativeTelemetrySink, type NativeTelemetryVendorSkipReason, type NativeVendorSkipTelemetryEvent, } from "../runtime/native-telemetry.js";
|
package/dist/server/index.js
CHANGED
|
@@ -6,3 +6,5 @@ export { resolveHealthCheckInputDateTokens, } from "./self-test-input-tokens.js"
|
|
|
6
6
|
export { collectSelfTestSensitiveValues, redactSelfTestText, SELF_TEST_MAX_TEXT_LENGTH, SELF_TEST_REDACTED_PLACEHOLDER, } from "./self-test-redaction.js";
|
|
7
7
|
export { DEFAULT_SELF_TEST_PORT, deriveSelfTestToken, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_ENV, PROVIDER_RUNTIME_SELF_TEST_MASTER_SECRET_PREVIOUS_ENV, PROVIDER_RUNTIME_SELF_TEST_PORT_ENV, resolveSelfTestMasterSecrets, verifySelfTestAuthorization, } from "./self-test-token.js";
|
|
8
8
|
export { AuthFlowRequestSchema, AuthFlowSuccessResponseSchema, ConnectionModeSchema, ErrorEnvelopeSchema, OperationConnectionSchema, OperationErrorResponseSchema, OperationRequestSchema, OperationSuccessResponseSchema, } from "./types.js";
|
|
9
|
+
export { HttpTelemetryCollector, } from "../runtime/http-telemetry.js";
|
|
10
|
+
export { NativeTelemetryCollector, } from "../runtime/native-telemetry.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ProviderDefinition } from "../types.js";
|
|
2
2
|
export declare const SELF_TEST_SENSITIVE_SOURCE_KINDS: readonly ["selfTestMasterSecrets", "providerSecrets", "healthProbeSecrets", "requestCredentials"];
|
|
3
3
|
/** Explicit source allowlist: no environment-name or payload-shape secret sweep. */
|
|
4
|
-
export declare const DIAGNOSTIC_SENSITIVE_SOURCE_KINDS: readonly ["selfTestMasterSecrets", "providerSecrets", "healthProbeSecrets", "requestCredentials", "engineProxyCredentials", "engineSolverKeys", "engineCeremonyLeaseCredentials", "
|
|
4
|
+
export declare const DIAGNOSTIC_SENSITIVE_SOURCE_KINDS: readonly ["selfTestMasterSecrets", "providerSecrets", "healthProbeSecrets", "requestCredentials", "engineProxyCredentials", "engineSolverKeys", "engineCeremonyLeaseCredentials", "ocrCredentials", "sttCredentials", "cdpCredentials", "statefulForwardingSecret", "redisCredentials", "otlpHeaders", "cacheKeyPepper", "sensitiveParams"];
|
|
5
5
|
export type DiagnosticSensitiveSourceKind = (typeof DIAGNOSTIC_SENSITIVE_SOURCE_KINDS)[number];
|
|
6
6
|
/**
|
|
7
7
|
* Startup inventory; request-scoped readers additionally register live values on access.
|
|
@@ -2,7 +2,6 @@ import { resolvedStringVariants, urlCredentialComponents, otlpHeaderCredentialVa
|
|
|
2
2
|
import { PROVIDER_CACHE_REDIS_URL_ENV, PROVIDER_STATE_REDIS_URL_ENV, REDIS_URL_ENV, } from "../config/loader.js";
|
|
3
3
|
import { ENGINE_OWNED_PROXY_CREDENTIAL_ENV_NAMES, ENGINE_OWNED_RESOLVER_CREDENTIAL_ENV_NAMES, } from "../engine.js";
|
|
4
4
|
import { APIFUSE__CACHE__KEY_PEPPER_ENV } from "../runtime/cache.js";
|
|
5
|
-
import { PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV } from "../runtime/choice.js";
|
|
6
5
|
import { APIFUSE__ENGINE__CEREMONY_LEASE_KEY } from "../runtime/egress-lease.js";
|
|
7
6
|
import { APIFUSE__OCR__API_KEY_ENV, APIFUSE__OCR__CLOUDFLARE_API_TOKEN_ENV, } from "../runtime/ocr.js";
|
|
8
7
|
import { OTEL_EXPORTER_OTLP_HEADERS, OTEL_EXPORTER_OTLP_TRACES_HEADERS, OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, } from "../runtime/otlp.js";
|
|
@@ -21,7 +20,6 @@ export const DIAGNOSTIC_SENSITIVE_SOURCE_KINDS = [
|
|
|
21
20
|
"engineProxyCredentials",
|
|
22
21
|
"engineSolverKeys",
|
|
23
22
|
"engineCeremonyLeaseCredentials",
|
|
24
|
-
"choiceMasterSecret",
|
|
25
23
|
"ocrCredentials",
|
|
26
24
|
"sttCredentials",
|
|
27
25
|
"cdpCredentials",
|
|
@@ -68,7 +66,6 @@ export function collectDiagnosticSensitiveValues(provider, options = {}) {
|
|
|
68
66
|
// These are the resolver-config API keys after #251's engine credential projection.
|
|
69
67
|
engineSolverKeys: () => resolvedEnvValues(ENGINE_OWNED_RESOLVER_CREDENTIAL_ENV_NAMES),
|
|
70
68
|
engineCeremonyLeaseCredentials: () => resolvedEnvValues([APIFUSE__ENGINE__CEREMONY_LEASE_KEY]),
|
|
71
|
-
choiceMasterSecret: () => resolvedEnvValues([PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV]),
|
|
72
69
|
ocrCredentials: () => resolvedEnvValues([APIFUSE__OCR__CLOUDFLARE_API_TOKEN_ENV, APIFUSE__OCR__API_KEY_ENV]),
|
|
73
70
|
sttCredentials: () => resolvedEnvValues([APIFUSE__STT__CLOUDFLARE_API_TOKEN_ENV]),
|
|
74
71
|
cdpCredentials: () => resolvedStringVariants(env[APIFUSE__CDP_POOL__URL]).flatMap((url) => [
|
|
@@ -3,6 +3,8 @@ import { z } from "zod";
|
|
|
3
3
|
import { type ProviderEngine } from "../engine.js";
|
|
4
4
|
import { type ProviderErrorObservability } from "../errors.js";
|
|
5
5
|
import { type ProviderErrorCategory } from "../observability.js";
|
|
6
|
+
import type { HandleTelemetryEvent } from "../handle.js";
|
|
7
|
+
import { type HttpTelemetryLogPayload } from "../runtime/http-telemetry.js";
|
|
6
8
|
import { type ProxyTelemetryLogPayload } from "../runtime/proxy-telemetry.js";
|
|
7
9
|
import { type ResolverTelemetryLogPayload } from "../runtime/resolver-telemetry.js";
|
|
8
10
|
import type { OcrContext, ProviderContext, ProviderDefinition, ProviderFilesContext, ProviderRuntimeState, ResolverContext, SttContext } from "../types.js";
|
|
@@ -87,6 +89,7 @@ type ProviderServerLogEventBase = ProviderRequestCost & {
|
|
|
87
89
|
status: number;
|
|
88
90
|
proxy?: ProxyTelemetryLogPayload;
|
|
89
91
|
resolver?: ResolverTelemetryLogPayload;
|
|
92
|
+
http?: HttpTelemetryLogPayload;
|
|
90
93
|
};
|
|
91
94
|
export type ProviderServerLogEvent = (ProviderServerLogEventBase & {
|
|
92
95
|
level: "info";
|
|
@@ -115,18 +118,10 @@ export type ProviderServerLogEvent = (ProviderServerLogEventBase & {
|
|
|
115
118
|
event: "provider_secrets_missing";
|
|
116
119
|
providerId: string;
|
|
117
120
|
missingSecrets: string[];
|
|
118
|
-
} | {
|
|
121
|
+
} | ({
|
|
119
122
|
level: "info";
|
|
120
|
-
event: "
|
|
121
|
-
|
|
122
|
-
purpose: string;
|
|
123
|
-
operation: "parse" | "consume";
|
|
124
|
-
format: "word" | "legacy";
|
|
125
|
-
outcome: "success" | "not-found" | "invalid" | "unsupported" | "error";
|
|
126
|
-
consumeMode: "never" | "on-parse" | "explicit";
|
|
127
|
-
consumed: boolean;
|
|
128
|
-
replay: boolean;
|
|
129
|
-
} | {
|
|
123
|
+
event: "provider_handle";
|
|
124
|
+
} & HandleTelemetryEvent) | {
|
|
130
125
|
level: "warn";
|
|
131
126
|
event: "provider_cleanup_failed";
|
|
132
127
|
providerId: string;
|