@apifuse/provider-sdk 2.1.0-beta.12 → 2.1.0-beta.14

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.
@@ -2,6 +2,7 @@ import { existsSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { Hono } from "hono";
4
4
  import { z } from "zod";
5
+ import { AuthAbortError, createAuthFlowHelpers } from "../auth";
5
6
  import { AuthError, ProviderError, SessionExpiredError, TransportError, } from "../errors";
6
7
  import { loadProviderLocaleCatalogs, localizeAuthTurn, } from "../i18n/catalog";
7
8
  import { categoryForStatus, isRetryableCategory, PROVIDER_OBSERVABILITY_TAXONOMY_VERSION, } from "../observability";
@@ -209,7 +210,7 @@ function createFlowContextStore(allowedKeys, initialContext = {}) {
209
210
  },
210
211
  };
211
212
  }
212
- function createAuthFlowContext(provider, request, options = {}) {
213
+ function createAuthFlowContext(provider, request, options = {}, signal) {
213
214
  const baseUrl = getProviderBaseUrl(provider);
214
215
  const stealthBaseUrl = getProviderStealthBaseUrl(provider);
215
216
  const stealthProfile = getProviderStealthProfile(provider);
@@ -251,6 +252,7 @@ function createAuthFlowContext(provider, request, options = {}) {
251
252
  credential,
252
253
  context: flowContextStore.context,
253
254
  stt: options.stt ?? createSttClientFromEnv(provider.stt),
255
+ auth: createAuthFlowHelpers({ signal }),
254
256
  },
255
257
  getPatch: flowContextStore.getPatch,
256
258
  };
@@ -879,14 +881,14 @@ function responseWithProviderTelemetry(response, proxyTelemetry) {
879
881
  statusText: response.statusText,
880
882
  });
881
883
  }
882
- async function handleAuthFlow(provider, request, route, options = {}) {
884
+ async function handleAuthFlow(provider, request, route, options = {}, signal) {
883
885
  const flow = provider.auth?.flow;
884
886
  if (!flow) {
885
887
  throw new ProviderError("Auth flow is not configured", {
886
888
  code: "AUTH_FLOW_NOT_CONFIGURED",
887
889
  });
888
890
  }
889
- const { context, getPatch } = createAuthFlowContext(provider, request, options);
891
+ const { context, getPatch } = createAuthFlowContext(provider, request, options, signal);
890
892
  try {
891
893
  const result = route === "start"
892
894
  ? await flow.start(context)
@@ -916,6 +918,12 @@ async function handleAuthFlow(provider, request, route, options = {}) {
916
918
  : result;
917
919
  return toAuthFlowResponse(materializedResult, getPatch());
918
920
  }
921
+ catch (error) {
922
+ if (error instanceof AuthAbortError) {
923
+ return toAuthFlowResponse(error.turn, getPatch());
924
+ }
925
+ throw error;
926
+ }
919
927
  finally {
920
928
  context.stealth.close?.();
921
929
  }
@@ -982,7 +990,7 @@ export function createServerApp(provider, options = {}) {
982
990
  .json()
983
991
  .catch(() => undefined);
984
992
  const body = withAuthRequestHeaders(AuthFlowRequestSchema.parse(rawBody), c.req.raw.headers);
985
- const response = await handleAuthFlow(provider, body, "start", options);
993
+ const response = await handleAuthFlow(provider, body, "start", options, c.req.raw.signal);
986
994
  logProviderSuccess(logger, provider, "auth", "start", body.requestId, response instanceof Response ? response.status : 200, finishRequestCost(requestCost));
987
995
  return response instanceof Response ? response : c.json(response);
988
996
  }
@@ -1002,7 +1010,7 @@ export function createServerApp(provider, options = {}) {
1002
1010
  .json()
1003
1011
  .catch(() => undefined);
1004
1012
  const body = withAuthRequestHeaders(AuthFlowRequestSchema.parse(rawBody), c.req.raw.headers);
1005
- const response = await handleAuthFlow(provider, body, "continue", options);
1013
+ const response = await handleAuthFlow(provider, body, "continue", options, c.req.raw.signal);
1006
1014
  logProviderSuccess(logger, provider, "auth", "continue", body.requestId, response instanceof Response ? response.status : 200, finishRequestCost(requestCost));
1007
1015
  return response instanceof Response ? response : c.json(response);
1008
1016
  }
@@ -1022,7 +1030,7 @@ export function createServerApp(provider, options = {}) {
1022
1030
  .json()
1023
1031
  .catch(() => undefined);
1024
1032
  const body = withAuthRequestHeaders(AuthFlowRequestSchema.parse(rawBody), c.req.raw.headers);
1025
- const response = await handleAuthFlow(provider, body, "poll", options);
1033
+ const response = await handleAuthFlow(provider, body, "poll", options, c.req.raw.signal);
1026
1034
  logProviderSuccess(logger, provider, "auth", "poll", body.requestId, response instanceof Response ? response.status : 200, finishRequestCost(requestCost));
1027
1035
  return response instanceof Response ? response : c.json(response);
1028
1036
  }
@@ -1042,7 +1050,7 @@ export function createServerApp(provider, options = {}) {
1042
1050
  .json()
1043
1051
  .catch(() => undefined);
1044
1052
  const body = withAuthRequestHeaders(AuthFlowRequestSchema.parse(rawBody), c.req.raw.headers);
1045
- const response = await handleAuthFlow(provider, body, "refresh", options);
1053
+ const response = await handleAuthFlow(provider, body, "refresh", options, c.req.raw.signal);
1046
1054
  logProviderSuccess(logger, provider, "auth", "refresh", body.requestId, response instanceof Response ? response.status : 200, finishRequestCost(requestCost));
1047
1055
  return response instanceof Response ? response : c.json(response);
1048
1056
  }
@@ -1062,7 +1070,7 @@ export function createServerApp(provider, options = {}) {
1062
1070
  .json()
1063
1071
  .catch(() => undefined);
1064
1072
  const body = withAuthRequestHeaders(AuthFlowRequestSchema.parse(rawBody), c.req.raw.headers);
1065
- const response = await handleAuthFlow(provider, body, "abort", options);
1073
+ const response = await handleAuthFlow(provider, body, "abort", options, c.req.raw.signal);
1066
1074
  logProviderSuccess(logger, provider, "auth", "disconnect", body.requestId, response instanceof Response ? response.status : 200, finishRequestCost(requestCost));
1067
1075
  return response instanceof Response ? response : c.json(response);
1068
1076
  }
package/dist/types.d.ts CHANGED
@@ -268,8 +268,16 @@ export interface HealthJourneySchedule {
268
268
  kind: "interval";
269
269
  /** ISO 8601 duration, for example PT8H. */
270
270
  interval: Iso8601Duration;
271
+ randomize?: HealthScheduleRandomization;
271
272
  jitter?: Iso8601Duration;
272
273
  }
274
+ export type HealthScheduleRandomization = {
275
+ mode: "centered";
276
+ maxOffset: Iso8601Duration;
277
+ } | {
278
+ mode: "delayed";
279
+ maxDelay: Iso8601Duration;
280
+ };
273
281
  export interface HealthJourneyStep {
274
282
  id: string;
275
283
  description?: string;
@@ -511,6 +519,9 @@ export interface HealthCheckCase<TInput = unknown, TOutput = unknown> {
511
519
  export interface HealthCheckSuite<TInput = unknown, TOutput = unknown> {
512
520
  /** Polling interval for the suite. All cases share this cadence. */
513
521
  interval: ProbeInterval;
522
+ schedule?: {
523
+ randomize?: HealthScheduleRandomization;
524
+ };
514
525
  /** Per-case timeout in milliseconds. Default: 30000. */
515
526
  timeoutMs?: number;
516
527
  /** Default degradation threshold for cases in this suite. Default: runtime threshold. */
@@ -1016,6 +1027,32 @@ export interface BrowserFrame {
1016
1027
  evaluate<T>(fn: string | (() => T)): Promise<T>;
1017
1028
  locator(selector: string): BrowserLocator;
1018
1029
  }
1030
+ export type BrowserResourceMethod = "GET" | "HEAD";
1031
+ export type BrowserResourceRequest = {
1032
+ readonly url: string;
1033
+ readonly method: BrowserResourceMethod;
1034
+ readonly resourceType?: string;
1035
+ readonly headers: Readonly<Record<string, string>>;
1036
+ };
1037
+ export type BrowserResourceBody = Buffer | Uint8Array | ArrayBuffer | string;
1038
+ export type BrowserResourceDecision = {
1039
+ readonly action: "fulfill";
1040
+ readonly status?: number;
1041
+ readonly headers?: Readonly<Record<string, string>>;
1042
+ readonly body?: BrowserResourceBody;
1043
+ } | {
1044
+ readonly action: "block";
1045
+ readonly reason?: string;
1046
+ };
1047
+ export type BrowserResourceRoute = {
1048
+ readonly match: string | RegExp | ((request: BrowserResourceRequest) => boolean);
1049
+ readonly handle: (request: BrowserResourceRequest) => Promise<BrowserResourceDecision> | BrowserResourceDecision;
1050
+ };
1051
+ export type BrowserResourcePolicy = {
1052
+ readonly defaultAction?: "block";
1053
+ readonly allowedMethods?: readonly BrowserResourceMethod[];
1054
+ readonly routes: readonly BrowserResourceRoute[];
1055
+ };
1019
1056
  export interface BrowserPage extends BrowserFrame {
1020
1057
  close(): Promise<void>;
1021
1058
  fill(selector: string, text: string): Promise<void>;
@@ -1030,6 +1067,7 @@ export interface BrowserPage extends BrowserFrame {
1030
1067
  timeout?: number;
1031
1068
  }): Promise<void>;
1032
1069
  frames(): Promise<BrowserFrame[]>;
1070
+ withResourcePolicy<T>(policy: BrowserResourcePolicy, run: () => Promise<T>): Promise<T>;
1033
1071
  }
1034
1072
  export type BrowserChallengeRequest = {
1035
1073
  type: "recaptcha";
@@ -1170,6 +1208,73 @@ export interface ContextScratchpad {
1170
1208
  toJSON(): Record<string, unknown>;
1171
1209
  }
1172
1210
  export type FlowContextStore = ContextScratchpad;
1211
+ export type AuthSafeJson = string | number | boolean | null | readonly AuthSafeJson[] | {
1212
+ readonly [key: string]: AuthSafeJson;
1213
+ };
1214
+ export type AuthSafeData = {
1215
+ readonly [key: string]: AuthSafeJson;
1216
+ };
1217
+ export type AuthAbortRetry = "never" | "retry" | "after_user_action";
1218
+ export type AuthAbortData = Record<string, unknown> & {
1219
+ readonly code: string;
1220
+ readonly message?: string;
1221
+ readonly retry?: AuthAbortRetry;
1222
+ readonly actionHint?: AuthSafeJson;
1223
+ readonly fieldErrors?: {
1224
+ readonly [field: string]: string;
1225
+ };
1226
+ readonly details?: AuthSafeData;
1227
+ };
1228
+ export interface AuthFlowTerminalContext {
1229
+ readonly signal?: AbortSignal;
1230
+ readonly deadline?: string;
1231
+ complete<TCredential extends Record<string, string>>(options: {
1232
+ readonly credential: TCredential;
1233
+ readonly metadata?: AuthSafeData;
1234
+ readonly data?: AuthSafeData;
1235
+ readonly turnId?: string;
1236
+ readonly expiresAt?: string;
1237
+ }): AuthTurn;
1238
+ abort(options: {
1239
+ readonly code: string;
1240
+ readonly message?: string;
1241
+ readonly retry?: AuthAbortRetry;
1242
+ readonly actionHint?: AuthSafeJson;
1243
+ readonly fieldErrors?: {
1244
+ readonly [field: string]: string;
1245
+ };
1246
+ readonly data?: AuthSafeData;
1247
+ readonly turnId?: string;
1248
+ readonly expiresAt?: string;
1249
+ }): AuthTurn;
1250
+ nextForm(options: {
1251
+ readonly hintKey?: ProviderLocaleKeyInput;
1252
+ readonly data?: AuthSafeData;
1253
+ readonly turnId?: string;
1254
+ readonly expiresAt?: string;
1255
+ readonly timing?: AuthTurn["timing"];
1256
+ } & ({
1257
+ readonly fields: Record<string, {
1258
+ readonly type?: "string" | "email" | "password" | "otp";
1259
+ readonly labelKey?: ProviderLocaleKeyInput;
1260
+ readonly descriptionKey?: ProviderLocaleKeyInput;
1261
+ readonly placeholderKey?: ProviderLocaleKeyInput;
1262
+ readonly required?: boolean;
1263
+ readonly sensitive?: boolean;
1264
+ }>;
1265
+ readonly expectedInput?: never;
1266
+ } | {
1267
+ readonly expectedInput: Record<string, unknown>;
1268
+ readonly fields?: never;
1269
+ })): AuthTurn;
1270
+ nextPoll(options?: {
1271
+ readonly hintKey?: ProviderLocaleKeyInput;
1272
+ readonly data?: AuthSafeData;
1273
+ readonly turnId?: string;
1274
+ readonly expiresAt?: string;
1275
+ readonly timing?: AuthTurn["timing"];
1276
+ }): AuthTurn;
1277
+ }
1173
1278
  export interface FlowContext {
1174
1279
  connectionId?: string;
1175
1280
  externalRef?: string;
@@ -1181,6 +1286,7 @@ export interface FlowContext {
1181
1286
  credential?: CredentialContext;
1182
1287
  context: ContextScratchpad;
1183
1288
  stt: SttContext;
1289
+ auth: AuthFlowTerminalContext;
1184
1290
  }
1185
1291
  export interface AuthTurn {
1186
1292
  kind: string;
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.1.0-beta.12",
2
+ "version": "2.1.0-beta.14",
3
3
  "name": "@apifuse/provider-sdk",
4
4
  "private": false,
5
5
  "type": "module",