@apifuse/provider-sdk 2.2.0-beta.3 → 2.2.0-beta.4

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 (165) hide show
  1. package/AUTHORING.md +14 -0
  2. package/CHANGELOG.md +4 -0
  3. package/bin/apifuse-check.ts +18 -58
  4. package/bin/apifuse-create.ts +1 -1
  5. package/bin/apifuse-dev.ts +27 -52
  6. package/bin/apifuse-pack-smoke.ts +22 -81
  7. package/bin/apifuse-pack-types.ts +266 -0
  8. package/bin/apifuse-perf.ts +45 -127
  9. package/bin/apifuse-record.ts +23 -61
  10. package/bin/apifuse-submit-check.ts +26 -21
  11. package/bin/apifuse.ts +1 -1
  12. package/bin/submit-check-xml.ts +1 -1
  13. package/dist/auth-turn/index.d.ts +1 -1
  14. package/dist/auth.d.ts +2 -2
  15. package/dist/auth.js +9 -18
  16. package/dist/ceremonies/index.d.ts +1 -1
  17. package/dist/ceremonies/index.js +8 -18
  18. package/dist/config/loader.d.ts +2 -2
  19. package/dist/config/loader.js +19 -42
  20. package/dist/contract-serialization.d.ts +2 -2
  21. package/dist/contract-serialization.js +3 -6
  22. package/dist/contract-types.d.ts +2 -2
  23. package/dist/contract.d.ts +3 -3
  24. package/dist/contract.js +4 -6
  25. package/dist/define.d.ts +8 -1
  26. package/dist/define.js +57 -115
  27. package/dist/dev.d.ts +1 -1
  28. package/dist/dev.js +1 -1
  29. package/dist/errors.d.ts +1 -1
  30. package/dist/errors.js +1 -3
  31. package/dist/i18n/catalog.d.ts +2 -2
  32. package/dist/i18n/catalog.js +4 -10
  33. package/dist/i18n/index.d.ts +2 -2
  34. package/dist/i18n/index.js +2 -2
  35. package/dist/i18n/keys.d.ts +2 -2
  36. package/dist/index.d.ts +43 -42
  37. package/dist/index.js +38 -37
  38. package/dist/lint.js +8 -15
  39. package/dist/provider.d.ts +11 -11
  40. package/dist/provider.js +9 -9
  41. package/dist/public-schema-field-lint.d.ts +1 -1
  42. package/dist/recipes/gov-api.js +1 -1
  43. package/dist/runtime/auth-flow.d.ts +1 -1
  44. package/dist/runtime/auth-flow.js +3 -3
  45. package/dist/runtime/browser.d.ts +1 -1
  46. package/dist/runtime/browser.js +15 -29
  47. package/dist/runtime/cache.d.ts +1 -1
  48. package/dist/runtime/cache.js +4 -8
  49. package/dist/runtime/choice.d.ts +1 -1
  50. package/dist/runtime/choice.js +12 -34
  51. package/dist/runtime/credential.d.ts +1 -1
  52. package/dist/runtime/credential.js +1 -1
  53. package/dist/runtime/env.d.ts +1 -1
  54. package/dist/runtime/executor.d.ts +1 -1
  55. package/dist/runtime/executor.js +2 -2
  56. package/dist/runtime/http.d.ts +2 -2
  57. package/dist/runtime/http.js +5 -5
  58. package/dist/runtime/insights.d.ts +1 -1
  59. package/dist/runtime/insights.js +6 -13
  60. package/dist/runtime/instrumentation.d.ts +2 -2
  61. package/dist/runtime/instrumentation.js +5 -15
  62. package/dist/runtime/keyring.js +1 -1
  63. package/dist/runtime/namespace.js +1 -1
  64. package/dist/runtime/otlp.d.ts +1 -1
  65. package/dist/runtime/perf.d.ts +1 -1
  66. package/dist/runtime/provider.d.ts +1 -1
  67. package/dist/runtime/provider.js +1 -2
  68. package/dist/runtime/proxy-errors.d.ts +1 -1
  69. package/dist/runtime/proxy-errors.js +3 -5
  70. package/dist/runtime/proxy-retry-policy.d.ts +2 -2
  71. package/dist/runtime/proxy-retry-policy.js +2 -2
  72. package/dist/runtime/proxy-telemetry.d.ts +1 -1
  73. package/dist/runtime/proxy-telemetry.js +16 -48
  74. package/dist/runtime/redis.d.ts +1 -1
  75. package/dist/runtime/redis.js +2 -4
  76. package/dist/runtime/request-options.d.ts +1 -1
  77. package/dist/runtime/state.d.ts +2 -2
  78. package/dist/runtime/state.js +3 -3
  79. package/dist/runtime/stealth.d.ts +2 -2
  80. package/dist/runtime/stealth.js +6 -6
  81. package/dist/runtime/stt.d.ts +1 -1
  82. package/dist/runtime/stt.js +11 -15
  83. package/dist/runtime/trace.d.ts +2 -2
  84. package/dist/runtime/trace.js +2 -4
  85. package/dist/runtime/waterfall.d.ts +1 -1
  86. package/dist/schema.d.ts +1 -1
  87. package/dist/schema.js +7 -15
  88. package/dist/serve.d.ts +1 -1
  89. package/dist/serve.js +1 -1
  90. package/dist/server/index.d.ts +7 -7
  91. package/dist/server/index.js +6 -6
  92. package/dist/server/self-test-redaction.d.ts +1 -1
  93. package/dist/server/self-test-redaction.js +1 -1
  94. package/dist/server/self-test.d.ts +3 -3
  95. package/dist/server/self-test.js +3 -3
  96. package/dist/server/serve.d.ts +3 -3
  97. package/dist/server/serve.js +36 -49
  98. package/dist/server/types.js +2 -7
  99. package/dist/stealth/profiles.d.ts +1 -1
  100. package/dist/stealth/profiles.js +5 -14
  101. package/dist/stream.d.ts +1 -1
  102. package/dist/testing/index.d.ts +2 -2
  103. package/dist/testing/index.js +2 -2
  104. package/dist/testing/run.d.ts +1 -1
  105. package/dist/testing/run.js +7 -14
  106. package/dist/types.d.ts +57 -0
  107. package/dist/user-input.d.ts +30 -0
  108. package/dist/user-input.js +66 -0
  109. package/package.json +6 -4
  110. package/src/auth-turn/index.ts +1 -1
  111. package/src/auth.ts +28 -86
  112. package/src/ceremonies/index.ts +24 -78
  113. package/src/config/loader.ts +58 -176
  114. package/src/contract-serialization.ts +5 -11
  115. package/src/contract-types.ts +2 -2
  116. package/src/contract.ts +12 -28
  117. package/src/define.ts +174 -495
  118. package/src/dev.ts +4 -9
  119. package/src/errors.ts +4 -11
  120. package/src/i18n/catalog.ts +10 -32
  121. package/src/i18n/index.ts +2 -2
  122. package/src/i18n/keys.ts +5 -11
  123. package/src/index.ts +44 -42
  124. package/src/lint.ts +89 -159
  125. package/src/provider.ts +12 -11
  126. package/src/public-schema-field-lint.ts +7 -33
  127. package/src/recipes/gov-api.ts +2 -5
  128. package/src/runtime/auth-flow.ts +5 -7
  129. package/src/runtime/browser.ts +64 -187
  130. package/src/runtime/cache.ts +20 -67
  131. package/src/runtime/choice.ts +55 -129
  132. package/src/runtime/credential.ts +2 -2
  133. package/src/runtime/env.ts +1 -1
  134. package/src/runtime/executor.ts +9 -19
  135. package/src/runtime/http.ts +7 -7
  136. package/src/runtime/insights.ts +15 -53
  137. package/src/runtime/instrumentation.ts +19 -58
  138. package/src/runtime/keyring.ts +7 -19
  139. package/src/runtime/namespace.ts +2 -7
  140. package/src/runtime/otlp.ts +12 -23
  141. package/src/runtime/perf.ts +1 -1
  142. package/src/runtime/provider.ts +4 -9
  143. package/src/runtime/proxy-errors.ts +17 -38
  144. package/src/runtime/proxy-retry-policy.ts +3 -3
  145. package/src/runtime/proxy-telemetry.ts +23 -72
  146. package/src/runtime/redis.ts +4 -12
  147. package/src/runtime/request-options.ts +4 -13
  148. package/src/runtime/state.ts +30 -109
  149. package/src/runtime/stealth.ts +8 -8
  150. package/src/runtime/stt.ts +38 -94
  151. package/src/runtime/trace.ts +14 -44
  152. package/src/runtime/waterfall.ts +5 -18
  153. package/src/schema.ts +23 -84
  154. package/src/serve.ts +1 -1
  155. package/src/server/index.ts +7 -7
  156. package/src/server/self-test-redaction.ts +2 -2
  157. package/src/server/self-test.ts +5 -5
  158. package/src/server/serve.ts +87 -242
  159. package/src/server/types.ts +6 -19
  160. package/src/stealth/profiles.ts +10 -26
  161. package/src/stream.ts +8 -19
  162. package/src/testing/index.ts +2 -2
  163. package/src/testing/run.ts +19 -67
  164. package/src/types.ts +58 -0
  165. package/src/user-input.ts +118 -0
@@ -1,4 +1,4 @@
1
- import { ProviderError, TransportError, ValidationError } from "../errors";
1
+ import { ProviderError, TransportError, ValidationError } from "../errors.js";
2
2
  import type {
3
3
  Bcp47Locale,
4
4
  ProviderSttConfig,
@@ -13,16 +13,14 @@ import type {
13
13
  VerificationCodeCandidate,
14
14
  VerificationCodeCandidateSource,
15
15
  VerificationCodeExtractionResult,
16
- } from "../types";
16
+ } from "../types.js";
17
17
 
18
18
  export const APIFUSE__STT__BACKEND_ENV = "APIFUSE__STT__BACKEND";
19
19
  export const APIFUSE__STT__MODEL_ENV = "APIFUSE__STT__MODEL";
20
20
  export const CLOUDFLARE_ACCOUNT_ID_ENV = "APIFUSE__CLOUDFLARE__ACCOUNT_ID";
21
- export const APIFUSE__STT__CLOUDFLARE_API_TOKEN_ENV =
22
- "APIFUSE__STT__CLOUDFLARE_API_TOKEN";
21
+ export const APIFUSE__STT__CLOUDFLARE_API_TOKEN_ENV = "APIFUSE__STT__CLOUDFLARE_API_TOKEN";
23
22
  export const CLOUDFLARE_WORKERS_AI_STT_BACKEND = "cloudflare-workers-ai";
24
- export const DEFAULT_CLOUDFLARE_WORKERS_AI_STT_MODEL =
25
- "@cf/openai/whisper-large-v3-turbo";
23
+ export const DEFAULT_CLOUDFLARE_WORKERS_AI_STT_MODEL = "@cf/openai/whisper-large-v3-turbo";
26
24
  export const DEFAULT_STT_MAX_AUDIO_BYTES = 10 * 1024 * 1024;
27
25
  export const DEFAULT_STT_TIMEOUT_MS = 30_000;
28
26
 
@@ -45,10 +43,7 @@ type ErrorSttClientOptions = {
45
43
  fix?: string;
46
44
  };
47
45
 
48
- function providerError(
49
- message: string,
50
- options: { code: string; fix?: string },
51
- ): ProviderError {
46
+ function providerError(message: string, options: { code: string; fix?: string }): ProviderError {
52
47
  return new ProviderError(message, options);
53
48
  }
54
49
 
@@ -82,9 +77,7 @@ export function createSttClientFromEnv(
82
77
  env: EnvLike = process.env,
83
78
  ): SttContext {
84
79
  if (!config) {
85
- return createUnsupportedSttClient(
86
- "Provider does not declare STT capability",
87
- );
80
+ return createUnsupportedSttClient("Provider does not declare STT capability");
88
81
  }
89
82
 
90
83
  const backend = normalizedEnvValue(env, APIFUSE__STT__BACKEND_ENV);
@@ -116,25 +109,17 @@ export function createSttClientFromEnv(
116
109
  accountId,
117
110
  apiToken,
118
111
  model:
119
- normalizedEnvValue(env, APIFUSE__STT__MODEL_ENV) ??
120
- DEFAULT_CLOUDFLARE_WORKERS_AI_STT_MODEL,
112
+ normalizedEnvValue(env, APIFUSE__STT__MODEL_ENV) ?? DEFAULT_CLOUDFLARE_WORKERS_AI_STT_MODEL,
121
113
  });
122
114
  }
123
115
 
124
116
  function base64ByteLength(data: string): number {
125
117
  const normalized = data.trim();
126
- const padding = normalized.endsWith("==")
127
- ? 2
128
- : normalized.endsWith("=")
129
- ? 1
130
- : 0;
118
+ const padding = normalized.endsWith("==") ? 2 : normalized.endsWith("=") ? 1 : 0;
131
119
  return Math.floor((normalized.length * 3) / 4) - padding;
132
120
  }
133
121
 
134
- function assertBase64Audio(
135
- audio: SttAudioInput,
136
- maxAudioBytes: number | undefined,
137
- ): number {
122
+ function assertBase64Audio(audio: SttAudioInput, maxAudioBytes: number | undefined): number {
138
123
  if (audio.kind !== "base64") {
139
124
  throw new ValidationError("Unsupported STT audio input kind", {
140
125
  code: "UNSUPPORTED_STT_OPTION",
@@ -142,32 +127,22 @@ function assertBase64Audio(
142
127
  });
143
128
  }
144
129
  const data = audio.data.trim();
145
- if (
146
- data.length === 0 ||
147
- data.length % 4 !== 0 ||
148
- !BASE64_AUDIO_PATTERN.test(data)
149
- ) {
150
- throw new ValidationError(
151
- "STT audio.data must be a base64-encoded string",
152
- {
153
- code: "INVALID_STT_AUDIO",
154
- },
155
- );
130
+ if (data.length === 0 || data.length % 4 !== 0 || !BASE64_AUDIO_PATTERN.test(data)) {
131
+ throw new ValidationError("STT audio.data must be a base64-encoded string", {
132
+ code: "INVALID_STT_AUDIO",
133
+ });
156
134
  }
157
135
  const bytes = base64ByteLength(data);
158
136
  const maxBytes = maxAudioBytes ?? DEFAULT_STT_MAX_AUDIO_BYTES;
159
137
  if (bytes > maxBytes) {
160
- throw new ValidationError(
161
- `STT audio exceeds maxAudioBytes (${bytes} > ${maxBytes})`,
162
- { code: "STT_AUDIO_TOO_LARGE" },
163
- );
138
+ throw new ValidationError(`STT audio exceeds maxAudioBytes (${bytes} > ${maxBytes})`, {
139
+ code: "STT_AUDIO_TOO_LARGE",
140
+ });
164
141
  }
165
142
  return bytes;
166
143
  }
167
144
 
168
- export function resolveSttPrompt(
169
- request: SttTranscribeRequest,
170
- ): string | undefined {
145
+ export function resolveSttPrompt(request: SttTranscribeRequest): string | undefined {
171
146
  const policy = effectivePromptPolicy(request);
172
147
  if (policy === "none") return undefined;
173
148
  if (policy === "default-hint") return DEFAULT_OTP_HINT;
@@ -183,17 +158,14 @@ function warnOrThrowUnsupportedOption(
183
158
  request: SttTranscribeRequest,
184
159
  message: string,
185
160
  ): { code: "UNSUPPORTED_STT_OPTION"; message: string } | undefined {
186
- const policy: SttUnsupportedOptionPolicy =
187
- request.unsupportedOptionPolicy ?? "warn";
161
+ const policy: SttUnsupportedOptionPolicy = request.unsupportedOptionPolicy ?? "warn";
188
162
  if (policy === "error") {
189
163
  throw new ProviderError(message, { code: "UNSUPPORTED_STT_OPTION" });
190
164
  }
191
165
  return { code: "UNSUPPORTED_STT_OPTION", message };
192
166
  }
193
167
 
194
- function normalizeCloudflareLanguage(
195
- language: Bcp47Locale | undefined,
196
- ): string | undefined {
168
+ function normalizeCloudflareLanguage(language: Bcp47Locale | undefined): string | undefined {
197
169
  return language?.split("-")[0]?.toLowerCase();
198
170
  }
199
171
 
@@ -232,9 +204,7 @@ function createTimeoutController(signalTimeoutMs: number): {
232
204
  return { controller, clear: () => clearTimeout(timeout) };
233
205
  }
234
206
 
235
- function toCloudflareInput(
236
- request: SttTranscribeRequest,
237
- ): Record<string, unknown> {
207
+ function toCloudflareInput(request: SttTranscribeRequest): Record<string, unknown> {
238
208
  const prompt = resolveSttPrompt(request);
239
209
  const input: Record<string, unknown> = {
240
210
  audio: request.audio.data.trim(),
@@ -273,8 +243,7 @@ function parseSegments(value: unknown): SttSegment[] | undefined {
273
243
  : typeof segment.endMs === "number"
274
244
  ? segment.endMs
275
245
  : undefined,
276
- confidence:
277
- typeof segment.confidence === "number" ? segment.confidence : undefined,
246
+ confidence: typeof segment.confidence === "number" ? segment.confidence : undefined,
278
247
  });
279
248
  }
280
249
  return segments.length > 0 ? segments : undefined;
@@ -288,13 +257,10 @@ function toSttTranscript(payload: unknown, audioBytes: number): SttTranscript {
288
257
  (typeof result?.text === "string" ? result.text : undefined) ??
289
258
  (typeof info?.text === "string" ? info.text : undefined);
290
259
  if (!text) {
291
- throw new TransportError(
292
- "STT upstream response did not include transcript text",
293
- {
294
- code: "STT_UPSTREAM_FAILED",
295
- status: 502,
296
- },
297
- );
260
+ throw new TransportError("STT upstream response did not include transcript text", {
261
+ code: "STT_UPSTREAM_FAILED",
262
+ status: 502,
263
+ });
298
264
  }
299
265
  const durationMs =
300
266
  typeof result?.durationMs === "number"
@@ -327,23 +293,15 @@ export function createCloudflareWorkersAiSttClient(
327
293
  return {
328
294
  async transcribe(request) {
329
295
  const warnings = [];
330
- if (
331
- request.initialPrompt &&
332
- effectivePromptPolicy(request) !== "custom-hint"
333
- ) {
296
+ if (request.initialPrompt && effectivePromptPolicy(request) !== "custom-hint") {
334
297
  const warning = warnOrThrowUnsupportedOption(
335
298
  request,
336
299
  "initialPrompt is honored only when promptPolicy is custom-hint",
337
300
  );
338
301
  if (warning) warnings.push(warning);
339
302
  }
340
- const audioBytes = assertBase64Audio(
341
- request.audio,
342
- request.maxAudioBytes,
343
- );
344
- const timeout = createTimeoutController(
345
- request.timeoutMs ?? DEFAULT_STT_TIMEOUT_MS,
346
- );
303
+ const audioBytes = assertBase64Audio(request.audio, request.maxAudioBytes);
304
+ const timeout = createTimeoutController(request.timeoutMs ?? DEFAULT_STT_TIMEOUT_MS);
347
305
  try {
348
306
  let response: Response;
349
307
  try {
@@ -388,10 +346,7 @@ export function createCloudflareWorkersAiSttClient(
388
346
  if (request.mode === "otp" || request.verificationCode) {
389
347
  return {
390
348
  ...withWarnings,
391
- verificationCode: extractVerificationCode(
392
- withWarnings.text,
393
- request.verificationCode,
394
- ),
349
+ verificationCode: extractVerificationCode(withWarnings.text, request.verificationCode),
395
350
  };
396
351
  }
397
352
  return withWarnings;
@@ -433,12 +388,9 @@ const KO_DIGITS: Record<string, string> = {
433
388
  구: "9",
434
389
  };
435
390
 
436
- function lengthSet(
437
- codeLengths: SttVerificationCodeOptions["codeLengths"],
438
- ): Set<number> {
391
+ function lengthSet(codeLengths: SttVerificationCodeOptions["codeLengths"]): Set<number> {
439
392
  if (codeLengths === undefined) return new Set([4, 5, 6, 7, 8]);
440
- if (typeof codeLengths === "number")
441
- return new Set([validCodeLength(codeLengths)]);
393
+ if (typeof codeLengths === "number") return new Set([validCodeLength(codeLengths)]);
442
394
  if (Array.isArray(codeLengths)) {
443
395
  const values = codeLengths.map((length) => validCodeLength(length));
444
396
  return new Set(values);
@@ -469,10 +421,9 @@ function lengthSet(
469
421
 
470
422
  function validCodeLength(value: number): number {
471
423
  if (!Number.isInteger(value) || value < 1 || value > 32) {
472
- throw new ValidationError(
473
- "STT verification code length must be an integer between 1 and 32",
474
- { code: "INVALID_STT_VERIFICATION_CODE_OPTIONS" },
475
- );
424
+ throw new ValidationError("STT verification code length must be an integer between 1 and 32", {
425
+ code: "INVALID_STT_VERIFICATION_CODE_OPTIONS",
426
+ });
476
427
  }
477
428
  return value;
478
429
  }
@@ -554,11 +505,7 @@ function tokenizeDigits(text: string): DigitToken[] {
554
505
  return tokens.sort((a, b) => a.startIndex - b.startIndex);
555
506
  }
556
507
 
557
- function isAdjacent(
558
- left: DigitToken,
559
- right: DigitToken,
560
- text: string,
561
- ): boolean {
508
+ function isAdjacent(left: DigitToken, right: DigitToken, text: string): boolean {
562
509
  const between = text.slice(left.endIndex, right.startIndex);
563
510
  return /^[\s,.:;\-_/]*$/u.test(between);
564
511
  }
@@ -608,12 +555,9 @@ export function extractVerificationCode(
608
555
  }
609
556
  const candidates = [...candidatesByCode.values()];
610
557
  if (candidates.length === 0) {
611
- throw new ProviderError(
612
- "No verification code candidate found in transcript",
613
- {
614
- code: "NO_CODE_FOUND",
615
- },
616
- );
558
+ throw new ProviderError("No verification code candidate found in transcript", {
559
+ code: "NO_CODE_FOUND",
560
+ });
617
561
  }
618
562
  if (candidates.length > 1) {
619
563
  throw new ProviderError("Multiple verification code candidates found", {
@@ -5,8 +5,8 @@ import type {
5
5
  TraceAttributeValue,
6
6
  TraceConfig,
7
7
  TraceSpan,
8
- } from "../types";
9
- import { exportSpansOTLP, type OTLPExportOptions } from "./otlp";
8
+ } from "../types.js";
9
+ import { exportSpansOTLP, type OTLPExportOptions } from "./otlp.js";
10
10
 
11
11
  export type SpanAttributeValue = TraceAttributeValue;
12
12
 
@@ -44,16 +44,10 @@ type CompletedSpanEntry = {
44
44
  };
45
45
 
46
46
  export interface TraceRecorder {
47
- runSpan<T>(
48
- name: string,
49
- fn: () => Promise<T> | T,
50
- options?: SpanHookOptions<T>,
51
- ): Promise<T>;
47
+ runSpan<T>(name: string, fn: () => Promise<T> | T, options?: SpanHookOptions<T>): Promise<T>;
52
48
  }
53
49
 
54
- export const TRACE_RECORDER = Symbol.for(
55
- "@apifuse/provider-sdk/runtime/trace-recorder",
56
- );
50
+ export const TRACE_RECORDER = Symbol.for("@apifuse/provider-sdk/runtime/trace-recorder");
57
51
 
58
52
  type InternalTraceContext = TraceContext & {
59
53
  [TRACE_RECORDER]: TraceRecorder;
@@ -61,9 +55,7 @@ type InternalTraceContext = TraceContext & {
61
55
  _resourceAttributes?: Record<string, string>;
62
56
  };
63
57
 
64
- function buildOTLPExportOptions(
65
- config?: TraceConfig,
66
- ): OTLPExportOptions | undefined {
58
+ function buildOTLPExportOptions(config?: TraceConfig): OTLPExportOptions | undefined {
67
59
  if (config?.exporter !== "otlp") {
68
60
  return undefined;
69
61
  }
@@ -80,9 +72,7 @@ function buildOTLPExportOptions(
80
72
  };
81
73
  }
82
74
 
83
- export function resolveTraceContextOptions(
84
- config?: TraceConfig,
85
- ): CreateTraceContextOptions {
75
+ export function resolveTraceContextOptions(config?: TraceConfig): CreateTraceContextOptions {
86
76
  return {
87
77
  maxSpans: config?.maxSpans,
88
78
  onSpan: config?.onSpan,
@@ -90,14 +80,8 @@ export function resolveTraceContextOptions(
90
80
  };
91
81
  }
92
82
 
93
- function normalizeAttributeValue(
94
- value: unknown,
95
- ): SpanAttributeValue | undefined {
96
- if (
97
- typeof value === "string" ||
98
- typeof value === "number" ||
99
- typeof value === "boolean"
100
- ) {
83
+ function normalizeAttributeValue(value: unknown): SpanAttributeValue | undefined {
84
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
101
85
  return value;
102
86
  }
103
87
 
@@ -117,10 +101,7 @@ function normalizeAttributes(
117
101
 
118
102
  const normalizedEntries = Object.entries(attributes)
119
103
  .map(([key, value]) => [key, normalizeAttributeValue(value)] as const)
120
- .filter(
121
- (entry): entry is readonly [string, SpanAttributeValue] =>
122
- entry[1] !== undefined,
123
- );
104
+ .filter((entry): entry is readonly [string, SpanAttributeValue] => entry[1] !== undefined);
124
105
 
125
106
  return Object.fromEntries(normalizedEntries);
126
107
  }
@@ -130,9 +111,7 @@ function insertCompletedSpan(
130
111
  entry: CompletedSpanEntry,
131
112
  maxSpans: number,
132
113
  ): void {
133
- const insertAt = completed.findIndex(
134
- (existingEntry) => existingEntry.sequence > entry.sequence,
135
- );
114
+ const insertAt = completed.findIndex((existingEntry) => existingEntry.sequence > entry.sequence);
136
115
 
137
116
  if (insertAt === -1) {
138
117
  completed.push(entry);
@@ -145,15 +124,11 @@ function insertCompletedSpan(
145
124
  }
146
125
  }
147
126
 
148
- export function getTraceRecorder(
149
- trace: BaseTraceContext,
150
- ): TraceRecorder | null {
127
+ export function getTraceRecorder(trace: BaseTraceContext): TraceRecorder | null {
151
128
  return (trace as Partial<InternalTraceContext>)[TRACE_RECORDER] ?? null;
152
129
  }
153
130
 
154
- export function createTraceContext(
155
- options: CreateTraceContextOptions = {},
156
- ): TraceContext {
131
+ export function createTraceContext(options: CreateTraceContextOptions = {}): TraceContext {
157
132
  const maxSpans = options.maxSpans ?? 1000;
158
133
  const completed: CompletedSpanEntry[] = [];
159
134
  const activeSpanStorage = new AsyncLocalStorage<PendingSpan | undefined>();
@@ -214,11 +189,7 @@ export function createTraceContext(
214
189
  ...(pendingSpan.parentId ? { parentId: pendingSpan.parentId } : {}),
215
190
  };
216
191
 
217
- insertCompletedSpan(
218
- completed,
219
- { sequence: pendingSpan.sequence, span },
220
- maxSpans,
221
- );
192
+ insertCompletedSpan(completed, { sequence: pendingSpan.sequence, span }, maxSpans);
222
193
  options.onSpan?.(span);
223
194
 
224
195
  if (!pendingSpan.parentId) {
@@ -233,8 +204,7 @@ export function createTraceContext(
233
204
  finalize("ok", successAttributes ?? undefined);
234
205
  return value;
235
206
  } catch (error) {
236
- const errorMessage =
237
- error instanceof Error ? error.message : String(error);
207
+ const errorMessage = error instanceof Error ? error.message : String(error);
238
208
  const errorAttributes = spanOptions.onError?.(error);
239
209
  finalize("error", errorAttributes ?? undefined, errorMessage);
240
210
  throw error;
@@ -1,4 +1,4 @@
1
- import type { Span } from "./trace";
1
+ import type { Span } from "./trace.js";
2
2
 
3
3
  export type WaterfallRequest = {
4
4
  method: string;
@@ -52,11 +52,7 @@ export function renderWaterfall(
52
52
 
53
53
  for (const node of tree) {
54
54
  const operationDuration = formatDuration(node.span.duration_ms);
55
- const operationBar = renderBar(
56
- node.span.duration_ms,
57
- totalDuration,
58
- maxBarWidth,
59
- );
55
+ const operationBar = renderBar(node.span.duration_ms, totalDuration, maxBarWidth);
60
56
  const operationColor = spanColor(node.span, slowThresholdMs);
61
57
 
62
58
  lines.push(
@@ -104,14 +100,9 @@ function renderChildren(
104
100
  const provider = isLast ? "└─" : "├─";
105
101
 
106
102
  const duration = formatDuration(node.span.duration_ms);
107
- const bar = renderBar(
108
- node.span.duration_ms,
109
- ctx.totalDuration,
110
- ctx.maxBarWidth,
111
- );
103
+ const bar = renderBar(node.span.duration_ms, ctx.totalDuration, ctx.maxBarWidth);
112
104
  const color = spanColor(node.span, ctx.slowThresholdMs);
113
- const star =
114
- node.span.id === ctx.bottleneckId ? ` ${ANSI.yellow}★${ANSI.reset}` : "";
105
+ const star = node.span.id === ctx.bottleneckId ? ` ${ANSI.yellow}★${ANSI.reset}` : "";
115
106
  const barSuffix = bar ? ` ${bar}` : "";
116
107
 
117
108
  const nameWidth = 20;
@@ -190,11 +181,7 @@ function findBottleneck(roots: SpanNode[]): string | null {
190
181
  return longest.id;
191
182
  }
192
183
 
193
- function renderBar(
194
- durationMs: number,
195
- totalMs: number,
196
- maxWidth: number,
197
- ): string {
184
+ function renderBar(durationMs: number, totalMs: number, maxWidth: number): string {
198
185
  if (totalMs <= 0 || durationMs <= 0) {
199
186
  return "";
200
187
  }
package/src/schema.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  import { type ZodString, type ZodType, z } from "zod";
2
2
 
3
- import { ValidationError } from "./errors";
4
- import { providerLocaleKey } from "./i18n/keys";
3
+ import { ValidationError } from "./errors.js";
4
+ import { providerLocaleKey } from "./i18n/keys.js";
5
5
  import type {
6
6
  InferSchemaOutput,
7
7
  ProviderLocaleKey,
8
8
  SchemaLike,
9
9
  StandardSchemaV1,
10
- } from "./types";
10
+ } from "./types.js";
11
11
 
12
12
  export { z };
13
13
 
@@ -25,15 +25,11 @@ function isFailureResult<Output>(
25
25
  return "issues" in result;
26
26
  }
27
27
  function isPromiseResult<Output>(
28
- result:
29
- | StandardSchemaV1.Result<Output>
30
- | Promise<StandardSchemaV1.Result<Output>>,
28
+ result: StandardSchemaV1.Result<Output> | Promise<StandardSchemaV1.Result<Output>>,
31
29
  ): result is Promise<StandardSchemaV1.Result<Output>> {
32
30
  return result instanceof Promise;
33
31
  }
34
- function formatStandardSchemaIssues(
35
- issues: readonly StandardSchemaV1.Issue[],
36
- ): string {
32
+ function formatStandardSchemaIssues(issues: readonly StandardSchemaV1.Issue[]): string {
37
33
  return issues.map((issue) => issue.message).join("; ");
38
34
  }
39
35
  export function parseSchema<TSchema extends SchemaLike>(
@@ -46,8 +42,7 @@ export async function parseSchema(
46
42
  value: unknown,
47
43
  fieldPath: string,
48
44
  ): Promise<unknown> {
49
- if ("parse" in schema && typeof schema.parse === "function")
50
- return schema.parse(value);
45
+ if ("parse" in schema && typeof schema.parse === "function") return schema.parse(value);
51
46
  const result = schema["~standard"].validate(value);
52
47
  const resolved = isPromiseResult(result) ? await result : result;
53
48
  if (isFailureResult(resolved))
@@ -78,8 +73,7 @@ export function safeParseSchemaSync(
78
73
  `Schema validation for ${fieldPath} returned a Promise. defineProvider fixture validation requires synchronous Standard Schema validation.`,
79
74
  ),
80
75
  };
81
- if (isFailureResult(result))
82
- return { success: false, error: result.issues };
76
+ if (isFailureResult(result)) return { success: false, error: result.issues };
83
77
  return { success: true, data: result.value };
84
78
  } catch (error) {
85
79
  return { success: false, error };
@@ -147,9 +141,7 @@ const describeKeyMethod = function <TSchema extends ZodType>(
147
141
  };
148
142
 
149
143
  function installDescribeKeyOnPrototype(prototype: unknown): void {
150
- const target = prototype as
151
- | (Record<string, unknown> & { describeKey?: unknown })
152
- | null;
144
+ const target = prototype as (Record<string, unknown> & { describeKey?: unknown }) | null;
153
145
  if (!target || typeof target.describeKey === "function") {
154
146
  return;
155
147
  }
@@ -201,12 +193,8 @@ export function field<TSchema extends ZodType>(
201
193
  const metadata = described.meta() ?? {};
202
194
  return described.meta({
203
195
  ...metadata,
204
- ...((options.sensitive ?? true)
205
- ? { [APIFUSE_SENSITIVE_META_KEY]: true }
206
- : {}),
207
- ...(options.kind
208
- ? { [APIFUSE_SENSITIVE_KIND_META_KEY]: options.kind }
209
- : {}),
196
+ ...((options.sensitive ?? true) ? { [APIFUSE_SENSITIVE_META_KEY]: true } : {}),
197
+ ...(options.kind ? { [APIFUSE_SENSITIVE_KIND_META_KEY]: options.kind } : {}),
210
198
  });
211
199
  }
212
200
 
@@ -222,10 +210,7 @@ function sensitiveString(
222
210
  description: string,
223
211
  options: { description?: string; minLength?: number } = {},
224
212
  ): ZodString {
225
- const schema =
226
- options.minLength === undefined
227
- ? z.string()
228
- : z.string().min(options.minLength);
213
+ const schema = options.minLength === undefined ? z.string() : z.string().min(options.minLength);
229
214
  return field(schema, {
230
215
  kind,
231
216
  description: options.description ?? description,
@@ -234,33 +219,17 @@ function sensitiveString(
234
219
 
235
220
  export const fields = {
236
221
  apiKey: (options?: { description?: string }) =>
237
- sensitiveString(
238
- "api_key",
239
- "Provider API key or credential secret.",
240
- options,
241
- ),
222
+ sensitiveString("api_key", "Provider API key or credential secret.", options),
242
223
  authorization: (options?: { description?: string }) =>
243
- sensitiveString(
244
- "authorization",
245
- "Authorization header value or bearer credential.",
246
- options,
247
- ),
224
+ sensitiveString("authorization", "Authorization header value or bearer credential.", options),
248
225
  cookie: (options?: { description?: string }) =>
249
- sensitiveString(
250
- "cookie",
251
- "Cookie header or browser session secret.",
252
- options,
253
- ),
226
+ sensitiveString("cookie", "Cookie header or browser session secret.", options),
254
227
  otp: (options?: { description?: string }) =>
255
228
  sensitiveString("otp", "One-time verification code.", options),
256
229
  password: (options?: { description?: string; minLength?: number }) =>
257
230
  sensitiveString("password", "Password credential.", options),
258
231
  paymentUrl: (options?: { description?: string }) =>
259
- sensitiveString(
260
- "payment_url",
261
- "Sensitive payment or checkout URL.",
262
- options,
263
- ),
232
+ sensitiveString("payment_url", "Sensitive payment or checkout URL.", options),
264
233
  phone: (options?: { description?: string }) =>
265
234
  sensitiveString("phone", "Phone number or phone-based identity.", options),
266
235
  secret: (options?: { description?: string }) =>
@@ -271,10 +240,7 @@ export const fields = {
271
240
 
272
241
  export function isSensitiveSchema(schema: unknown): boolean {
273
242
  const metadata = readZodMetadata(schema);
274
- return (
275
- metadata !== undefined &&
276
- Reflect.get(metadata, APIFUSE_SENSITIVE_META_KEY) === true
277
- );
243
+ return metadata !== undefined && Reflect.get(metadata, APIFUSE_SENSITIVE_META_KEY) === true;
278
244
  }
279
245
 
280
246
  export function collectSensitivePaths(schema: unknown): SensitivePath[] {
@@ -283,10 +249,7 @@ export function collectSensitivePaths(schema: unknown): SensitivePath[] {
283
249
  return out;
284
250
  }
285
251
 
286
- export function redactPayload(
287
- value: unknown,
288
- paths: readonly SensitivePath[] = [],
289
- ): unknown {
252
+ export function redactPayload(value: unknown, paths: readonly SensitivePath[] = []): unknown {
290
253
  return redactValue(value, [], paths);
291
254
  }
292
255
 
@@ -297,8 +260,7 @@ function collectSensitivePathsInto(
297
260
  activeSchemas: Set<unknown>,
298
261
  emittedPaths: Set<string>,
299
262
  ): void {
300
- if (!schema || typeof schema !== "object" || activeSchemas.has(schema))
301
- return;
263
+ if (!schema || typeof schema !== "object" || activeSchemas.has(schema)) return;
302
264
  activeSchemas.add(schema);
303
265
  try {
304
266
  if (isSensitiveSchema(schema)) pushSensitivePath(out, emittedPaths, path);
@@ -308,13 +270,7 @@ function collectSensitivePathsInto(
308
270
  case "object": {
309
271
  const shape = readObjectShape(def);
310
272
  for (const [key, child] of Object.entries(shape)) {
311
- collectSensitivePathsInto(
312
- child,
313
- [...path, key],
314
- out,
315
- activeSchemas,
316
- emittedPaths,
317
- );
273
+ collectSensitivePathsInto(child, [...path, key], out, activeSchemas, emittedPaths);
318
274
  }
319
275
  break;
320
276
  }
@@ -341,20 +297,8 @@ function collectSensitivePathsInto(
341
297
  );
342
298
  break;
343
299
  case "pipe":
344
- collectSensitivePathsInto(
345
- Reflect.get(def, "in"),
346
- path,
347
- out,
348
- activeSchemas,
349
- emittedPaths,
350
- );
351
- collectSensitivePathsInto(
352
- Reflect.get(def, "out"),
353
- path,
354
- out,
355
- activeSchemas,
356
- emittedPaths,
357
- );
300
+ collectSensitivePathsInto(Reflect.get(def, "in"), path, out, activeSchemas, emittedPaths);
301
+ collectSensitivePathsInto(Reflect.get(def, "out"), path, out, activeSchemas, emittedPaths);
358
302
  break;
359
303
  }
360
304
  } finally {
@@ -402,18 +346,13 @@ function pathMatches(
402
346
  ): boolean {
403
347
  return patterns.some((pattern) => {
404
348
  if (pattern.length !== path.length) return false;
405
- return pattern.every(
406
- (segment, index) => segment === "*" || segment === path[index],
407
- );
349
+ return pattern.every((segment, index) => segment === "*" || segment === path[index]);
408
350
  });
409
351
  }
410
352
 
411
353
  function isReservedSensitiveKey(key: string): boolean {
412
354
  const normalized = key.toLowerCase().replace(/[-_\s]/g, "");
413
- return (
414
- RESERVED_SENSITIVE_KEYS.has(normalized) ||
415
- RESERVED_SENSITIVE_KEYS.has(key.toLowerCase())
416
- );
355
+ return RESERVED_SENSITIVE_KEYS.has(normalized) || RESERVED_SENSITIVE_KEYS.has(key.toLowerCase());
417
356
  }
418
357
 
419
358
  function readZodMetadata(schema: unknown): object | undefined {
package/src/serve.ts CHANGED
@@ -1 +1 @@
1
- export { createServerApp, type ServeOptions, serve } from "./server/serve";
1
+ export { createServerApp, type ServeOptions, serve } from "./server/serve.js";