@apifuse/provider-sdk 2.1.0-beta.5 → 2.1.0-beta.6
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/CHANGELOG.md +6 -0
- package/README.md +2 -2
- package/SUBMISSION.md +2 -1
- package/bin/apifuse-check.ts +60 -6
- package/bin/apifuse-dev.ts +48 -5
- package/bin/apifuse-perf.ts +50 -11
- package/bin/apifuse-record.ts +35 -11
- package/bin/apifuse-submit-check.ts +1425 -3
- package/package.json +107 -92
- package/src/ceremonies/index.ts +8 -2
- package/src/choice-token.ts +1 -0
- package/src/cli/commands.ts +8 -5
- package/src/cli/create.ts +28 -0
- package/src/cli/templates/provider/operations/ping.ts.tpl +3 -2
- package/src/cli/templates/provider/schemas/ping.ts.tpl +8 -0
- package/src/config/loader.ts +19 -1
- package/src/contract-json.ts +75 -0
- package/src/contract-serialization.ts +89 -0
- package/src/contract-types.ts +52 -0
- package/src/contract.ts +215 -0
- package/src/define.ts +37 -2
- package/src/errors.ts +15 -0
- package/src/i18n/catalog.ts +156 -0
- package/src/index.ts +22 -1
- package/src/lint.ts +256 -37
- package/src/provider.ts +45 -2
- package/src/runtime/browser.ts +685 -30
- package/src/runtime/cache.ts +35 -89
- package/src/runtime/choice.ts +760 -0
- package/src/runtime/executor.ts +19 -2
- package/src/runtime/redis.ts +116 -0
- package/src/runtime/state.ts +487 -0
- package/src/runtime/stealth.ts +8 -1
- package/src/server/serve.ts +361 -46
- package/src/server/types.ts +2 -0
- package/src/testing/run.ts +16 -3
- package/src/types.ts +209 -6
package/src/server/types.ts
CHANGED
|
@@ -82,8 +82,10 @@ export const AuthFlowRequestSchema = z.object({
|
|
|
82
82
|
externalRef: z.string().optional(),
|
|
83
83
|
tenantId: z.string().optional(),
|
|
84
84
|
providerId: z.string().optional(),
|
|
85
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
85
86
|
input: z.record(z.string(), z.unknown()).optional(),
|
|
86
87
|
context: z.record(z.string(), z.unknown()).optional(),
|
|
88
|
+
connection: OperationConnectionSchema.optional(),
|
|
87
89
|
});
|
|
88
90
|
|
|
89
91
|
export const AuthFlowSuccessResponseSchema = z.object({
|
package/src/testing/run.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { describe, expect, it } from "bun:test";
|
|
2
2
|
|
|
3
3
|
import { createProviderCache } from "../runtime/cache";
|
|
4
|
-
import {
|
|
4
|
+
import { createTestProviderChoiceContext } from "../runtime/choice";
|
|
5
|
+
import { createMemoryProviderRuntimeState } from "../runtime/state";
|
|
5
6
|
import { createUnsupportedSttClient } from "../runtime/stt";
|
|
6
7
|
import { safeParseSchemaSync } from "../schema";
|
|
7
8
|
import type {
|
|
@@ -149,11 +150,13 @@ function createSnapshotContext(rawFixture: unknown): ProviderContext {
|
|
|
149
150
|
getAccessToken: () => undefined,
|
|
150
151
|
getScopes: () => [],
|
|
151
152
|
};
|
|
153
|
+
const request = { headers: {} };
|
|
154
|
+
const state = createMemoryProviderRuntimeState();
|
|
152
155
|
|
|
153
156
|
return {
|
|
154
157
|
env: { get: () => undefined },
|
|
155
158
|
credential,
|
|
156
|
-
request
|
|
159
|
+
request,
|
|
157
160
|
http: {
|
|
158
161
|
request: async () => jsonResponse(rawFixture),
|
|
159
162
|
get: async () => jsonResponse(rawFixture),
|
|
@@ -164,7 +167,7 @@ function createSnapshotContext(rawFixture: unknown): ProviderContext {
|
|
|
164
167
|
sse: async () => unsupported("ctx.http.sse"),
|
|
165
168
|
},
|
|
166
169
|
cache: createProviderCache({ providerId: "standard-test" }),
|
|
167
|
-
state
|
|
170
|
+
state,
|
|
168
171
|
stealth: {
|
|
169
172
|
fetch: async () => unsupported("ctx.stealth.fetch"),
|
|
170
173
|
createSession: () => unsupported("ctx.stealth.createSession"),
|
|
@@ -172,6 +175,10 @@ function createSnapshotContext(rawFixture: unknown): ProviderContext {
|
|
|
172
175
|
browser: {
|
|
173
176
|
engine: "playwright-stealth",
|
|
174
177
|
newPage: async () => unsupported("ctx.browser.newPage"),
|
|
178
|
+
rawPage: async () => unsupported("ctx.browser.rawPage"),
|
|
179
|
+
withIsolatedContext: async () =>
|
|
180
|
+
unsupported("ctx.browser.withIsolatedContext"),
|
|
181
|
+
solveChallenge: async () => unsupported("ctx.browser.solveChallenge"),
|
|
175
182
|
},
|
|
176
183
|
trace: {
|
|
177
184
|
span: async (_name, fn) => fn(),
|
|
@@ -183,6 +190,12 @@ function createSnapshotContext(rawFixture: unknown): ProviderContext {
|
|
|
183
190
|
stt: createUnsupportedSttClient(
|
|
184
191
|
"Standard test snapshot context does not support ctx.stt.transcribe",
|
|
185
192
|
),
|
|
193
|
+
choice: createTestProviderChoiceContext({
|
|
194
|
+
providerId: "standard-test",
|
|
195
|
+
request,
|
|
196
|
+
credential,
|
|
197
|
+
state,
|
|
198
|
+
}),
|
|
186
199
|
};
|
|
187
200
|
}
|
|
188
201
|
|
package/src/types.ts
CHANGED
|
@@ -524,6 +524,26 @@ export interface HealthCheckAssertionContext<TOutput = unknown> {
|
|
|
524
524
|
readonly meta?: Record<string, unknown>;
|
|
525
525
|
}
|
|
526
526
|
|
|
527
|
+
export interface HealthCheckInputPreparationContext<TInput = unknown> {
|
|
528
|
+
readonly providerId: string;
|
|
529
|
+
readonly operationId: string;
|
|
530
|
+
readonly input: TInput;
|
|
531
|
+
readonly connectionId?: string;
|
|
532
|
+
readonly gateway: {
|
|
533
|
+
execute: (
|
|
534
|
+
providerId: string,
|
|
535
|
+
operationId: string,
|
|
536
|
+
input: unknown,
|
|
537
|
+
options?: { connectionId?: string },
|
|
538
|
+
) => Promise<{
|
|
539
|
+
status: number;
|
|
540
|
+
duration: number;
|
|
541
|
+
data: unknown;
|
|
542
|
+
meta?: Record<string, unknown>;
|
|
543
|
+
}>;
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
|
|
527
547
|
/**
|
|
528
548
|
* Optional return value from an assertions lambda. Allows the case to
|
|
529
549
|
* downgrade to "degraded" without throwing, and to attach a human-friendly
|
|
@@ -550,6 +570,14 @@ export interface HealthCheckCase<TInput = unknown, TOutput = unknown> {
|
|
|
550
570
|
description?: string;
|
|
551
571
|
/** Input passed to the operation handler for this case. */
|
|
552
572
|
input: TInput;
|
|
573
|
+
/**
|
|
574
|
+
* Optional runtime input preparation hook for volatile probes. Use this when
|
|
575
|
+
* the durable probe input must be derived from a live read-only operation
|
|
576
|
+
* immediately before the checked operation executes.
|
|
577
|
+
*/
|
|
578
|
+
prepareInput?: (
|
|
579
|
+
ctx: HealthCheckInputPreparationContext<TInput>,
|
|
580
|
+
) => TInput | Promise<TInput>;
|
|
553
581
|
/**
|
|
554
582
|
* Assertion executed against the operation's response and timing.
|
|
555
583
|
*
|
|
@@ -694,6 +722,7 @@ export interface BrowserOptions {
|
|
|
694
722
|
stealth?: boolean;
|
|
695
723
|
proxy?: string;
|
|
696
724
|
engine?: BrowserEngine;
|
|
725
|
+
requireCdpPool?: boolean;
|
|
697
726
|
}
|
|
698
727
|
|
|
699
728
|
export interface StealthProfile {
|
|
@@ -950,6 +979,13 @@ export type HttpMethod =
|
|
|
950
979
|
export interface StealthFetchOptions extends RequestOptions {
|
|
951
980
|
method?: HttpMethod;
|
|
952
981
|
body?: string | Buffer;
|
|
982
|
+
/**
|
|
983
|
+
* Offsets policy-managed proxy pool selection for caller-managed retries.
|
|
984
|
+
* Use when a request receives an upstream challenge page rather than a
|
|
985
|
+
* transport error, so the next logical retry does not restart at the same
|
|
986
|
+
* operation-affinity proxy.
|
|
987
|
+
*/
|
|
988
|
+
proxyAttemptOffset?: number;
|
|
953
989
|
/** Override the configured browser-like stealth profile for this request. */
|
|
954
990
|
profile?: string;
|
|
955
991
|
/**
|
|
@@ -1139,9 +1175,62 @@ export interface StealthClient {
|
|
|
1139
1175
|
|
|
1140
1176
|
export interface BrowserClient {
|
|
1141
1177
|
readonly engine: BrowserEngine;
|
|
1142
|
-
|
|
1178
|
+
close?(): Promise<void>;
|
|
1179
|
+
newPage(): Promise<BrowserPage>;
|
|
1180
|
+
rawPage(): Promise<BrowserPage>;
|
|
1181
|
+
withIsolatedContext<T>(
|
|
1182
|
+
handler: (page: BrowserPage) => Promise<T>,
|
|
1183
|
+
): Promise<T>;
|
|
1184
|
+
solveChallenge(
|
|
1185
|
+
request: BrowserChallengeRequest,
|
|
1186
|
+
): Promise<BrowserChallengeResult>;
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
export interface BrowserLocator {
|
|
1190
|
+
click(): Promise<void>;
|
|
1191
|
+
fill(text: string): Promise<void>;
|
|
1192
|
+
textContent(): Promise<string | null>;
|
|
1193
|
+
waitFor(options?: { timeout?: number }): Promise<void>;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
export interface BrowserFrame {
|
|
1197
|
+
id: string;
|
|
1198
|
+
name?: string;
|
|
1199
|
+
parentId?: string;
|
|
1200
|
+
url(): Promise<string>;
|
|
1201
|
+
title(): Promise<string>;
|
|
1202
|
+
content(): Promise<string>;
|
|
1203
|
+
evaluate<T>(fn: string | (() => T)): Promise<T>;
|
|
1204
|
+
locator(selector: string): BrowserLocator;
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
export interface BrowserPage extends BrowserFrame {
|
|
1208
|
+
close(): Promise<void>;
|
|
1209
|
+
fill(selector: string, text: string): Promise<void>;
|
|
1210
|
+
goto(url: string): Promise<void>;
|
|
1211
|
+
pageId?: string;
|
|
1212
|
+
screenshot(options?: { fullPage?: boolean }): Promise<Buffer>;
|
|
1213
|
+
click(selector: string): Promise<void>;
|
|
1214
|
+
type(selector: string, text: string): Promise<void>;
|
|
1215
|
+
waitForSelector(
|
|
1216
|
+
selector: string,
|
|
1217
|
+
options?: { timeout?: number },
|
|
1218
|
+
): Promise<void>;
|
|
1219
|
+
frames(): Promise<BrowserFrame[]>;
|
|
1143
1220
|
}
|
|
1144
1221
|
|
|
1222
|
+
export type BrowserChallengeRequest = {
|
|
1223
|
+
type: "recaptcha";
|
|
1224
|
+
siteKey?: string;
|
|
1225
|
+
timeout?: number;
|
|
1226
|
+
};
|
|
1227
|
+
|
|
1228
|
+
export type BrowserChallengeResult = {
|
|
1229
|
+
type: BrowserChallengeRequest["type"];
|
|
1230
|
+
solved: boolean;
|
|
1231
|
+
frameUrl?: string;
|
|
1232
|
+
};
|
|
1233
|
+
|
|
1145
1234
|
export type TraceAttributeValue = string | number | boolean;
|
|
1146
1235
|
|
|
1147
1236
|
export interface TraceSpan {
|
|
@@ -1197,6 +1286,107 @@ export interface ProviderRequestContext {
|
|
|
1197
1286
|
headers: Record<string, string>;
|
|
1198
1287
|
}
|
|
1199
1288
|
|
|
1289
|
+
export interface ProviderChoiceBindingOptions {
|
|
1290
|
+
connection?: boolean;
|
|
1291
|
+
credentialKeys?: readonly string[];
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
export type ProviderChoiceStorageOptions =
|
|
1295
|
+
| {
|
|
1296
|
+
readonly mode: "inline";
|
|
1297
|
+
}
|
|
1298
|
+
| {
|
|
1299
|
+
readonly mode: "server";
|
|
1300
|
+
readonly namespace: string;
|
|
1301
|
+
readonly state?: ProviderRuntimeState;
|
|
1302
|
+
readonly ttl?: ProviderStateDurationString;
|
|
1303
|
+
readonly maxEntries: number;
|
|
1304
|
+
readonly maxValueBytes: number;
|
|
1305
|
+
readonly unavailable?: "reject";
|
|
1306
|
+
}
|
|
1307
|
+
| {
|
|
1308
|
+
readonly mode: "auto";
|
|
1309
|
+
readonly namespace: string;
|
|
1310
|
+
readonly state?: ProviderRuntimeState;
|
|
1311
|
+
readonly ttl?: ProviderStateDurationString;
|
|
1312
|
+
readonly maxInlineBytes: number;
|
|
1313
|
+
readonly maxEntries: number;
|
|
1314
|
+
readonly maxValueBytes: number;
|
|
1315
|
+
readonly unavailable?: "reject";
|
|
1316
|
+
};
|
|
1317
|
+
|
|
1318
|
+
export interface ProviderChoiceIssueOptions<
|
|
1319
|
+
TPayload extends Record<string, unknown>,
|
|
1320
|
+
> {
|
|
1321
|
+
prefix: string;
|
|
1322
|
+
purpose: string;
|
|
1323
|
+
payload: TPayload;
|
|
1324
|
+
ttlMs: number;
|
|
1325
|
+
nowMs?: number;
|
|
1326
|
+
bind?: ProviderChoiceBindingOptions;
|
|
1327
|
+
storage?: ProviderChoiceStorageOptions;
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
export interface ProviderChoiceParseOptions {
|
|
1331
|
+
token: string;
|
|
1332
|
+
prefix: string;
|
|
1333
|
+
purpose: string;
|
|
1334
|
+
ttlMs?: number;
|
|
1335
|
+
nowMs?: number;
|
|
1336
|
+
futureToleranceMs?: number;
|
|
1337
|
+
bind?: ProviderChoiceBindingOptions;
|
|
1338
|
+
storage?: ProviderChoiceStorageOptions;
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
export interface ProviderChoiceContext {
|
|
1342
|
+
issue<TPayload extends Record<string, unknown>>(
|
|
1343
|
+
options: ProviderChoiceIssueOptions<TPayload> & {
|
|
1344
|
+
readonly storage?: { readonly mode: "inline" };
|
|
1345
|
+
},
|
|
1346
|
+
): string;
|
|
1347
|
+
issue<TPayload extends Record<string, unknown>>(
|
|
1348
|
+
options: ProviderChoiceIssueOptions<TPayload> & {
|
|
1349
|
+
readonly storage: Extract<
|
|
1350
|
+
ProviderChoiceStorageOptions,
|
|
1351
|
+
{ readonly mode: "server" }
|
|
1352
|
+
>;
|
|
1353
|
+
},
|
|
1354
|
+
): Promise<string>;
|
|
1355
|
+
issue<TPayload extends Record<string, unknown>>(
|
|
1356
|
+
options: ProviderChoiceIssueOptions<TPayload> & {
|
|
1357
|
+
readonly storage: Extract<
|
|
1358
|
+
ProviderChoiceStorageOptions,
|
|
1359
|
+
{ readonly mode: "auto" }
|
|
1360
|
+
>;
|
|
1361
|
+
},
|
|
1362
|
+
): string | Promise<string>;
|
|
1363
|
+
issue<TPayload extends Record<string, unknown>>(
|
|
1364
|
+
options: ProviderChoiceIssueOptions<TPayload>,
|
|
1365
|
+
): string | Promise<string>;
|
|
1366
|
+
parse(
|
|
1367
|
+
options: ProviderChoiceParseOptions & {
|
|
1368
|
+
readonly storage?: { readonly mode: "inline" };
|
|
1369
|
+
},
|
|
1370
|
+
): Record<string, unknown>;
|
|
1371
|
+
parse(
|
|
1372
|
+
options: ProviderChoiceParseOptions & {
|
|
1373
|
+
readonly storage: Extract<
|
|
1374
|
+
ProviderChoiceStorageOptions,
|
|
1375
|
+
{ readonly mode: "server" }
|
|
1376
|
+
>;
|
|
1377
|
+
},
|
|
1378
|
+
): Promise<Record<string, unknown>>;
|
|
1379
|
+
parse(
|
|
1380
|
+
options: ProviderChoiceParseOptions & {
|
|
1381
|
+
readonly storage: Extract<
|
|
1382
|
+
ProviderChoiceStorageOptions,
|
|
1383
|
+
{ readonly mode: "auto" }
|
|
1384
|
+
>;
|
|
1385
|
+
},
|
|
1386
|
+
): Record<string, unknown> | Promise<Record<string, unknown>>;
|
|
1387
|
+
parse(options: ProviderChoiceParseOptions): Record<string, unknown>;
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1200
1390
|
export interface ContextScratchpad {
|
|
1201
1391
|
get(key: string): unknown;
|
|
1202
1392
|
set(key: string, value: unknown): void;
|
|
@@ -1213,6 +1403,7 @@ export interface FlowContext {
|
|
|
1213
1403
|
http: HttpClient;
|
|
1214
1404
|
stealth: StealthClient;
|
|
1215
1405
|
env: EnvContext;
|
|
1406
|
+
credential?: CredentialContext;
|
|
1216
1407
|
context: ContextScratchpad;
|
|
1217
1408
|
stt: SttContext;
|
|
1218
1409
|
}
|
|
@@ -1223,23 +1414,33 @@ export interface AuthTurn {
|
|
|
1223
1414
|
expiresAt?: string;
|
|
1224
1415
|
data?: Record<string, unknown>;
|
|
1225
1416
|
expectedInput?: Record<string, unknown>;
|
|
1417
|
+
/**
|
|
1418
|
+
* @deprecated Compatibility-only materialized provider auth hint.
|
|
1419
|
+
* Provider source must emit hintKey; SDK/server boundaries may materialize
|
|
1420
|
+
* this field from provider locale catalogs for legacy clients.
|
|
1421
|
+
*/
|
|
1226
1422
|
hint?: string;
|
|
1423
|
+
/** Provider locale catalog key for the auth turn hint. */
|
|
1424
|
+
hintKey?: ProviderLocaleKeyInput;
|
|
1227
1425
|
timing?: {
|
|
1228
1426
|
suggestedPollIntervalMs?: number;
|
|
1229
1427
|
maxWaitMs?: number;
|
|
1230
1428
|
};
|
|
1231
1429
|
}
|
|
1232
1430
|
|
|
1233
|
-
export type
|
|
1431
|
+
export type AuthFlowStartHandler = (ctx: FlowContext) => Promise<AuthTurn>;
|
|
1432
|
+
|
|
1433
|
+
export type AuthFlowInputHandler = (
|
|
1234
1434
|
ctx: FlowContext,
|
|
1235
1435
|
input?: Record<string, unknown>,
|
|
1236
1436
|
) => Promise<AuthTurn>;
|
|
1237
1437
|
|
|
1238
1438
|
export interface AuthFlowDefinition {
|
|
1239
|
-
start:
|
|
1240
|
-
continue:
|
|
1241
|
-
poll?:
|
|
1242
|
-
abort?:
|
|
1439
|
+
start: AuthFlowStartHandler;
|
|
1440
|
+
continue: AuthFlowInputHandler;
|
|
1441
|
+
poll?: AuthFlowStartHandler;
|
|
1442
|
+
abort?: AuthFlowStartHandler;
|
|
1443
|
+
refresh?: AuthFlowInputHandler;
|
|
1243
1444
|
}
|
|
1244
1445
|
|
|
1245
1446
|
export type ProviderStateDurationString =
|
|
@@ -1325,6 +1526,7 @@ export interface ProviderContext {
|
|
|
1325
1526
|
trace: TraceContext;
|
|
1326
1527
|
auth: AuthContext;
|
|
1327
1528
|
stt: SttContext;
|
|
1529
|
+
choice: ProviderChoiceContext;
|
|
1328
1530
|
}
|
|
1329
1531
|
|
|
1330
1532
|
export interface AuthConfig {
|
|
@@ -1384,6 +1586,7 @@ export interface OperationDefinition<
|
|
|
1384
1586
|
toolRouter?: OperationToolRouterMetadata;
|
|
1385
1587
|
observability?: OperationObservabilityConfig;
|
|
1386
1588
|
transport?: OperationTransport;
|
|
1589
|
+
retryOnAuthRefresh?: boolean;
|
|
1387
1590
|
input: TInput;
|
|
1388
1591
|
output: TOutput;
|
|
1389
1592
|
handler(
|