@apifuse/provider-sdk 2.1.0-beta.9 → 2.2.0-beta.2

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 (138) hide show
  1. package/AUTHORING.md +134 -0
  2. package/CHANGELOG.md +61 -0
  3. package/README.md +21 -9
  4. package/SUBMISSION.md +10 -11
  5. package/bin/apifuse-pack-check.ts +22 -0
  6. package/bin/apifuse-submit-check.ts +1747 -388
  7. package/dist/auth-turn/auth-turn.v1.schema.json +89 -0
  8. package/dist/auth-turn/fixtures/invalid/empty-kind.json +4 -0
  9. package/dist/auth-turn/fixtures/invalid/expires-at-not-string.json +5 -0
  10. package/dist/auth-turn/fixtures/invalid/missing-kind.json +3 -0
  11. package/dist/auth-turn/fixtures/invalid/missing-turn-id.json +3 -0
  12. package/dist/auth-turn/fixtures/invalid/timing-unknown-field.json +7 -0
  13. package/dist/auth-turn/fixtures/invalid/turn-id-snake-case.json +4 -0
  14. package/dist/auth-turn/fixtures/invalid/unknown-top-level-field.json +5 -0
  15. package/dist/auth-turn/fixtures/valid/abort.json +8 -0
  16. package/dist/auth-turn/fixtures/valid/challenge.json +17 -0
  17. package/dist/auth-turn/fixtures/valid/complete.json +13 -0
  18. package/dist/auth-turn/fixtures/valid/form.json +14 -0
  19. package/dist/auth-turn/fixtures/valid/message.json +13 -0
  20. package/dist/auth-turn/fixtures/valid/multi_choice.json +15 -0
  21. package/dist/auth-turn/fixtures/valid/pending.json +5 -0
  22. package/dist/auth-turn/fixtures/valid/poll.json +9 -0
  23. package/dist/auth-turn/fixtures/valid/redirect.json +16 -0
  24. package/dist/auth-turn/fixtures/valid/retry.json +8 -0
  25. package/dist/auth-turn/fixtures/valid/unknown-kind.json +7 -0
  26. package/dist/auth-turn/index.d.ts +195 -0
  27. package/dist/auth-turn/index.js +133 -0
  28. package/dist/auth.d.ts +76 -0
  29. package/dist/auth.js +436 -0
  30. package/dist/ceremonies/index.js +7 -31
  31. package/dist/cli/create.js +45 -30
  32. package/dist/cli/templates/provider/.dockerignore.tpl +22 -0
  33. package/dist/cli/templates/provider/.gitignore.tpl +22 -0
  34. package/dist/cli/templates/provider/AGENTS.md.tpl +87 -0
  35. package/dist/cli/templates/provider/CLAUDE.md.tpl +1 -0
  36. package/dist/cli/templates/provider/Dockerfile.tpl +7 -0
  37. package/dist/cli/templates/provider/README.md.tpl +163 -0
  38. package/dist/cli/templates/provider/dev.ts.tpl +5 -0
  39. package/dist/cli/templates/provider/domain/README.md.tpl +3 -0
  40. package/dist/cli/templates/provider/index.test.ts.tpl +13 -0
  41. package/dist/cli/templates/provider/index.ts.tpl +15 -0
  42. package/dist/cli/templates/provider/mappers/README.md.tpl +3 -0
  43. package/dist/cli/templates/provider/meta.ts.tpl +7 -0
  44. package/dist/cli/templates/provider/operations/index.ts.tpl +5 -0
  45. package/dist/cli/templates/provider/operations/ping.ts.tpl +24 -0
  46. package/dist/cli/templates/provider/schemas/ping.ts.tpl +24 -0
  47. package/dist/cli/templates/provider/skills/fixtures-and-recording/SKILL.md.tpl +58 -0
  48. package/dist/cli/templates/provider/skills/health-checks-and-fail-closed/SKILL.md.tpl +65 -0
  49. package/dist/cli/templates/provider/skills/normalization-standards/SKILL.md.tpl +57 -0
  50. package/dist/cli/templates/provider/skills/pagination-and-counts/SKILL.md.tpl +52 -0
  51. package/dist/cli/templates/provider/skills/upstream-contract-verification/SKILL.md.tpl +45 -0
  52. package/dist/cli/templates/provider/skills/upstream-notes/README.md.tpl +13 -0
  53. package/dist/cli/templates/provider/start.ts.tpl +5 -0
  54. package/dist/cli/templates/provider/upstream/README.md.tpl +3 -0
  55. package/dist/contract.js +1 -0
  56. package/dist/define.d.ts +6 -1
  57. package/dist/define.js +140 -70
  58. package/dist/index.d.ts +3 -2
  59. package/dist/index.js +2 -1
  60. package/dist/lint.d.ts +1 -0
  61. package/dist/lint.js +27 -0
  62. package/dist/provider.d.ts +4 -2
  63. package/dist/provider.js +2 -1
  64. package/dist/runtime/auth-flow.js +2 -0
  65. package/dist/runtime/browser.js +203 -0
  66. package/dist/runtime/http.js +46 -336
  67. package/dist/runtime/proxy-retry-policy.d.ts +40 -0
  68. package/dist/runtime/proxy-retry-policy.js +326 -0
  69. package/dist/runtime/stealth.d.ts +5 -2
  70. package/dist/runtime/stealth.js +206 -206
  71. package/dist/server/index.d.ts +4 -0
  72. package/dist/server/index.js +4 -0
  73. package/dist/server/self-test-input-tokens.d.ts +1 -0
  74. package/dist/server/self-test-input-tokens.js +37 -0
  75. package/dist/server/self-test-redaction.d.ts +20 -0
  76. package/dist/server/self-test-redaction.js +70 -0
  77. package/dist/server/self-test-token.d.ts +30 -0
  78. package/dist/server/self-test-token.js +50 -0
  79. package/dist/server/self-test.d.ts +98 -0
  80. package/dist/server/self-test.js +555 -0
  81. package/dist/server/serve.d.ts +6 -0
  82. package/dist/server/serve.js +38 -10
  83. package/dist/server/types.d.ts +1 -0
  84. package/dist/server/types.js +1 -0
  85. package/dist/testing/run.js +5 -1
  86. package/dist/types.d.ts +150 -0
  87. package/package.json +9 -2
  88. package/src/auth-turn/auth-turn.v1.schema.json +89 -0
  89. package/src/auth-turn/fixtures/invalid/empty-kind.json +4 -0
  90. package/src/auth-turn/fixtures/invalid/expires-at-not-string.json +5 -0
  91. package/src/auth-turn/fixtures/invalid/missing-kind.json +3 -0
  92. package/src/auth-turn/fixtures/invalid/missing-turn-id.json +3 -0
  93. package/src/auth-turn/fixtures/invalid/timing-unknown-field.json +7 -0
  94. package/src/auth-turn/fixtures/invalid/turn-id-snake-case.json +4 -0
  95. package/src/auth-turn/fixtures/invalid/unknown-top-level-field.json +5 -0
  96. package/src/auth-turn/fixtures/valid/abort.json +8 -0
  97. package/src/auth-turn/fixtures/valid/challenge.json +17 -0
  98. package/src/auth-turn/fixtures/valid/complete.json +13 -0
  99. package/src/auth-turn/fixtures/valid/form.json +14 -0
  100. package/src/auth-turn/fixtures/valid/message.json +13 -0
  101. package/src/auth-turn/fixtures/valid/multi_choice.json +15 -0
  102. package/src/auth-turn/fixtures/valid/pending.json +5 -0
  103. package/src/auth-turn/fixtures/valid/poll.json +9 -0
  104. package/src/auth-turn/fixtures/valid/redirect.json +16 -0
  105. package/src/auth-turn/fixtures/valid/retry.json +8 -0
  106. package/src/auth-turn/fixtures/valid/unknown-kind.json +7 -0
  107. package/src/auth-turn/index.ts +177 -0
  108. package/src/auth.ts +786 -0
  109. package/src/ceremonies/index.ts +9 -43
  110. package/src/cli/create.ts +60 -97
  111. package/src/cli/templates/provider/AGENTS.md.tpl +87 -0
  112. package/src/cli/templates/provider/CLAUDE.md.tpl +1 -0
  113. package/src/cli/templates/provider/README.md.tpl +7 -4
  114. package/src/cli/templates/provider/skills/fixtures-and-recording/SKILL.md.tpl +58 -0
  115. package/src/cli/templates/provider/skills/health-checks-and-fail-closed/SKILL.md.tpl +65 -0
  116. package/src/cli/templates/provider/skills/normalization-standards/SKILL.md.tpl +57 -0
  117. package/src/cli/templates/provider/skills/pagination-and-counts/SKILL.md.tpl +52 -0
  118. package/src/cli/templates/provider/skills/upstream-contract-verification/SKILL.md.tpl +45 -0
  119. package/src/cli/templates/provider/skills/upstream-notes/README.md.tpl +13 -0
  120. package/src/contract.ts +1 -0
  121. package/src/define.ts +198 -71
  122. package/src/index.ts +16 -0
  123. package/src/lint.ts +33 -0
  124. package/src/provider.ts +27 -0
  125. package/src/runtime/auth-flow.ts +2 -0
  126. package/src/runtime/browser.ts +293 -1
  127. package/src/runtime/http.ts +84 -530
  128. package/src/runtime/proxy-retry-policy.ts +469 -0
  129. package/src/runtime/stealth.ts +269 -353
  130. package/src/server/index.ts +36 -0
  131. package/src/server/self-test-input-tokens.ts +46 -0
  132. package/src/server/self-test-redaction.ts +97 -0
  133. package/src/server/self-test-token.ts +70 -0
  134. package/src/server/self-test.ts +725 -0
  135. package/src/server/serve.ts +75 -6
  136. package/src/server/types.ts +1 -0
  137. package/src/testing/run.ts +9 -1
  138. package/src/types.ts +186 -0
@@ -3,6 +3,7 @@ import { join } from "node:path";
3
3
 
4
4
  import { Hono } from "hono";
5
5
  import { z } from "zod";
6
+ import { AuthAbortError, createAuthFlowHelpers } from "../auth";
6
7
  import {
7
8
  AuthError,
8
9
  ProviderError,
@@ -75,6 +76,12 @@ import type {
75
76
  StealthClient,
76
77
  SttContext,
77
78
  } from "../types";
79
+ import {
80
+ createSelfTestApp,
81
+ createSelfTestInvoke,
82
+ resolveSelfTestPort,
83
+ } from "./self-test";
84
+ import { resolveSelfTestMasterSecrets } from "./self-test-token";
78
85
  import {
79
86
  type AuthFlowRequest,
80
87
  AuthFlowRequestSchema,
@@ -189,7 +196,7 @@ export function resolveProviderProxyAffinityKey(
189
196
  operationId: string,
190
197
  ): string {
191
198
  const connectionKey =
192
- request.connection?.id ?? request.connection?.externalRef;
199
+ resolveOperationConnectionId(request) ?? request.connection?.externalRef;
193
200
  const affinity =
194
201
  typeof provider.proxy === "object"
195
202
  ? provider.proxy.session?.affinity
@@ -200,6 +207,12 @@ export function resolveProviderProxyAffinityKey(
200
207
  return connectionKey ?? provider.id;
201
208
  }
202
209
 
210
+ function resolveOperationConnectionId(
211
+ request: OperationRequest,
212
+ ): string | undefined {
213
+ return request.connection?.id ?? request.connectionId;
214
+ }
215
+
203
216
  function createProviderContext(
204
217
  provider: ProviderDefinition,
205
218
  request: OperationRequest,
@@ -238,7 +251,7 @@ function createProviderContext(
238
251
  values: request.connection?.secrets,
239
252
  });
240
253
  const requestContext = {
241
- connectionId: request.connection?.id,
254
+ connectionId: resolveOperationConnectionId(request),
242
255
  headers: request.headers ?? {},
243
256
  };
244
257
  const context = wrapWithInstrumentation({
@@ -329,6 +342,7 @@ function createAuthFlowContext(
329
342
  provider: ProviderDefinition,
330
343
  request: AuthFlowRequest,
331
344
  options: ProviderServerOptions = {},
345
+ signal?: AbortSignal,
332
346
  ): {
333
347
  context: FlowContext;
334
348
  getPatch: () => Record<string, unknown | null> | undefined;
@@ -383,6 +397,7 @@ function createAuthFlowContext(
383
397
  credential,
384
398
  context: flowContextStore.context,
385
399
  stt: options.stt ?? createSttClientFromEnv(provider.stt),
400
+ auth: createAuthFlowHelpers({ signal }),
386
401
  },
387
402
  getPatch: flowContextStore.getPatch,
388
403
  };
@@ -1291,6 +1306,7 @@ async function handleAuthFlow(
1291
1306
  request: AuthFlowRequest,
1292
1307
  route: AuthRoute,
1293
1308
  options: ProviderServerOptions = {},
1309
+ signal?: AbortSignal,
1294
1310
  ): Promise<Response | AuthFlowResponse> {
1295
1311
  const flow = provider.auth?.flow;
1296
1312
  if (!flow) {
@@ -1303,6 +1319,7 @@ async function handleAuthFlow(
1303
1319
  provider,
1304
1320
  request,
1305
1321
  options,
1322
+ signal,
1306
1323
  );
1307
1324
  try {
1308
1325
  const result =
@@ -1336,6 +1353,11 @@ async function handleAuthFlow(
1336
1353
  ? materializeAuthFlowTurn(provider, request, result)
1337
1354
  : result;
1338
1355
  return toAuthFlowResponse(materializedResult, getPatch());
1356
+ } catch (error) {
1357
+ if (error instanceof AuthAbortError) {
1358
+ return toAuthFlowResponse(error.turn, getPatch());
1359
+ }
1360
+ throw error;
1339
1361
  } finally {
1340
1362
  context.stealth.close?.();
1341
1363
  }
@@ -1450,7 +1472,13 @@ export function createServerApp(
1450
1472
  AuthFlowRequestSchema.parse(rawBody),
1451
1473
  c.req.raw.headers,
1452
1474
  );
1453
- const response = await handleAuthFlow(provider, body, "start", options);
1475
+ const response = await handleAuthFlow(
1476
+ provider,
1477
+ body,
1478
+ "start",
1479
+ options,
1480
+ c.req.raw.signal,
1481
+ );
1454
1482
  logProviderSuccess(
1455
1483
  logger,
1456
1484
  provider,
@@ -1495,6 +1523,7 @@ export function createServerApp(
1495
1523
  body,
1496
1524
  "continue",
1497
1525
  options,
1526
+ c.req.raw.signal,
1498
1527
  );
1499
1528
  logProviderSuccess(
1500
1529
  logger,
@@ -1535,7 +1564,13 @@ export function createServerApp(
1535
1564
  AuthFlowRequestSchema.parse(rawBody),
1536
1565
  c.req.raw.headers,
1537
1566
  );
1538
- const response = await handleAuthFlow(provider, body, "poll", options);
1567
+ const response = await handleAuthFlow(
1568
+ provider,
1569
+ body,
1570
+ "poll",
1571
+ options,
1572
+ c.req.raw.signal,
1573
+ );
1539
1574
  logProviderSuccess(
1540
1575
  logger,
1541
1576
  provider,
@@ -1575,7 +1610,13 @@ export function createServerApp(
1575
1610
  AuthFlowRequestSchema.parse(rawBody),
1576
1611
  c.req.raw.headers,
1577
1612
  );
1578
- const response = await handleAuthFlow(provider, body, "refresh", options);
1613
+ const response = await handleAuthFlow(
1614
+ provider,
1615
+ body,
1616
+ "refresh",
1617
+ options,
1618
+ c.req.raw.signal,
1619
+ );
1579
1620
  logProviderSuccess(
1580
1621
  logger,
1581
1622
  provider,
@@ -1615,7 +1656,13 @@ export function createServerApp(
1615
1656
  AuthFlowRequestSchema.parse(rawBody),
1616
1657
  c.req.raw.headers,
1617
1658
  );
1618
- const response = await handleAuthFlow(provider, body, "abort", options);
1659
+ const response = await handleAuthFlow(
1660
+ provider,
1661
+ body,
1662
+ "abort",
1663
+ options,
1664
+ c.req.raw.signal,
1665
+ );
1619
1666
  logProviderSuccess(
1620
1667
  logger,
1621
1668
  provider,
@@ -1675,6 +1722,12 @@ function getBunServeRuntime(): BunServeRuntime | undefined {
1675
1722
  export interface ServeOptions extends ProviderServerOptions {
1676
1723
  host?: string;
1677
1724
  port?: number;
1725
+ /**
1726
+ * Port for the internal self-test listener (default 3001 or
1727
+ * APIFUSE__PROVIDER_RUNTIME__SELF_TEST_PORT). The listener only starts
1728
+ * when APIFUSE__PROVIDER_RUNTIME__SELF_TEST_MASTER_SECRET is present.
1729
+ */
1730
+ selfTestPort?: number;
1678
1731
  }
1679
1732
 
1680
1733
  export async function serve(
@@ -1702,5 +1755,21 @@ export async function serve(
1702
1755
  hostname: options.host ?? DEFAULT_HOST,
1703
1756
  fetch: app.fetch,
1704
1757
  });
1758
+
1759
+ // Internal self-test listener (health dependency inversion): a SEPARATE
1760
+ // socket the tenant-facing gateway never dials. Off by default — it only
1761
+ // starts when the shared self-test master secret env is present.
1762
+ const selfTestSecrets = resolveSelfTestMasterSecrets();
1763
+ if (selfTestSecrets) {
1764
+ const selfTestApp = createSelfTestApp(provider, {
1765
+ secrets: selfTestSecrets,
1766
+ invoke: createSelfTestInvoke(app),
1767
+ });
1768
+ bunRuntime.serve({
1769
+ port: options.selfTestPort ?? resolveSelfTestPort(),
1770
+ hostname: options.host ?? DEFAULT_HOST,
1771
+ fetch: selfTestApp.fetch,
1772
+ });
1773
+ }
1705
1774
  await Promise.resolve();
1706
1775
  }
@@ -21,6 +21,7 @@ export const OperationConnectionSchema = z.object({
21
21
  export const OperationRequestSchema = z.object({
22
22
  requestId: z.string(),
23
23
  input: z.record(z.string(), z.unknown()),
24
+ connectionId: z.string().optional(),
24
25
  connection: OperationConnectionSchema.optional(),
25
26
  headers: z.record(z.string(), z.string()).optional(),
26
27
  trace: z.record(z.string(), z.string()).optional(),
@@ -128,13 +128,21 @@ function inferFixtureDir(providerId: string): string {
128
128
  }
129
129
 
130
130
  function jsonResponse(data: unknown): HttpResponse {
131
+ const body = JSON.stringify(data);
132
+ const bodyBytes = new TextEncoder().encode(body);
131
133
  return {
132
134
  status: 200,
133
135
  ok: true,
134
136
  headers: {},
135
137
  data,
136
138
  json: async <_T = unknown>() => JSON.parse(JSON.stringify(data)),
137
- text: async () => JSON.stringify(data),
139
+ text: async () => body,
140
+ arrayBuffer: async () =>
141
+ bodyBytes.buffer.slice(
142
+ bodyBytes.byteOffset,
143
+ bodyBytes.byteOffset + bodyBytes.byteLength,
144
+ ),
145
+ bytes: async () => bodyBytes.slice(0),
138
146
  };
139
147
  }
140
148
 
package/src/types.ts CHANGED
@@ -331,9 +331,20 @@ export interface HealthJourneySchedule {
331
331
  kind: "interval";
332
332
  /** ISO 8601 duration, for example PT8H. */
333
333
  interval: Iso8601Duration;
334
+ randomize?: HealthScheduleRandomization;
334
335
  jitter?: Iso8601Duration;
335
336
  }
336
337
 
338
+ export type HealthScheduleRandomization =
339
+ | {
340
+ mode: "centered";
341
+ maxOffset: Iso8601Duration;
342
+ }
343
+ | {
344
+ mode: "delayed";
345
+ maxDelay: Iso8601Duration;
346
+ };
347
+
337
348
  export interface HealthJourneyStep {
338
349
  id: string;
339
350
  description?: string;
@@ -612,6 +623,9 @@ export interface HealthCheckCase<TInput = unknown, TOutput = unknown> {
612
623
  export interface HealthCheckSuite<TInput = unknown, TOutput = unknown> {
613
624
  /** Polling interval for the suite. All cases share this cadence. */
614
625
  interval: ProbeInterval;
626
+ schedule?: {
627
+ randomize?: HealthScheduleRandomization;
628
+ };
615
629
  /** Per-case timeout in milliseconds. Default: 30000. */
616
630
  timeoutMs?: number;
617
631
  /** Default degradation threshold for cases in this suite. Default: runtime threshold. */
@@ -687,6 +701,14 @@ export interface ProviderHealthMonitorConfig {
687
701
  serviceAccount?: string;
688
702
  }
689
703
 
704
+ /**
705
+ * New name for `ProviderHealthMonitorConfig` as part of the health dependency
706
+ * inversion (`healthMonitor` → `healthProbe`). Both provider-level fields are
707
+ * accepted transitionally with identical validation; declaring both is a
708
+ * `ValidationError`.
709
+ */
710
+ export type ProviderHealthProbeConfig = ProviderHealthMonitorConfig;
711
+
690
712
  export interface HealthMonitorProbeOverride {
691
713
  /** Optional runtime interval override as a positive `ms`-style duration string. */
692
714
  interval?: ProbeInterval;
@@ -979,6 +1001,7 @@ export type HttpMethod =
979
1001
  export interface StealthFetchOptions extends RequestOptions {
980
1002
  method?: HttpMethod;
981
1003
  body?: string | Buffer;
1004
+ redirect?: "follow" | "manual" | "error";
982
1005
  /**
983
1006
  * Offsets policy-managed proxy pool selection for caller-managed retries.
984
1007
  * Use when a request receives an upstream challenge page rather than a
@@ -1005,9 +1028,20 @@ export interface CookieJar {
1005
1028
  find?(predicate: (cookie: string) => boolean): string | undefined;
1006
1029
  }
1007
1030
 
1031
+ export interface StealthSessionCookies extends CookieJar {
1032
+ has(name: string): boolean;
1033
+ setFromCookieStrings(cookieStrings: readonly string[]): void;
1034
+ toHeader(): string;
1035
+ snapshot(): Record<string, string>;
1036
+ restore(cookies: Record<string, string>): void;
1037
+ clear(): void;
1038
+ }
1039
+
1008
1040
  export interface DeclarativeStealthResponse {
1009
1041
  status: number;
1010
1042
  ok: boolean;
1043
+ url?: string;
1044
+ redirected?: boolean;
1011
1045
  headers: Record<string, string>;
1012
1046
  rawHeaders: [string, string][];
1013
1047
  body: string;
@@ -1026,8 +1060,34 @@ export type RequestWithMethodOptions = RequestOptions & {
1026
1060
  body?: unknown;
1027
1061
  };
1028
1062
 
1063
+ export interface StealthRedirectHop {
1064
+ url: string;
1065
+ status: number;
1066
+ method: string;
1067
+ location?: string;
1068
+ nextUrl?: string;
1069
+ }
1070
+
1071
+ export interface StealthRedirectRunOptions
1072
+ extends Omit<StealthFetchOptions, "redirect"> {
1073
+ url: string;
1074
+ maxHops?: number;
1075
+ stopWhen?: (hop: StealthRedirectHop) => boolean | Promise<boolean>;
1076
+ }
1077
+
1078
+ export interface StealthRedirectRunResult {
1079
+ final: StealthResponse;
1080
+ hops: StealthRedirectHop[];
1081
+ reason: "completed" | "stopped" | "max_hops" | "missing_location" | "loop";
1082
+ cookies: Record<string, string>;
1083
+ }
1084
+
1029
1085
  export interface StealthSession {
1030
1086
  fetch(url: string, options?: StealthFetchOptions): Promise<StealthResponse>;
1087
+ cookies: StealthSessionCookies;
1088
+ redirects: {
1089
+ run(options: StealthRedirectRunOptions): Promise<StealthRedirectRunResult>;
1090
+ };
1031
1091
  close(): void;
1032
1092
  }
1033
1093
 
@@ -1050,6 +1110,8 @@ export interface HttpResponse<T = unknown> {
1050
1110
  data: T;
1051
1111
  json<U = T>(): Promise<U>;
1052
1112
  text(): Promise<string>;
1113
+ arrayBuffer(): Promise<ArrayBuffer>;
1114
+ bytes(): Promise<Uint8Array>;
1053
1115
  }
1054
1116
 
1055
1117
  export interface HttpStreamResponse {
@@ -1206,6 +1268,45 @@ export interface BrowserFrame {
1206
1268
  locator(selector: string): BrowserLocator;
1207
1269
  }
1208
1270
 
1271
+ export type BrowserResourceMethod = "GET" | "HEAD";
1272
+
1273
+ export type BrowserResourceRequest = {
1274
+ readonly url: string;
1275
+ readonly method: BrowserResourceMethod;
1276
+ readonly resourceType?: string;
1277
+ readonly headers: Readonly<Record<string, string>>;
1278
+ };
1279
+
1280
+ export type BrowserResourceBody = Buffer | Uint8Array | ArrayBuffer | string;
1281
+
1282
+ export type BrowserResourceDecision =
1283
+ | {
1284
+ readonly action: "fulfill";
1285
+ readonly status?: number;
1286
+ readonly headers?: Readonly<Record<string, string>>;
1287
+ readonly body?: BrowserResourceBody;
1288
+ }
1289
+ | {
1290
+ readonly action: "block";
1291
+ readonly reason?: string;
1292
+ };
1293
+
1294
+ export type BrowserResourceRoute = {
1295
+ readonly match:
1296
+ | string
1297
+ | RegExp
1298
+ | ((request: BrowserResourceRequest) => boolean);
1299
+ readonly handle: (
1300
+ request: BrowserResourceRequest,
1301
+ ) => Promise<BrowserResourceDecision> | BrowserResourceDecision;
1302
+ };
1303
+
1304
+ export type BrowserResourcePolicy = {
1305
+ readonly defaultAction?: "block";
1306
+ readonly allowedMethods?: readonly BrowserResourceMethod[];
1307
+ readonly routes: readonly BrowserResourceRoute[];
1308
+ };
1309
+
1209
1310
  export interface BrowserPage extends BrowserFrame {
1210
1311
  close(): Promise<void>;
1211
1312
  fill(selector: string, text: string): Promise<void>;
@@ -1219,6 +1320,10 @@ export interface BrowserPage extends BrowserFrame {
1219
1320
  options?: { timeout?: number },
1220
1321
  ): Promise<void>;
1221
1322
  frames(): Promise<BrowserFrame[]>;
1323
+ withResourcePolicy<T>(
1324
+ policy: BrowserResourcePolicy,
1325
+ run: () => Promise<T>,
1326
+ ): Promise<T>;
1222
1327
  }
1223
1328
 
1224
1329
  export type BrowserChallengeRequest = {
@@ -1397,6 +1502,84 @@ export interface ContextScratchpad {
1397
1502
 
1398
1503
  export type FlowContextStore = ContextScratchpad;
1399
1504
 
1505
+ export type AuthSafeJson =
1506
+ | string
1507
+ | number
1508
+ | boolean
1509
+ | null
1510
+ | readonly AuthSafeJson[]
1511
+ | { readonly [key: string]: AuthSafeJson };
1512
+
1513
+ export type AuthSafeData = { readonly [key: string]: AuthSafeJson };
1514
+
1515
+ export type AuthAbortRetry = "never" | "retry" | "after_user_action";
1516
+
1517
+ export type AuthAbortData = Record<string, unknown> & {
1518
+ readonly code: string;
1519
+ readonly message?: string;
1520
+ readonly retry?: AuthAbortRetry;
1521
+ readonly actionHint?: AuthSafeJson;
1522
+ readonly fieldErrors?: { readonly [field: string]: string };
1523
+ readonly details?: AuthSafeData;
1524
+ };
1525
+
1526
+ export interface AuthFlowTerminalContext {
1527
+ readonly signal?: AbortSignal;
1528
+ readonly deadline?: string;
1529
+ complete<TCredential extends Record<string, string>>(options: {
1530
+ readonly credential: TCredential;
1531
+ readonly metadata?: AuthSafeData;
1532
+ readonly data?: AuthSafeData;
1533
+ readonly turnId?: string;
1534
+ readonly expiresAt?: string;
1535
+ }): AuthTurn;
1536
+ abort(options: {
1537
+ readonly code: string;
1538
+ readonly message?: string;
1539
+ readonly retry?: AuthAbortRetry;
1540
+ readonly actionHint?: AuthSafeJson;
1541
+ readonly fieldErrors?: { readonly [field: string]: string };
1542
+ readonly data?: AuthSafeData;
1543
+ readonly turnId?: string;
1544
+ readonly expiresAt?: string;
1545
+ }): AuthTurn;
1546
+ nextForm(
1547
+ options: {
1548
+ readonly hintKey?: ProviderLocaleKeyInput;
1549
+ readonly data?: AuthSafeData;
1550
+ readonly turnId?: string;
1551
+ readonly expiresAt?: string;
1552
+ readonly timing?: AuthTurn["timing"];
1553
+ } & (
1554
+ | {
1555
+ readonly fields: Record<
1556
+ string,
1557
+ {
1558
+ readonly type?: "string" | "email" | "password" | "otp";
1559
+ readonly labelKey?: ProviderLocaleKeyInput;
1560
+ readonly descriptionKey?: ProviderLocaleKeyInput;
1561
+ readonly placeholderKey?: ProviderLocaleKeyInput;
1562
+ readonly required?: boolean;
1563
+ readonly sensitive?: boolean;
1564
+ }
1565
+ >;
1566
+ readonly expectedInput?: never;
1567
+ }
1568
+ | {
1569
+ readonly expectedInput: Record<string, unknown>;
1570
+ readonly fields?: never;
1571
+ }
1572
+ ),
1573
+ ): AuthTurn;
1574
+ nextPoll(options?: {
1575
+ readonly hintKey?: ProviderLocaleKeyInput;
1576
+ readonly data?: AuthSafeData;
1577
+ readonly turnId?: string;
1578
+ readonly expiresAt?: string;
1579
+ readonly timing?: AuthTurn["timing"];
1580
+ }): AuthTurn;
1581
+ }
1582
+
1400
1583
  export interface FlowContext {
1401
1584
  connectionId?: string;
1402
1585
  externalRef?: string;
@@ -1408,6 +1591,7 @@ export interface FlowContext {
1408
1591
  credential?: CredentialContext;
1409
1592
  context: ContextScratchpad;
1410
1593
  stt: SttContext;
1594
+ auth: AuthFlowTerminalContext;
1411
1595
  }
1412
1596
 
1413
1597
  export interface AuthTurn {
@@ -1636,5 +1820,7 @@ export interface ProviderDefinition {
1636
1820
  meta: ProviderMeta;
1637
1821
  operations: Record<string, OperationDefinition<SchemaLike, SchemaLike>>;
1638
1822
  healthMonitor?: ProviderHealthMonitorConfig;
1823
+ /** Transitional alias for `healthMonitor`; `defineProvider` mirrors both. */
1824
+ healthProbe?: ProviderHealthProbeConfig;
1639
1825
  healthJourneys?: readonly HealthJourneyDefinition[];
1640
1826
  }