@apifuse/provider-sdk 2.2.0-beta.11 → 2.2.0-beta.13

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 (59) hide show
  1. package/AUTHORING.md +238 -0
  2. package/CHANGELOG.md +14 -0
  3. package/README.md +44 -2
  4. package/bin/apifuse-pack-smoke.ts +14 -0
  5. package/bin/apifuse-pack-types.ts +40 -1
  6. package/bin/apifuse-record.ts +622 -57
  7. package/bin/apifuse-submit-check.ts +43 -10
  8. package/dist/config/loader.d.ts +9 -1
  9. package/dist/config/loader.js +9 -0
  10. package/dist/define.d.ts +2 -1
  11. package/dist/define.js +61 -3
  12. package/dist/errors.d.ts +5 -0
  13. package/dist/errors.js +15 -0
  14. package/dist/fixture-sanitization.d.ts +26 -0
  15. package/dist/fixture-sanitization.js +216 -0
  16. package/dist/index.d.ts +4 -3
  17. package/dist/index.js +2 -1
  18. package/dist/provider.d.ts +2 -1
  19. package/dist/provider.js +1 -0
  20. package/dist/runtime/http.js +86 -32
  21. package/dist/runtime/instrumentation.js +295 -9
  22. package/dist/runtime/native-network.d.ts +53 -0
  23. package/dist/runtime/native-network.js +477 -0
  24. package/dist/runtime/proxy-nodemaven.d.ts +14 -0
  25. package/dist/runtime/proxy-nodemaven.js +20 -2
  26. package/dist/runtime/request-options.d.ts +68 -1
  27. package/dist/runtime/request-options.js +548 -0
  28. package/dist/runtime/stealth.d.ts +3 -1
  29. package/dist/runtime/stealth.js +352 -86
  30. package/dist/server/index.d.ts +1 -1
  31. package/dist/server/index.js +1 -1
  32. package/dist/server/self-test-input-tokens.d.ts +2 -1
  33. package/dist/server/self-test-input-tokens.js +18 -14
  34. package/dist/stream-evidence.d.ts +74 -0
  35. package/dist/stream-evidence.js +785 -0
  36. package/dist/testing/index.d.ts +1 -1
  37. package/dist/testing/index.js +1 -1
  38. package/dist/testing/run.d.ts +32 -2
  39. package/dist/testing/run.js +451 -19
  40. package/dist/types.d.ts +201 -7
  41. package/package.json +3 -1
  42. package/src/config/loader.ts +22 -1
  43. package/src/define.ts +81 -3
  44. package/src/errors.ts +15 -0
  45. package/src/fixture-sanitization.ts +247 -0
  46. package/src/index.ts +45 -1
  47. package/src/provider.ts +37 -0
  48. package/src/runtime/http.ts +144 -38
  49. package/src/runtime/instrumentation.ts +424 -8
  50. package/src/runtime/native-network.ts +600 -0
  51. package/src/runtime/proxy-nodemaven.ts +37 -2
  52. package/src/runtime/request-options.ts +680 -1
  53. package/src/runtime/stealth.ts +420 -88
  54. package/src/server/index.ts +4 -1
  55. package/src/server/self-test-input-tokens.ts +29 -14
  56. package/src/stream-evidence.ts +988 -0
  57. package/src/testing/index.ts +9 -1
  58. package/src/testing/run.ts +608 -12
  59. package/src/types.ts +235 -7
package/src/types.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type ms from "ms";
2
+ import type { SerializedCookieJar } from "tough-cookie";
2
3
 
3
4
  import type { infer as ZodInfer, ZodType } from "zod";
4
5
 
@@ -823,6 +824,12 @@ export interface ProviderProxyPolicy {
823
824
  affinity?: ProviderProxySessionAffinity;
824
825
  lifetimeMinutes?: number;
825
826
  poolSize?: number;
827
+ /**
828
+ * Seconds before hard sticky expiry at which native connections receive
829
+ * the `expiring` event so the provider can drain and reconnect cleanly.
830
+ * Declared by the provider; the SDK does not assume a default cut point.
831
+ */
832
+ drainLeadSeconds?: number;
826
833
  };
827
834
  }
828
835
 
@@ -999,6 +1006,11 @@ export interface HttpRetrySummary {
999
1006
  export interface RequestOptions {
1000
1007
  headers?: Record<string, string>;
1001
1008
  params?: RequestParams;
1009
+ /**
1010
+ * Query parameters whose values contain credentials or other secret material.
1011
+ * They are sent like `params`, but redacted from SDK errors, traces, and recorded fixtures.
1012
+ */
1013
+ sensitiveParams?: Record<string, string>;
1002
1014
  proxy?: string;
1003
1015
  timeout?: number;
1004
1016
  /**
@@ -1031,6 +1043,12 @@ export interface StealthFetchOptions extends RequestOptions {
1031
1043
  method?: HttpMethod;
1032
1044
  body?: string | Buffer;
1033
1045
  redirect?: "follow" | "manual" | "error";
1046
+ /**
1047
+ * Maximum decoded response-body bytes to buffer. When set, the stealth
1048
+ * transport aborts the response and throws `response_too_large` if the
1049
+ * declared or streamed body exceeds this limit.
1050
+ */
1051
+ maxBodyBytes?: number;
1034
1052
  /**
1035
1053
  * Offsets policy-managed proxy pool selection for caller-managed retries.
1036
1054
  * Use when a request receives an upstream challenge page rather than a
@@ -1051,18 +1069,45 @@ export interface StealthFetchOptions extends RequestOptions {
1051
1069
  }
1052
1070
 
1053
1071
  export interface CookieJar {
1054
- get(name: string): string | undefined;
1055
- getAll(): Record<string, string>;
1056
- toString(): string;
1057
- find?(predicate: (cookie: string) => boolean): string | undefined;
1072
+ /** URL-less reads use the jar's response URL or session base URL. */
1073
+ get(name: string, url?: string): string | undefined;
1074
+ getAll(url?: string): Record<string, string>;
1075
+ toString(url?: string): string;
1076
+ find?(predicate: (cookie: string) => boolean, url?: string): string | undefined;
1077
+ }
1078
+
1079
+ /**
1080
+ * Version 1 of the JSON-safe, attribute-preserving stealth cookie store.
1081
+ * The nested jar is tough-cookie's serialized form and retains cookie origin,
1082
+ * Path, Secure, expiry, host-only, and other RFC attributes.
1083
+ */
1084
+ export interface StealthCookieStoreV1 {
1085
+ readonly version: 1;
1086
+ readonly jar: SerializedCookieJar;
1058
1087
  }
1059
1088
 
1089
+ /** Cookie persistence formats understood by this SDK version. */
1090
+ export type StealthCookieStore = StealthCookieStoreV1;
1091
+
1060
1092
  export interface StealthSessionCookies extends CookieJar {
1061
- has(name: string): boolean;
1062
- setFromCookieStrings(cookieStrings: readonly string[]): void;
1063
- toHeader(): string;
1093
+ has(name: string, url?: string): boolean;
1094
+ /** URL-less writes are scoped to the session base URL. */
1095
+ setFromCookieStrings(cookieStrings: readonly string[], url?: string): void;
1096
+ toHeader(url?: string): string;
1097
+ /**
1098
+ * Returns every cookie as a flat name/value map, collapsing duplicate names.
1099
+ * @deprecated Use serialize() for lossless, attribute-preserving persistence.
1100
+ */
1064
1101
  snapshot(): Record<string, string>;
1102
+ /**
1103
+ * Restores flat values as host-only, Path=/ cookies on the session base URL.
1104
+ * @deprecated Use deserialize() with state produced by serialize().
1105
+ */
1065
1106
  restore(cookies: Record<string, string>): void;
1107
+ /** Returns a versioned, JSON-safe, attribute-preserving representation of every cookie. */
1108
+ serialize(): StealthCookieStoreV1;
1109
+ /** Replaces the jar with a previously serialized, attribute-preserving cookie store. */
1110
+ deserialize(state: StealthCookieStore): void;
1066
1111
  clear(): void;
1067
1112
  }
1068
1113
 
@@ -1108,7 +1153,13 @@ export interface StealthRedirectRunResult {
1108
1153
  final: StealthResponse;
1109
1154
  hops: StealthRedirectHop[];
1110
1155
  reason: "completed" | "stopped" | "max_hops" | "missing_location" | "loop";
1156
+ /**
1157
+ * Complete flat view across all redirect hosts. Attributes and duplicate names are lost.
1158
+ * @deprecated Use cookieStore for lossless persistence.
1159
+ */
1111
1160
  cookies: Record<string, string>;
1161
+ /** Versioned, attribute-preserving cookie state accumulated across the redirect chain. */
1162
+ cookieStore: StealthCookieStoreV1;
1112
1163
  }
1113
1164
 
1114
1165
  export interface StealthSession {
@@ -1198,6 +1249,171 @@ export interface HttpClient {
1198
1249
  ): Promise<AsyncIterable<SseMessage>>;
1199
1250
  }
1200
1251
 
1252
+ /** Request-scoped file reference accepted by provider operation inputs. */
1253
+ export interface ProviderFileRef {
1254
+ readonly type: "request_file";
1255
+ readonly id: string;
1256
+ readonly filename: string;
1257
+ readonly mime_type?: string;
1258
+ readonly size: number;
1259
+ readonly sha256?: string;
1260
+ }
1261
+
1262
+ /** File body resolved from a request-scoped {@link ProviderFileRef}. */
1263
+ export type ProviderResolvedFile = Omit<ProviderFileRef, "mime_type"> & {
1264
+ readonly mimeType?: string;
1265
+ arrayBuffer(): Promise<ArrayBuffer>;
1266
+ bytes(): Promise<Uint8Array>;
1267
+ stream(): ReadableStream<Uint8Array>;
1268
+ };
1269
+
1270
+ /** Resolver supplied by runtimes that accept request-scoped file inputs. */
1271
+ export interface ProviderFilesContext {
1272
+ has(input: string | ProviderFileRef): boolean;
1273
+ resolve(input: string | ProviderFileRef): Promise<ProviderResolvedFile>;
1274
+ }
1275
+
1276
+ export type NativeTcpTlsMode = "required" | "allowed" | "disabled";
1277
+
1278
+ export interface NativeTcpPortRange {
1279
+ readonly start: number;
1280
+ readonly end: number;
1281
+ }
1282
+
1283
+ /** Static native TCP egress declared by a provider. */
1284
+ export interface NativeTcpEgressRule {
1285
+ readonly host: string;
1286
+ readonly ports: readonly number[];
1287
+ readonly tls: NativeTcpTlsMode;
1288
+ }
1289
+
1290
+ /**
1291
+ * Bounded native TCP egress discovered through a declared bootstrap endpoint.
1292
+ * Host suffixes are exact DNS suffixes, not wildcard patterns.
1293
+ */
1294
+ export interface NativeTcpDynamicEgressRule {
1295
+ readonly sourceHost?: string;
1296
+ readonly sourceHostSuffixes?: readonly string[];
1297
+ readonly sourcePorts?: readonly number[];
1298
+ readonly sourcePortRanges?: readonly NativeTcpPortRange[];
1299
+ readonly targetHostSuffixes: readonly string[];
1300
+ readonly targetPorts?: readonly number[];
1301
+ readonly targetPortRanges?: readonly NativeTcpPortRange[];
1302
+ readonly tls: NativeTcpTlsMode;
1303
+ readonly ttlMs?: number;
1304
+ readonly maxGrants?: number;
1305
+ }
1306
+
1307
+ /** Common TCP/TLS connection input supported by the native runtime. */
1308
+ export interface NativeNetworkConnectInput {
1309
+ readonly host: string;
1310
+ readonly port: number;
1311
+ readonly serverName?: string;
1312
+ readonly rejectUnauthorized?: boolean;
1313
+ /**
1314
+ * Maximum time without a successful socket read before the connection is
1315
+ * closed. Opt-in; when absent, reads can remain pending indefinitely.
1316
+ */
1317
+ readonly idleTimeoutMs?: number;
1318
+ /** Maximum time allowed to establish the TCP/SOCKS/TLS connection. */
1319
+ readonly timeoutMs?: number;
1320
+ readonly signal?: AbortSignal;
1321
+ /** Overrides the credential-derived sticky affinity key. */
1322
+ readonly affinityKey?: string;
1323
+ }
1324
+
1325
+ export type NativeNetworkConnectOptions = Omit<
1326
+ NativeNetworkConnectInput,
1327
+ "serverName" | "rejectUnauthorized"
1328
+ >;
1329
+
1330
+ export type NativeTlsConnectOptions = NativeNetworkConnectInput;
1331
+
1332
+ export interface NativeNetworkDynamicGrantOptions {
1333
+ readonly sourceHost: string;
1334
+ readonly sourcePort: number;
1335
+ readonly host: string;
1336
+ readonly port: number;
1337
+ readonly tls: NativeTcpTlsMode;
1338
+ readonly ttlMs?: number;
1339
+ }
1340
+
1341
+ export interface NativeNetworkEgressGrant {
1342
+ revoke(): void;
1343
+ }
1344
+
1345
+ /** Consumer-facing alias used by native TCP providers. */
1346
+ export type NativeTcpEgressGrant = NativeNetworkEgressGrant;
1347
+
1348
+ /** Resolved egress identity for a native connection routed through a proxy. */
1349
+ export interface NativeProxyEgressInfo {
1350
+ readonly vendor: ProviderProxyProvider;
1351
+ readonly sticky: boolean;
1352
+ /** Vendor sticky session id (sid). Absent for rotating sessions. */
1353
+ readonly sessionId?: string;
1354
+ /** Hard expiry of the sticky binding, ISO 8601. */
1355
+ readonly expiresAt?: string;
1356
+ }
1357
+
1358
+ export type NativeProxyExpiringReason = "sticky_expiry";
1359
+
1360
+ export interface NativeProxyExpiringEvent {
1361
+ readonly expiresAt: string;
1362
+ readonly leadSeconds: number;
1363
+ readonly reason: NativeProxyExpiringReason;
1364
+ }
1365
+
1366
+ /**
1367
+ * Cooperative drain handler. The SDK awaits this before closing a socket whose
1368
+ * sticky proxy binding is about to expire, then force-closes at hard expiry.
1369
+ */
1370
+ export type NativeProxyDrainHandler = (
1371
+ event: NativeProxyExpiringEvent,
1372
+ ) => void | Promise<void>;
1373
+
1374
+ /** Typed reason recorded when the SDK closes a native connection intentionally. */
1375
+ export interface NativeNetworkCloseReason {
1376
+ readonly code: string;
1377
+ readonly message: string;
1378
+ }
1379
+
1380
+ /** Byte-oriented connection returned by the native TCP/TLS runtime. */
1381
+ export interface NativeNetworkConnection {
1382
+ /** Present when the connection was routed through a proxy. */
1383
+ readonly proxy?: NativeProxyEgressInfo;
1384
+ /** Present after an SDK-planned close, such as sticky proxy expiry. */
1385
+ readonly closeReason?: NativeNetworkCloseReason;
1386
+ /** Register a cooperative drain handler for sticky-expiry reconnects. */
1387
+ onExpiring?(handler: NativeProxyDrainHandler): void;
1388
+ read(): Promise<Uint8Array | null>;
1389
+ write(data: Uint8Array): Promise<void>;
1390
+ close(): Promise<void>;
1391
+ }
1392
+
1393
+ export interface NativeNetworkClient {
1394
+ connectTcp(
1395
+ input: NativeNetworkConnectOptions,
1396
+ ): Promise<NativeNetworkConnection>;
1397
+ connectTls(input: NativeTlsConnectOptions): Promise<NativeNetworkConnection>;
1398
+ grantTcpEgress(
1399
+ input: NativeNetworkDynamicGrantOptions,
1400
+ ): NativeNetworkEgressGrant;
1401
+ }
1402
+
1403
+ export interface NativeContext {
1404
+ readonly network: NativeNetworkClient;
1405
+ }
1406
+
1407
+ /** Consumer-facing alias for the native capability on provider contexts. */
1408
+ export type NativeProviderContext = NativeContext;
1409
+
1410
+ export interface NativeProviderConfig {
1411
+ readonly network?: {
1412
+ readonly tcp?: readonly NativeTcpEgressRule[];
1413
+ readonly dynamicTcp?: readonly NativeTcpDynamicEgressRule[];
1414
+ };
1415
+ }
1416
+
1201
1417
  export interface ProviderCacheKeyOptions {
1202
1418
  /**
1203
1419
  * Additional field names to omit from stable key material. The SDK always
@@ -1615,6 +1831,8 @@ export interface FlowContext {
1615
1831
  tenantId: string;
1616
1832
  providerId: string;
1617
1833
  http: HttpClient;
1834
+ /** Present when the selected runtime supplies native network capabilities. */
1835
+ readonly native?: NativeProviderContext;
1618
1836
  stealth: StealthClient;
1619
1837
  env: EnvContext;
1620
1838
  credential?: CredentialContext;
@@ -1734,6 +1952,10 @@ export interface ProviderContext {
1734
1952
  credential: CredentialContext;
1735
1953
  request?: ProviderRequestContext;
1736
1954
  http: HttpClient;
1955
+ /** Present for requests carrying runtime-resolvable file references. */
1956
+ readonly files?: ProviderFilesContext;
1957
+ /** Present when the selected runtime supplies native network capabilities. */
1958
+ readonly native?: NativeProviderContext;
1737
1959
  cache: ProviderCache;
1738
1960
  state: ProviderRuntimeState;
1739
1961
  stealth: StealthClient;
@@ -1826,6 +2048,11 @@ export interface OperationDefinition<
1826
2048
  fixtures?: {
1827
2049
  request: InferSchemaOutput<TInput>;
1828
2050
  response: InferSchemaOutput<TOutput>;
2051
+ /**
2052
+ * KST calendar date when `response` evidence was captured. Date fields in
2053
+ * the response align with this date, not a resolved relative request date.
2054
+ */
2055
+ recordedAt?: string;
1829
2056
  };
1830
2057
  upstream?: {
1831
2058
  baseUrl?: string;
@@ -1889,6 +2116,7 @@ export interface ProviderDefinition {
1889
2116
  */
1890
2117
  deployment?: ProviderDeploymentOverrides;
1891
2118
  allowedHosts?: string[];
2119
+ native?: NativeProviderConfig;
1892
2120
  stealth?: {
1893
2121
  profile: string;
1894
2122
  platform: StealthPlatform;