@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.
- package/AUTHORING.md +134 -0
- package/CHANGELOG.md +8 -0
- package/README.md +8 -0
- package/dist/auth.d.ts +76 -0
- package/dist/auth.js +436 -0
- package/dist/contract.js +1 -0
- package/dist/define.d.ts +4 -1
- package/dist/define.js +109 -46
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/lint.d.ts +1 -0
- package/dist/lint.js +27 -0
- package/dist/provider.d.ts +4 -2
- package/dist/provider.js +2 -1
- package/dist/runtime/auth-flow.js +2 -0
- package/dist/runtime/browser.js +203 -0
- package/dist/server/serve.js +16 -8
- package/dist/types.d.ts +106 -0
- package/package.json +1 -1
- package/src/auth.ts +786 -0
- package/src/contract.ts +1 -0
- package/src/define.ts +158 -48
- package/src/index.ts +10 -0
- package/src/lint.ts +33 -0
- package/src/provider.ts +27 -0
- package/src/runtime/auth-flow.ts +2 -0
- package/src/runtime/browser.ts +293 -1
- package/src/server/serve.ts +39 -4
- package/src/types.ts +136 -0
package/dist/server/serve.js
CHANGED
|
@@ -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