@apifuse/provider-sdk 2.1.0-beta.3 → 2.1.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 (60) hide show
  1. package/AUTHORING.md +163 -8
  2. package/CHANGELOG.md +8 -1
  3. package/README.md +17 -16
  4. package/SUBMISSION.md +4 -4
  5. package/bin/apifuse-dev.ts +12 -5
  6. package/bin/apifuse-pack-check.ts +9 -2
  7. package/bin/apifuse-pack-smoke.ts +127 -6
  8. package/bin/apifuse-perf.ts +19 -15
  9. package/bin/apifuse-record.ts +41 -53
  10. package/bin/apifuse-submit-check.ts +179 -7
  11. package/bin/apifuse.ts +1 -1
  12. package/package.json +17 -8
  13. package/src/choice-token.ts +164 -0
  14. package/src/cli/commands.ts +1 -3
  15. package/src/cli/create.ts +159 -50
  16. package/src/cli/templates/provider/README.md.tpl +24 -7
  17. package/src/cli/templates/provider/dev.ts.tpl +1 -1
  18. package/src/cli/templates/provider/domain/README.md.tpl +3 -0
  19. package/src/cli/templates/provider/index.ts.tpl +5 -47
  20. package/src/cli/templates/provider/mappers/README.md.tpl +3 -0
  21. package/src/cli/templates/provider/meta.ts.tpl +7 -0
  22. package/src/cli/templates/provider/operations/index.ts.tpl +5 -0
  23. package/src/cli/templates/provider/operations/ping.ts.tpl +23 -0
  24. package/src/cli/templates/provider/schemas/ping.ts.tpl +16 -0
  25. package/src/cli/templates/provider/start.ts.tpl +1 -1
  26. package/src/cli/templates/provider/upstream/README.md.tpl +3 -0
  27. package/src/config/loader.ts +1206 -9
  28. package/src/define.ts +1618 -104
  29. package/src/errors.ts +12 -0
  30. package/src/i18n/catalog.ts +121 -0
  31. package/src/i18n/index.ts +2 -0
  32. package/src/i18n/keys.ts +64 -0
  33. package/src/index.ts +149 -8
  34. package/src/lint.ts +297 -42
  35. package/src/observability.ts +41 -0
  36. package/src/provider.ts +60 -3
  37. package/src/public-schema-field-lint.ts +237 -0
  38. package/src/runtime/auth-flow.ts +7 -0
  39. package/src/runtime/browser.ts +77 -21
  40. package/src/runtime/cache.ts +582 -0
  41. package/src/runtime/executor.ts +13 -1
  42. package/src/runtime/http.ts +939 -195
  43. package/src/runtime/insights.ts +11 -11
  44. package/src/runtime/instrumentation.ts +12 -4
  45. package/src/runtime/key-derivation.ts +1 -1
  46. package/src/runtime/keyring.ts +4 -3
  47. package/src/runtime/proxy-errors.ts +132 -0
  48. package/src/runtime/proxy-telemetry.ts +253 -0
  49. package/src/runtime/request-options.ts +66 -0
  50. package/src/runtime/state.ts +76 -0
  51. package/src/runtime/stealth.ts +1145 -0
  52. package/src/runtime/stt.ts +629 -0
  53. package/src/schema.ts +363 -1
  54. package/src/server/serve.ts +816 -58
  55. package/src/server/types.ts +35 -0
  56. package/src/stream.ts +210 -0
  57. package/src/testing/run.ts +17 -4
  58. package/src/types.ts +869 -50
  59. package/src/runtime/tls.ts +0 -434
  60. package/src/types/playwright-stealth.d.ts +0 -9
package/src/errors.ts CHANGED
@@ -1,7 +1,12 @@
1
+ import type { ProviderErrorCategory } from "./observability";
2
+
1
3
  export type ProviderErrorOptions = {
2
4
  fix?: string;
3
5
  code?: string;
6
+ details?: unknown;
4
7
  cause?: Error;
8
+ category?: ProviderErrorCategory;
9
+ retryable?: boolean;
5
10
  };
6
11
 
7
12
  export class ProviderError extends Error {
@@ -23,6 +28,10 @@ export class ProviderError extends Error {
23
28
  get code(): string | undefined {
24
29
  return this.options?.code;
25
30
  }
31
+
32
+ get details(): unknown {
33
+ return this.options?.details;
34
+ }
26
35
  }
27
36
 
28
37
  export class SDKError extends ProviderError {
@@ -55,15 +64,18 @@ export class ValidationError extends ProviderError {
55
64
 
56
65
  export type TransportErrorOptions = ProviderErrorOptions & {
57
66
  status?: number;
67
+ upstreamStatus?: number;
58
68
  };
59
69
 
60
70
  export class TransportError extends ProviderError {
61
71
  readonly status?: number;
72
+ readonly upstreamStatus?: number;
62
73
 
63
74
  constructor(message: string, options?: TransportErrorOptions) {
64
75
  super(message, options);
65
76
  this.name = "TransportError";
66
77
  this.status = options?.status;
78
+ this.upstreamStatus = options?.upstreamStatus ?? options?.status;
67
79
  }
68
80
  }
69
81
 
@@ -0,0 +1,121 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ import {
5
+ getProviderLocalePath,
6
+ isProviderLocaleValue,
7
+ type ProviderLocale,
8
+ type ProviderLocaleCatalog,
9
+ type ProviderLocaleKey,
10
+ type ProviderLocaleValue,
11
+ providerLocaleKey,
12
+ } from "./keys";
13
+
14
+ export type ProviderLocaleCatalogMap = Record<
15
+ ProviderLocale,
16
+ ProviderLocaleCatalog
17
+ >;
18
+
19
+ export interface LoadProviderLocaleCatalogsOptions {
20
+ providerDir: string;
21
+ locales: readonly ProviderLocale[];
22
+ }
23
+
24
+ export interface ProviderLocaleValidationIssue {
25
+ locale: ProviderLocale;
26
+ key: string;
27
+ message: string;
28
+ severity: "error" | "warning";
29
+ }
30
+
31
+ export interface ProviderLocaleValidationResult {
32
+ ok: boolean;
33
+ issues: ProviderLocaleValidationIssue[];
34
+ }
35
+
36
+ export function loadProviderLocaleCatalogs(
37
+ options: LoadProviderLocaleCatalogsOptions,
38
+ ): ProviderLocaleCatalogMap {
39
+ const catalogs: ProviderLocaleCatalogMap = {};
40
+ for (const locale of options.locales) {
41
+ const filePath = join(options.providerDir, "locales", `${locale}.json`);
42
+ catalogs[locale] = JSON.parse(readFileSync(filePath, "utf8"));
43
+ }
44
+ return catalogs;
45
+ }
46
+
47
+ export function resolveProviderLocaleValue(
48
+ catalogs: ProviderLocaleCatalogMap,
49
+ key: ProviderLocaleKey | string,
50
+ locale: ProviderLocale,
51
+ fallbackLocale: ProviderLocale = "en",
52
+ ): ProviderLocaleValue | undefined {
53
+ providerLocaleKey(key);
54
+ return (
55
+ getProviderLocalePath(catalogs[locale] ?? {}, key) ??
56
+ getProviderLocalePath(catalogs[fallbackLocale] ?? {}, key)
57
+ );
58
+ }
59
+
60
+ export function validateProviderLocaleCatalogs(options: {
61
+ catalogs: ProviderLocaleCatalogMap;
62
+ requiredLocales: readonly ProviderLocale[];
63
+ requiredKeys: readonly (ProviderLocaleKey | string)[];
64
+ }): ProviderLocaleValidationResult {
65
+ const issues: ProviderLocaleValidationIssue[] = [];
66
+ const uniqueKeys = Array.from(
67
+ new Set(
68
+ options.requiredKeys.map((key) => {
69
+ providerLocaleKey(key);
70
+ return key;
71
+ }),
72
+ ),
73
+ );
74
+
75
+ for (const locale of options.requiredLocales) {
76
+ const catalog = options.catalogs[locale];
77
+ if (!catalog) {
78
+ issues.push({
79
+ locale,
80
+ key: "*",
81
+ message: `Missing provider locale catalog for ${locale}`,
82
+ severity: "error",
83
+ });
84
+ continue;
85
+ }
86
+
87
+ for (const key of uniqueKeys) {
88
+ const value = getProviderLocalePath(catalog, key);
89
+ if (value === undefined) {
90
+ issues.push({
91
+ locale,
92
+ key,
93
+ message: `Missing provider locale key ${key} in ${locale}`,
94
+ severity: "error",
95
+ });
96
+ continue;
97
+ }
98
+ if (!isProviderLocaleValue(value)) {
99
+ issues.push({
100
+ locale,
101
+ key,
102
+ message: `Provider locale key ${key} must resolve to a string or string array`,
103
+ severity: "error",
104
+ });
105
+ continue;
106
+ }
107
+ for (const text of Array.isArray(value) ? value : [value]) {
108
+ if (text.trim().length === 0 || /\bTODO\b/i.test(text)) {
109
+ issues.push({
110
+ locale,
111
+ key,
112
+ message: `Provider locale key ${key} in ${locale} is empty or placeholder text`,
113
+ severity: "error",
114
+ });
115
+ }
116
+ }
117
+ }
118
+ }
119
+
120
+ return { ok: issues.every((issue) => issue.severity !== "error"), issues };
121
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./catalog";
2
+ export * from "./keys";
@@ -0,0 +1,64 @@
1
+ import type { ProviderLocaleKey } from "../types";
2
+
3
+ export type { ProviderLocale, ProviderLocaleKey } from "../types";
4
+
5
+ const PROVIDER_LOCALE_KEY_RE =
6
+ /^[a-z][a-z0-9]*(?:[A-Z][a-z0-9]+)*(?:\.[a-z][a-z0-9]*(?:[A-Z][a-z0-9]+)*|\.[0-9]+)*$/;
7
+
8
+ export function providerLocaleKey(key: string): ProviderLocaleKey {
9
+ assertProviderLocaleKey(key);
10
+ return key;
11
+ }
12
+
13
+ export function isProviderLocaleKey(
14
+ value: unknown,
15
+ ): value is ProviderLocaleKey {
16
+ return typeof value === "string" && PROVIDER_LOCALE_KEY_RE.test(value);
17
+ }
18
+
19
+ export function assertProviderLocaleKey(
20
+ value: unknown,
21
+ ): asserts value is ProviderLocaleKey {
22
+ if (!isProviderLocaleKey(value)) {
23
+ throw new Error(
24
+ `Provider locale key must be a dot path such as "meta.description" or "operations.search.description"; received ${JSON.stringify(value)}`,
25
+ );
26
+ }
27
+ }
28
+
29
+ export function qualifyProviderLocaleKey(
30
+ providerId: string,
31
+ key: ProviderLocaleKey | string,
32
+ ): string {
33
+ assertProviderLocaleKey(key);
34
+ return `providers.${providerId}.${key}`;
35
+ }
36
+
37
+ export function getProviderLocalePath(
38
+ catalog: ProviderLocaleCatalog,
39
+ key: ProviderLocaleKey | string,
40
+ ): ProviderLocaleValue | undefined {
41
+ assertProviderLocaleKey(key);
42
+ let cursor: unknown = catalog;
43
+ for (const segment of key.split(".")) {
44
+ if (!isRecord(cursor)) return undefined;
45
+ cursor = cursor[segment];
46
+ }
47
+ return isProviderLocaleValue(cursor) ? cursor : undefined;
48
+ }
49
+
50
+ export type ProviderLocaleValue = string | readonly string[];
51
+ export type ProviderLocaleCatalog = Record<string, unknown>;
52
+
53
+ export function isProviderLocaleValue(
54
+ value: unknown,
55
+ ): value is ProviderLocaleValue {
56
+ return (
57
+ typeof value === "string" ||
58
+ (Array.isArray(value) && value.every((entry) => typeof entry === "string"))
59
+ );
60
+ }
61
+
62
+ function isRecord(value: unknown): value is Record<string, unknown> {
63
+ return typeof value === "object" && value !== null && !Array.isArray(value);
64
+ }
package/src/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  // @apifuse/provider-sdk
2
2
 
3
- export { z } from "zod";
4
3
  export * from "./ceremonies";
4
+ export * from "./choice-token";
5
5
  export type {
6
6
  ApiFuseConfig,
7
7
  BrowserConfig,
@@ -9,10 +9,19 @@ export type {
9
9
  SessionConfig,
10
10
  } from "./config/loader";
11
11
  export { defineConfig, loadApiFuseConfig } from "./config/loader";
12
- export { defineOperation, defineProvider, type ProviderConfig } from "./define";
12
+ export {
13
+ defineHealthJourney,
14
+ defineOperation,
15
+ defineProvider,
16
+ defineSmsOtpMatcher,
17
+ defineStreamOperation,
18
+ every,
19
+ type ProviderConfig,
20
+ } from "./define";
13
21
  export type { DevServerOptions } from "./dev";
14
22
  export { createDevServer, startDevServer } from "./dev";
15
23
  export * from "./errors";
24
+ export * from "./i18n";
16
25
  export {
17
26
  type LintDiagnostic,
18
27
  lintOperation,
@@ -23,6 +32,12 @@ export * from "./recipes/rest-api";
23
32
  export { createFlowContext, createScratchpad } from "./runtime/auth-flow";
24
33
  export type { BrowserClientOptions } from "./runtime/browser";
25
34
  export { BrowserClient, createBrowserClient } from "./runtime/browser";
35
+ export {
36
+ createBypassProviderCache,
37
+ createProviderCache,
38
+ type ProviderCacheOptions,
39
+ resetProviderCacheForTests,
40
+ } from "./runtime/cache";
26
41
  export {
27
42
  type CreateCredentialContextOptions,
28
43
  createCredentialContext,
@@ -39,15 +54,46 @@ export {
39
54
  } from "./runtime/instrumentation";
40
55
  export { type PrevalidateResult, prevalidate } from "./runtime/prevalidate";
41
56
  export { getProviderBaseUrl } from "./runtime/provider";
42
- export { createTlsClient } from "./runtime/tls";
57
+ export {
58
+ createUnsupportedProviderRuntimeState,
59
+ UnsupportedProviderStateError,
60
+ } from "./runtime/state";
61
+ export { createStealthClient } from "./runtime/stealth";
62
+ export {
63
+ APIFUSE__STT__BACKEND_ENV,
64
+ APIFUSE__STT__CLOUDFLARE_API_TOKEN_ENV,
65
+ APIFUSE__STT__MODEL_ENV,
66
+ createSttClientFromEnv,
67
+ createUnsupportedSttClient,
68
+ extractVerificationCode,
69
+ resolveSttPrompt,
70
+ } from "./runtime/stt";
43
71
  export {
44
72
  type CreateTraceContextOptions,
45
73
  createTraceContext,
46
74
  type Span,
47
75
  type TraceContext,
48
76
  } from "./runtime/trace";
77
+ export {
78
+ APIFUSE_DESCRIPTION_KEY_META_KEY,
79
+ APIFUSE_REDACTION_MARKER,
80
+ APIFUSE_SENSITIVE_KIND_META_KEY,
81
+ APIFUSE_SENSITIVE_META_KEY,
82
+ collectSensitivePaths,
83
+ describeKey,
84
+ field,
85
+ fields,
86
+ isSensitiveSchema,
87
+ redactPayload,
88
+ type SensitiveFieldKind,
89
+ type SensitiveFieldOptions,
90
+ type SensitivePath,
91
+ sensitive,
92
+ z,
93
+ } from "./schema";
49
94
  export { createServerApp, type ServeOptions, serve } from "./server";
50
95
  export { getStealthProfile, listStealthProfiles } from "./stealth/profiles";
96
+ export * from "./stream";
51
97
  export type {
52
98
  ApiFuseResponse,
53
99
  AuthConfig,
@@ -56,6 +102,7 @@ export type {
56
102
  AuthFlowHandler,
57
103
  AuthMode,
58
104
  AuthTurn,
105
+ Bcp47Locale,
59
106
  BrowserEngine,
60
107
  BrowserOptions,
61
108
  ConnectionMode,
@@ -63,6 +110,7 @@ export type {
63
110
  ContextScratchpad,
64
111
  CredentialContext,
65
112
  CredentialDeclaration,
113
+ E164PhoneNumber,
66
114
  EnvContext,
67
115
  FlowContext,
68
116
  FlowContextStore,
@@ -71,38 +119,131 @@ export type {
71
119
  HealthCheckCaseResult,
72
120
  HealthCheckSuite,
73
121
  HealthCheckUnsupported,
122
+ HealthJourneyDefinition,
123
+ HealthJourneyEventContext,
124
+ HealthJourneyGatewayContext,
125
+ HealthJourneyJournalContext,
126
+ HealthJourneyManualTriggerPolicy,
127
+ HealthJourneyRunContext,
128
+ HealthJourneyRunResult,
129
+ HealthJourneySchedule,
130
+ HealthJourneySmsContext,
131
+ HealthJourneyStep,
74
132
  HttpClient,
133
+ HttpMethod,
75
134
  HttpResponse,
135
+ HttpRetryOptions,
136
+ HttpRetrySummary,
137
+ HttpStreamResponse,
138
+ IanaTimeZone,
76
139
  InferSchemaOutput,
140
+ Iso3166Alpha2CountryCode,
141
+ Iso4217CurrencyCode,
142
+ Iso8601Duration,
77
143
  OperationAnnotations,
144
+ OperationApprovalPolicy,
78
145
  OperationContractMetadata,
79
146
  OperationDefinition,
80
147
  OperationDeprecationMetadata,
81
148
  OperationDocMeta,
82
149
  OperationErrorCode,
150
+ OperationHandlerResult,
83
151
  OperationInputExample,
84
152
  OperationLifecycle,
153
+ OperationObservabilityConfig,
154
+ OperationObservabilitySensitiveConfig,
85
155
  OperationRelationships,
156
+ OperationRiskClass,
157
+ OperationSensitivePath,
158
+ OperationToolRouterMetadata,
159
+ OperationTransport,
160
+ OperationTransportKind,
86
161
  ProbeInterval,
162
+ ProviderAccessConfig,
163
+ ProviderAccessVisibility,
164
+ ProviderCache,
165
+ ProviderCacheGetOrSetOptions,
166
+ ProviderCacheKeyOptions,
167
+ ProviderCacheLookupMeta,
168
+ ProviderCacheResponseMeta,
169
+ ProviderCacheResult,
87
170
  ProviderContext,
88
171
  ProviderDefinition,
89
172
  ProviderHealthMonitorConfig,
173
+ ProviderLocale,
174
+ ProviderLocaleKey,
175
+ ProviderLocaleKeyInput,
176
+ ProviderLogoProfile,
177
+ ProviderLogoSource,
90
178
  ProviderMeta,
179
+ ProviderProxyConfig,
180
+ ProviderProxyMode,
181
+ ProviderProxyPolicy,
182
+ ProviderProxyProvider,
183
+ ProviderProxySessionAffinity,
184
+ ProviderPublicConnectionMode,
185
+ ProviderPublicProfile,
91
186
  ProviderReviewed,
187
+ ProviderRuntimeState,
92
188
  ProviderSecretDeclaration,
189
+ ProviderStateDurationString,
190
+ ProviderStateNamespace,
191
+ ProviderStreamEvent,
192
+ ProviderSttConfig,
193
+ ProviderSttMode,
194
+ ProviderSupportLevel,
93
195
  RequestOptions,
196
+ Rfc3339Instant,
94
197
  SchemaLike,
198
+ SmsOrigin,
199
+ SmsOtpExtractionPattern,
200
+ SmsOtpMatcherDefinition,
201
+ SseMessage,
95
202
  StandardSchemaV1,
203
+ StateCasResult,
204
+ StateNamespaceOptions,
205
+ StateValue,
206
+ StateWriteOptions,
207
+ StealthClient,
208
+ StealthFetchOptions,
96
209
  StealthPlatform,
97
210
  StealthProfile,
98
- TlsClient,
99
- TlsFetchOptions,
100
- TlsResponse,
101
- TlsSession,
211
+ StealthResponse,
212
+ StealthSession,
213
+ SttAudioInput,
214
+ SttContext,
215
+ SttPromptPolicy,
216
+ SttSegment,
217
+ SttTranscribeMode,
218
+ SttTranscribeRequest,
219
+ SttTranscript,
220
+ SttUnsupportedOptionPolicy,
221
+ SttUsage,
222
+ SttVerificationCodeOptions,
223
+ SttWarning,
102
224
  TraceConfig,
103
225
  TraceSpan,
226
+ VerificationCodeCandidate,
227
+ VerificationCodeCandidateSource,
228
+ VerificationCodeExtractionResult,
229
+ } from "./types";
230
+ export {
231
+ DEFAULT_OPERATION_TRANSPORT,
232
+ HttpRetryAfterPolicy,
233
+ HttpRetryDelayStrategy,
234
+ HttpRetryJitter,
235
+ HttpRetryPreset,
236
+ HttpRetryUnsafeMethodPolicy,
237
+ PROBE_INTERVALS,
238
+ STREAM_CHUNK_BYTES_MAX,
239
+ STREAM_CHUNK_BYTES_MIN,
240
+ STREAM_HEARTBEAT_MS_MAX,
241
+ STREAM_HEARTBEAT_MS_MIN,
242
+ STREAM_IDLE_TIMEOUT_MS_MAX,
243
+ STREAM_IDLE_TIMEOUT_MS_MIN,
244
+ STREAM_MAX_DURATION_MS_MAX,
245
+ STREAM_MAX_DURATION_MS_MIN,
104
246
  } from "./types";
105
- export { PROBE_INTERVALS } from "./types";
106
247
  export * from "./utils/date";
107
248
  export * from "./utils/parse";
108
249
  export * from "./utils/text";