@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.
Files changed (85) hide show
  1. package/AUTHORING.md +17 -16
  2. package/CHANGELOG.md +8 -0
  3. package/bin/apifuse-dev.ts +5 -7
  4. package/bin/apifuse-pack-types.ts +26 -0
  5. package/bin/apifuse-perf.ts +4 -6
  6. package/bin/apifuse-record.ts +4 -7
  7. package/bin/apifuse-submit-check.ts +2 -2
  8. package/dist/define.d.ts +3 -2
  9. package/dist/define.js +1 -1
  10. package/dist/dev.js +3 -1
  11. package/dist/engine.d.ts +7 -6
  12. package/dist/engine.js +3 -4
  13. package/dist/error-resolution.js +21 -4
  14. package/dist/errors.d.ts +3 -0
  15. package/dist/errors.js +9 -0
  16. package/dist/handle-meta.d.ts +55 -0
  17. package/dist/handle-meta.js +57 -0
  18. package/dist/handle.d.ts +208 -0
  19. package/dist/handle.js +299 -0
  20. package/dist/i18n/catalog.js +21 -1
  21. package/dist/index.d.ts +7 -4
  22. package/dist/index.js +6 -3
  23. package/dist/lint.d.ts +3 -0
  24. package/dist/lint.js +372 -47
  25. package/dist/provider.d.ts +5 -3
  26. package/dist/provider.js +4 -2
  27. package/dist/runtime/handle-wordlist.d.ts +43 -0
  28. package/dist/runtime/{choice-wordlist.js → handle-wordlist.js} +127 -9
  29. package/dist/runtime/handle.d.ts +71 -0
  30. package/dist/runtime/handle.js +900 -0
  31. package/dist/runtime/http-telemetry-binding.d.ts +10 -0
  32. package/dist/runtime/http-telemetry-binding.js +152 -0
  33. package/dist/runtime/http-telemetry-guard.d.ts +6 -0
  34. package/dist/runtime/http-telemetry-guard.js +150 -0
  35. package/dist/runtime/http-telemetry.d.ts +104 -0
  36. package/dist/runtime/http-telemetry.js +190 -0
  37. package/dist/runtime/http.d.ts +31 -0
  38. package/dist/runtime/http.js +222 -146
  39. package/dist/runtime/native-network.d.ts +10 -1
  40. package/dist/runtime/native-network.js +230 -29
  41. package/dist/runtime/native-telemetry.d.ts +142 -0
  42. package/dist/runtime/native-telemetry.js +231 -0
  43. package/dist/runtime/state.d.ts +4 -1
  44. package/dist/runtime/state.js +32 -17
  45. package/dist/server/index.d.ts +3 -0
  46. package/dist/server/index.js +2 -0
  47. package/dist/server/sensitive-values.d.ts +1 -1
  48. package/dist/server/sensitive-values.js +0 -3
  49. package/dist/server/serve-implementation.d.ts +6 -11
  50. package/dist/server/serve-implementation.js +119 -52
  51. package/dist/testing/run.js +10 -7
  52. package/dist/types.d.ts +4 -107
  53. package/package.json +1 -1
  54. package/src/define.ts +4 -3
  55. package/src/dev.ts +3 -1
  56. package/src/engine.ts +5 -6
  57. package/src/error-resolution.ts +21 -4
  58. package/src/errors.ts +13 -0
  59. package/src/handle-meta.ts +93 -0
  60. package/src/handle.ts +612 -0
  61. package/src/i18n/catalog.ts +23 -1
  62. package/src/index.ts +45 -13
  63. package/src/lint.ts +437 -55
  64. package/src/provider.ts +19 -20
  65. package/src/runtime/{choice-wordlist.ts → handle-wordlist.ts} +130 -9
  66. package/src/runtime/handle.ts +1172 -0
  67. package/src/runtime/http-telemetry-binding.ts +162 -0
  68. package/src/runtime/http-telemetry-guard.ts +155 -0
  69. package/src/runtime/http-telemetry.ts +292 -0
  70. package/src/runtime/http.ts +295 -173
  71. package/src/runtime/native-network.ts +281 -33
  72. package/src/runtime/native-telemetry.ts +366 -0
  73. package/src/runtime/state.ts +44 -16
  74. package/src/server/index.ts +30 -0
  75. package/src/server/sensitive-values.ts +0 -3
  76. package/src/server/serve-implementation.ts +127 -89
  77. package/src/testing/run.ts +11 -7
  78. package/src/types.ts +4 -137
  79. package/dist/choice-token.d.ts +0 -24
  80. package/dist/choice-token.js +0 -74
  81. package/dist/runtime/choice-wordlist.d.ts +0 -9
  82. package/dist/runtime/choice.d.ts +0 -27
  83. package/dist/runtime/choice.js +0 -801
  84. package/src/choice-token.ts +0 -165
  85. 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
+ }
@@ -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(): ProviderRuntimeState;
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 {};
@@ -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
- local next_decoded = cjson.decode(envelope)
64
- next_decoded.createdAt = current_decoded.createdAt
65
- envelope = cjson.encode(next_decoded)
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
- return { value, version, expiresAt, createdAt, updatedAt };
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 = Date.now()) {
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 = { namespaces: new Map() }, scopeDiscriminator = MISSING_CONNECTION_SCOPE_DISCRIMINATOR) {
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(Date.now() + 3_600_000).toISOString();
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(Date.now() + amount * multiplier).toISOString();
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();
@@ -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";
@@ -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", "choiceMasterSecret", "ocrCredentials", "sttCredentials", "cdpCredentials", "statefulForwardingSecret", "redisCredentials", "otlpHeaders", "cacheKeyPepper", "sensitiveParams"];
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: "provider_choice_token";
121
- providerId: string;
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;