@apifuse/provider-sdk 2.0.0-beta.1 → 2.1.0-beta.0

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 (78) hide show
  1. package/AUTHORING.md +102 -0
  2. package/CHANGELOG.md +14 -0
  3. package/README.md +100 -28
  4. package/bin/apifuse-check.ts +78 -71
  5. package/bin/apifuse-create.ts +12 -0
  6. package/bin/apifuse-dev.ts +24 -61
  7. package/bin/apifuse-pack-check.ts +47 -0
  8. package/bin/apifuse-perf.ts +33 -32
  9. package/bin/apifuse-record.ts +17 -7
  10. package/bin/apifuse-test.ts +6 -4
  11. package/bin/apifuse.ts +36 -35
  12. package/package.json +28 -9
  13. package/src/ceremonies/index.ts +747 -0
  14. package/src/cli/commands.ts +87 -0
  15. package/src/cli/create.ts +845 -0
  16. package/src/cli/templates/provider/Dockerfile.tpl +7 -0
  17. package/src/cli/templates/provider/README.md.tpl +28 -0
  18. package/src/cli/templates/provider/dev.ts.tpl +5 -0
  19. package/src/cli/templates/provider/index.test.ts.tpl +13 -0
  20. package/src/cli/templates/provider/index.ts.tpl +54 -0
  21. package/src/cli/templates/provider/start.ts.tpl +5 -0
  22. package/src/composite.ts +43 -0
  23. package/src/define.ts +527 -41
  24. package/src/dev.ts +2 -6
  25. package/src/errors.ts +42 -0
  26. package/src/index.ts +50 -38
  27. package/src/lint.ts +574 -0
  28. package/src/provider.ts +14 -0
  29. package/src/runtime/auth-flow.ts +67 -0
  30. package/src/runtime/credential.ts +95 -0
  31. package/src/runtime/env.ts +13 -0
  32. package/src/runtime/executor.ts +13 -14
  33. package/src/runtime/http.ts +10 -2
  34. package/src/runtime/insights.ts +3 -3
  35. package/src/runtime/key-derivation.ts +122 -0
  36. package/src/runtime/keyring.ts +148 -0
  37. package/src/runtime/namespace.ts +33 -0
  38. package/src/runtime/prevalidate.ts +252 -0
  39. package/src/runtime/tls.ts +20 -5
  40. package/src/runtime/waterfall.ts +0 -1
  41. package/src/schema.ts +77 -0
  42. package/src/serve.ts +1 -664
  43. package/src/server/index.ts +22 -0
  44. package/src/server/serve.ts +610 -0
  45. package/src/server/types.ts +78 -0
  46. package/src/stealth/profiles.ts +10 -93
  47. package/src/testing/run.ts +391 -32
  48. package/src/types.ts +364 -41
  49. package/bin/apifuse-init.ts +0 -387
  50. package/src/__tests__/auth.test.ts +0 -396
  51. package/src/__tests__/browser-auth.test.ts +0 -180
  52. package/src/__tests__/browser.test.ts +0 -632
  53. package/src/__tests__/define.test.ts +0 -225
  54. package/src/__tests__/errors.test.ts +0 -69
  55. package/src/__tests__/executor.test.ts +0 -214
  56. package/src/__tests__/http.test.ts +0 -238
  57. package/src/__tests__/insights.test.ts +0 -210
  58. package/src/__tests__/instrumentation.test.ts +0 -290
  59. package/src/__tests__/otlp.test.ts +0 -141
  60. package/src/__tests__/perf.test.ts +0 -60
  61. package/src/__tests__/providers-yaml.test.ts +0 -135
  62. package/src/__tests__/proxy.test.ts +0 -359
  63. package/src/__tests__/recipes.test.ts +0 -36
  64. package/src/__tests__/serve.test.ts +0 -233
  65. package/src/__tests__/session.test.ts +0 -231
  66. package/src/__tests__/state.test.ts +0 -100
  67. package/src/__tests__/stealth.test.ts +0 -57
  68. package/src/__tests__/testing.test.ts +0 -97
  69. package/src/__tests__/tls.test.ts +0 -345
  70. package/src/__tests__/types.test.ts +0 -142
  71. package/src/__tests__/utils.test.ts +0 -62
  72. package/src/__tests__/waterfall.test.ts +0 -270
  73. package/src/config/providers-yaml.ts +0 -370
  74. package/src/index.test.ts +0 -1
  75. package/src/protocol.ts +0 -183
  76. package/src/runtime/auth.ts +0 -245
  77. package/src/runtime/session.ts +0 -573
  78. package/src/runtime/state.ts +0 -124
@@ -0,0 +1,610 @@
1
+ import { Hono } from "hono";
2
+ import { z } from "zod";
3
+
4
+ import { ProviderError, TransportError } from "../errors";
5
+ import { createScratchpad } from "../runtime/auth-flow";
6
+ import { createBrowserClient } from "../runtime/browser";
7
+ import { createCredentialContext } from "../runtime/credential";
8
+ import { createEnvContext } from "../runtime/env";
9
+ import { executeOperation } from "../runtime/executor";
10
+ import { createHttpClient } from "../runtime/http";
11
+ import { getProviderBaseUrl } from "../runtime/provider";
12
+ import { createTlsClient } from "../runtime/tls";
13
+ import { createTraceContext } from "../runtime/trace";
14
+ import type {
15
+ AuthContext,
16
+ BrowserClient,
17
+ FlowContext,
18
+ FlowContextStore,
19
+ ProviderContext,
20
+ ProviderDefinition,
21
+ TlsClient,
22
+ } from "../types";
23
+ import {
24
+ type AuthFlowRequest,
25
+ AuthFlowRequestSchema,
26
+ type AuthFlowResponse,
27
+ type AuthFlowSuccessResponse,
28
+ type OperationErrorResponse,
29
+ type OperationRequest,
30
+ OperationRequestSchema,
31
+ type OperationResponse,
32
+ type OperationSuccessResponse,
33
+ } from "./types";
34
+
35
+ const DEFAULT_HOST = "0.0.0.0";
36
+ const DEFAULT_PORT = 3000;
37
+
38
+ function createAuthStub(): AuthContext {
39
+ return {
40
+ async requestField(name) {
41
+ throw new ProviderError(`Auth prompt is unavailable for ${name}`, {
42
+ code: "AUTH_PROMPT_UNAVAILABLE",
43
+ });
44
+ },
45
+ };
46
+ }
47
+
48
+ function createBrowserStub(): BrowserClient {
49
+ return {
50
+ engine: "playwright-stealth",
51
+ async newPage() {
52
+ throw new ProviderError("Browser runtime is not available", {
53
+ code: "BROWSER_RUNTIME_UNSUPPORTED",
54
+ });
55
+ },
56
+ };
57
+ }
58
+
59
+ function createTlsStub(): TlsClient {
60
+ return {
61
+ async fetch() {
62
+ throw new ProviderError("TLS runtime is not available", {
63
+ code: "TLS_RUNTIME_UNSUPPORTED",
64
+ });
65
+ },
66
+ createSession() {
67
+ throw new ProviderError("TLS runtime is not available", {
68
+ code: "TLS_RUNTIME_UNSUPPORTED",
69
+ });
70
+ },
71
+ };
72
+ }
73
+
74
+ function createProviderContext(
75
+ provider: ProviderDefinition,
76
+ request: OperationRequest,
77
+ ): ProviderContext {
78
+ const baseUrl = getProviderBaseUrl(provider);
79
+
80
+ return {
81
+ env: createEnvContext(provider.secrets?.map((secret) => secret.name)),
82
+ credential: createCredentialContext({
83
+ allowedKeys: provider.credential?.keys,
84
+ mode: request.connection?.mode,
85
+ scopes: request.connection?.scopes,
86
+ values: request.connection?.secrets,
87
+ }),
88
+ request: {
89
+ connectionId: request.connection?.id,
90
+ headers: request.headers ?? {},
91
+ },
92
+ http: createHttpClient(baseUrl),
93
+ tls: baseUrl ? createTlsClient(baseUrl) : createTlsStub(),
94
+ browser:
95
+ provider.runtime === "browser"
96
+ ? createBrowserClient({
97
+ cdpUrl:
98
+ process.env.CDP_POOL_URL ?? process.env.APIFUSE_CDP_POOL_URL,
99
+ headless: true,
100
+ stealth: true,
101
+ engine: provider.browser?.engine,
102
+ })
103
+ : createBrowserStub(),
104
+ trace: createTraceContext(),
105
+ auth: createAuthStub(),
106
+ };
107
+ }
108
+
109
+ function createFlowContextStore(
110
+ allowedKeys: string[],
111
+ initialContext: Record<string, unknown> = {},
112
+ ): {
113
+ context: FlowContextStore;
114
+ getPatch: () => Record<string, unknown | null> | undefined;
115
+ } {
116
+ const context = createScratchpad(allowedKeys, initialContext);
117
+
118
+ return {
119
+ context,
120
+ getPatch() {
121
+ const next = context.toJSON();
122
+ const patch = new Map<string, unknown | null>();
123
+
124
+ for (const [key, value] of Object.entries(next)) {
125
+ if (initialContext[key] !== value) {
126
+ patch.set(key, value);
127
+ }
128
+ }
129
+
130
+ for (const key of Object.keys(initialContext)) {
131
+ if (!(key in next)) {
132
+ patch.set(key, null);
133
+ }
134
+ }
135
+
136
+ if (patch.size === 0) {
137
+ return undefined;
138
+ }
139
+
140
+ return Object.fromEntries(patch.entries());
141
+ },
142
+ };
143
+ }
144
+
145
+ function createAuthFlowContext(
146
+ provider: ProviderDefinition,
147
+ request: AuthFlowRequest,
148
+ ): {
149
+ context: FlowContext;
150
+ getPatch: () => Record<string, unknown | null> | undefined;
151
+ } {
152
+ const baseUrl = getProviderBaseUrl(provider);
153
+ const contextData = request.context ?? {};
154
+ const flowContextStore = createFlowContextStore(
155
+ provider.context?.keys ?? Object.keys(contextData),
156
+ contextData,
157
+ );
158
+
159
+ return {
160
+ context: {
161
+ connectionId: request.connectionId,
162
+ externalRef: request.externalRef,
163
+ tenantId: request.tenantId ?? "",
164
+ providerId: request.providerId ?? provider.id,
165
+ http: createHttpClient(baseUrl),
166
+ env: createEnvContext(provider.secrets?.map((secret) => secret.name)),
167
+ context: flowContextStore.context,
168
+ },
169
+ getPatch: flowContextStore.getPatch,
170
+ };
171
+ }
172
+
173
+ export type ProviderServerLogEvent = {
174
+ level: "warn" | "error";
175
+ event: "provider_request_failed";
176
+ providerId: string;
177
+ kind: "operation" | "auth";
178
+ route: string;
179
+ requestId?: string;
180
+ status: number;
181
+ code: string;
182
+ errorClass: string;
183
+ message: string;
184
+ upstreamStatus?: number;
185
+ issues?: Array<{ path: string; code: string; message: string }>;
186
+ };
187
+
188
+ export type ProviderServerLogger = (event: ProviderServerLogEvent) => void;
189
+
190
+ export type ProviderServerOptions = {
191
+ logger?: ProviderServerLogger;
192
+ };
193
+
194
+ const defaultProviderServerLogger: ProviderServerLogger = (event) => {
195
+ console.error(JSON.stringify(event));
196
+ };
197
+
198
+ function zodDetails(error: z.ZodError): Array<{
199
+ path: string;
200
+ code: string;
201
+ message: string;
202
+ }> {
203
+ return error.issues.map((issue) => ({
204
+ path: issue.path.join("."),
205
+ code: issue.code,
206
+ message: issue.message,
207
+ }));
208
+ }
209
+
210
+ function toErrorResponse(
211
+ error: unknown,
212
+ requestId?: string,
213
+ ): OperationErrorResponse {
214
+ if (error instanceof ProviderError) {
215
+ return {
216
+ error: {
217
+ code: error.code ?? "provider_error",
218
+ message: error.message,
219
+ ...(requestId ? { requestId } : {}),
220
+ ...(error.fix ? { fix: error.fix } : {}),
221
+ ...(error instanceof TransportError && error.status
222
+ ? { details: { upstreamStatus: error.status } }
223
+ : {}),
224
+ },
225
+ };
226
+ }
227
+
228
+ if (error instanceof z.ZodError) {
229
+ return {
230
+ error: {
231
+ code: "invalid_request",
232
+ message: "Invalid request body",
233
+ ...(requestId ? { requestId } : {}),
234
+ details: zodDetails(error),
235
+ },
236
+ };
237
+ }
238
+
239
+ return {
240
+ error: {
241
+ code: "internal_error",
242
+ message: "Internal error",
243
+ ...(requestId ? { requestId } : {}),
244
+ },
245
+ };
246
+ }
247
+
248
+ function toStatusCode(error: unknown): 400 | 404 | 500 | 502 | 504 {
249
+ if (error instanceof z.ZodError) {
250
+ return 400;
251
+ }
252
+
253
+ if (error instanceof TransportError) {
254
+ return error.code === "transport_timeout" ? 504 : 502;
255
+ }
256
+
257
+ if (error instanceof ProviderError) {
258
+ if (error.code === "NOT_FOUND") {
259
+ return 404;
260
+ }
261
+
262
+ return 400;
263
+ }
264
+
265
+ return 500;
266
+ }
267
+
268
+ function extractRequestId(raw: unknown): string | undefined {
269
+ if (!raw || typeof raw !== "object") {
270
+ return undefined;
271
+ }
272
+
273
+ const value = Object.getOwnPropertyDescriptor(raw, "requestId")?.value;
274
+ return typeof value === "string" ? value : undefined;
275
+ }
276
+
277
+ function logProviderError(
278
+ logger: ProviderServerLogger | unknown,
279
+ provider: ProviderDefinition,
280
+ kind: "operation" | "auth",
281
+ route: string,
282
+ requestId: string | undefined,
283
+ error: unknown,
284
+ status: number,
285
+ ): void {
286
+ const code =
287
+ error instanceof ProviderError
288
+ ? (error.code ?? "provider_error")
289
+ : error instanceof z.ZodError
290
+ ? "invalid_request"
291
+ : "internal_error";
292
+ const errorClass = error instanceof Error ? error.name : typeof error;
293
+ const message = error instanceof Error ? error.message : String(error);
294
+ const emit =
295
+ typeof logger === "function" ? logger : defaultProviderServerLogger;
296
+ emit({
297
+ level: status >= 500 ? "error" : "warn",
298
+ event: "provider_request_failed",
299
+ providerId: provider.id,
300
+ kind,
301
+ route,
302
+ ...(requestId ? { requestId } : {}),
303
+ status,
304
+ code,
305
+ errorClass,
306
+ message,
307
+ ...(error instanceof TransportError && error.status
308
+ ? { upstreamStatus: error.status }
309
+ : {}),
310
+ ...(error instanceof z.ZodError ? { issues: zodDetails(error) } : {}),
311
+ });
312
+ }
313
+
314
+ function toJsonSuccessResponse(
315
+ result: unknown,
316
+ ): Response | OperationSuccessResponse {
317
+ if (result instanceof Response) {
318
+ return result;
319
+ }
320
+
321
+ if (result instanceof ReadableStream) {
322
+ return new Response(result);
323
+ }
324
+
325
+ return { data: result };
326
+ }
327
+
328
+ function toAuthFlowResponse(
329
+ result: unknown,
330
+ contextPatch: Record<string, unknown | null> | undefined,
331
+ ): Response | AuthFlowSuccessResponse {
332
+ if (result instanceof Response) {
333
+ return result;
334
+ }
335
+
336
+ if (result instanceof ReadableStream) {
337
+ return new Response(result);
338
+ }
339
+
340
+ return {
341
+ data: result,
342
+ ...(contextPatch ? { contextPatch } : {}),
343
+ };
344
+ }
345
+
346
+ async function handleOperation(
347
+ provider: ProviderDefinition,
348
+ request: OperationRequest,
349
+ operationId: string,
350
+ ): Promise<Response | OperationResponse> {
351
+ const ctx = createProviderContext(provider, request);
352
+ const result = await executeOperation(
353
+ provider,
354
+ operationId,
355
+ ctx,
356
+ request.input,
357
+ );
358
+ return toJsonSuccessResponse(result);
359
+ }
360
+
361
+ type AuthRoute = "start" | "continue" | "poll" | "abort";
362
+
363
+ async function handleAuthFlow(
364
+ provider: ProviderDefinition,
365
+ request: AuthFlowRequest,
366
+ route: AuthRoute,
367
+ ): Promise<Response | AuthFlowResponse> {
368
+ const flow = provider.auth?.flow;
369
+ if (!flow) {
370
+ throw new ProviderError("Auth flow is not configured", {
371
+ code: "AUTH_FLOW_NOT_CONFIGURED",
372
+ });
373
+ }
374
+
375
+ const { context, getPatch } = createAuthFlowContext(provider, request);
376
+
377
+ const result =
378
+ route === "start"
379
+ ? await flow.start(context)
380
+ : route === "continue"
381
+ ? await flow.continue(context, request.input ?? {})
382
+ : route === "poll"
383
+ ? flow.poll
384
+ ? await flow.poll(context)
385
+ : null
386
+ : flow.abort
387
+ ? await flow.abort(context)
388
+ : null;
389
+
390
+ return toAuthFlowResponse(result, getPatch());
391
+ }
392
+
393
+ export function createServerApp(
394
+ provider: ProviderDefinition,
395
+ options: ProviderServerOptions = {},
396
+ ): Hono {
397
+ const app = new Hono();
398
+ const logger = options.logger ?? defaultProviderServerLogger;
399
+
400
+ app.notFound((c) =>
401
+ c.json(
402
+ {
403
+ error: {
404
+ code: "not_found",
405
+ message: "Not found",
406
+ },
407
+ },
408
+ 404,
409
+ ),
410
+ );
411
+
412
+ app.get("/health", (c) =>
413
+ c.json({
414
+ status: "ok",
415
+ provider: provider.id,
416
+ version: provider.version,
417
+ }),
418
+ );
419
+
420
+ app.post("/v1/:operation", async (c) => {
421
+ let rawBody: unknown;
422
+ const operation = c.req.param("operation");
423
+ try {
424
+ rawBody = await c.req.raw
425
+ .clone()
426
+ .json()
427
+ .catch(() => undefined);
428
+ const body = OperationRequestSchema.parse(rawBody);
429
+ const requestHeaders = Object.fromEntries(c.req.raw.headers.entries());
430
+ body.headers = { ...requestHeaders, ...body.headers };
431
+ const response = await handleOperation(provider, body, operation);
432
+ return response instanceof Response ? response : c.json(response);
433
+ } catch (error) {
434
+ const status = toStatusCode(error);
435
+ const requestId = extractRequestId(rawBody);
436
+ logProviderError(
437
+ logger,
438
+ provider,
439
+ "operation",
440
+ operation,
441
+ requestId,
442
+ error,
443
+ status,
444
+ );
445
+ return c.json(toErrorResponse(error, requestId), status);
446
+ }
447
+ });
448
+
449
+ app.post("/auth/start", async (c) => {
450
+ let rawBody: unknown;
451
+ try {
452
+ rawBody = await c.req.raw
453
+ .clone()
454
+ .json()
455
+ .catch(() => undefined);
456
+ const body = AuthFlowRequestSchema.parse(rawBody);
457
+ const response = await handleAuthFlow(provider, body, "start");
458
+ return response instanceof Response ? response : c.json(response);
459
+ } catch (error) {
460
+ const status = toStatusCode(error);
461
+ const requestId = extractRequestId(rawBody);
462
+ logProviderError(
463
+ logger,
464
+ provider,
465
+ "auth",
466
+ "start",
467
+ requestId,
468
+ error,
469
+ status,
470
+ );
471
+ return c.json(toErrorResponse(error, requestId), status);
472
+ }
473
+ });
474
+
475
+ app.post("/auth/continue", async (c) => {
476
+ let rawBody: unknown;
477
+ try {
478
+ rawBody = await c.req.raw
479
+ .clone()
480
+ .json()
481
+ .catch(() => undefined);
482
+ const body = AuthFlowRequestSchema.parse(rawBody);
483
+ const response = await handleAuthFlow(provider, body, "continue");
484
+ return response instanceof Response ? response : c.json(response);
485
+ } catch (error) {
486
+ const status = toStatusCode(error);
487
+ const requestId = extractRequestId(rawBody);
488
+ logProviderError(
489
+ logger,
490
+ provider,
491
+ "auth",
492
+ "continue",
493
+ requestId,
494
+ error,
495
+ status,
496
+ );
497
+ return c.json(toErrorResponse(error, requestId), status);
498
+ }
499
+ });
500
+
501
+ app.post("/auth/poll", async (c) => {
502
+ let rawBody: unknown;
503
+ try {
504
+ rawBody = await c.req.raw
505
+ .clone()
506
+ .json()
507
+ .catch(() => undefined);
508
+ const body = AuthFlowRequestSchema.parse(rawBody);
509
+ const response = await handleAuthFlow(provider, body, "poll");
510
+ return response instanceof Response ? response : c.json(response);
511
+ } catch (error) {
512
+ const status = toStatusCode(error);
513
+ const requestId = extractRequestId(rawBody);
514
+ logProviderError(
515
+ logger,
516
+ provider,
517
+ "auth",
518
+ "poll",
519
+ requestId,
520
+ error,
521
+ status,
522
+ );
523
+ return c.json(toErrorResponse(error, requestId), status);
524
+ }
525
+ });
526
+
527
+ app.post("/auth/disconnect", async (c) => {
528
+ let rawBody: unknown;
529
+ try {
530
+ rawBody = await c.req.raw
531
+ .clone()
532
+ .json()
533
+ .catch(() => undefined);
534
+ const body = AuthFlowRequestSchema.parse(rawBody);
535
+ const response = await handleAuthFlow(provider, body, "abort");
536
+ return response instanceof Response ? response : c.json(response);
537
+ } catch (error) {
538
+ const status = toStatusCode(error);
539
+ const requestId = extractRequestId(rawBody);
540
+ logProviderError(
541
+ logger,
542
+ provider,
543
+ "auth",
544
+ "disconnect",
545
+ requestId,
546
+ error,
547
+ status,
548
+ );
549
+ return c.json(toErrorResponse(error, requestId), status);
550
+ }
551
+ });
552
+
553
+ return app;
554
+ }
555
+
556
+ type BunServeRuntime = {
557
+ serve: (options: {
558
+ port: number;
559
+ hostname: string;
560
+ fetch: (request: Request) => Response | Promise<Response>;
561
+ }) => unknown;
562
+ };
563
+
564
+ function getBunServeRuntime(): BunServeRuntime | undefined {
565
+ const bunValue = Object.getOwnPropertyDescriptor(globalThis, "Bun")?.value;
566
+ if (!bunValue || typeof bunValue !== "object") {
567
+ return undefined;
568
+ }
569
+
570
+ const serve = Object.getOwnPropertyDescriptor(bunValue, "serve")?.value;
571
+ if (typeof serve !== "function") {
572
+ return undefined;
573
+ }
574
+
575
+ return {
576
+ serve(options) {
577
+ return serve(options);
578
+ },
579
+ };
580
+ }
581
+
582
+ export interface ServeOptions extends ProviderServerOptions {
583
+ host?: string;
584
+ port?: number;
585
+ }
586
+
587
+ export async function serve(
588
+ provider: ProviderDefinition,
589
+ options: ServeOptions = {},
590
+ ): Promise<void> {
591
+ const bunRuntime = getBunServeRuntime();
592
+
593
+ if (bunRuntime === undefined) {
594
+ throw new ProviderError(
595
+ "Bun runtime is required to start the provider server",
596
+ {
597
+ code: "RUNTIME_UNSUPPORTED",
598
+ },
599
+ );
600
+ }
601
+
602
+ const app = createServerApp(provider, { logger: options.logger });
603
+
604
+ bunRuntime.serve({
605
+ port: options.port ?? DEFAULT_PORT,
606
+ hostname: options.host ?? DEFAULT_HOST,
607
+ fetch: app.fetch,
608
+ });
609
+ await Promise.resolve();
610
+ }
@@ -0,0 +1,78 @@
1
+ import { z } from "zod";
2
+
3
+ export const ConnectionModeSchema = z.enum([
4
+ "oauth2",
5
+ "credentials",
6
+ "platform-managed",
7
+ "none",
8
+ ]);
9
+
10
+ export const OperationConnectionSchema = z.object({
11
+ id: z.string(),
12
+ mode: ConnectionModeSchema,
13
+ secrets: z.record(z.string(), z.string()),
14
+ scopes: z.array(z.string()).optional(),
15
+ metadata: z.record(z.string(), z.unknown()),
16
+ externalRef: z.string(),
17
+ });
18
+
19
+ export const OperationRequestSchema = z.object({
20
+ requestId: z.string(),
21
+ input: z.record(z.string(), z.unknown()),
22
+ connection: OperationConnectionSchema.optional(),
23
+ headers: z.record(z.string(), z.string()).optional(),
24
+ trace: z.record(z.string(), z.string()).optional(),
25
+ });
26
+
27
+ export const ErrorEnvelopeSchema = z.object({
28
+ code: z.string(),
29
+ message: z.string(),
30
+ requestId: z.string().optional(),
31
+ fix: z.string().optional(),
32
+ details: z.unknown().optional(),
33
+ });
34
+
35
+ export const OperationSuccessResponseSchema = z.object({
36
+ data: z.unknown(),
37
+ });
38
+
39
+ export const OperationErrorResponseSchema = z.object({
40
+ error: ErrorEnvelopeSchema,
41
+ });
42
+
43
+ export const AuthFlowRequestSchema = z.object({
44
+ requestId: z.string(),
45
+ flowId: z.string(),
46
+ connectionId: z.string().optional(),
47
+ externalRef: z.string().optional(),
48
+ tenantId: z.string().optional(),
49
+ providerId: z.string().optional(),
50
+ input: z.record(z.string(), z.unknown()).optional(),
51
+ context: z.record(z.string(), z.unknown()).optional(),
52
+ });
53
+
54
+ export const AuthFlowSuccessResponseSchema = z.object({
55
+ data: z.unknown(),
56
+ contextPatch: z.record(z.string(), z.unknown().nullable()).optional(),
57
+ });
58
+
59
+ export const AuthFlowErrorResponseSchema = OperationErrorResponseSchema;
60
+
61
+ export type ConnectionMode = z.infer<typeof ConnectionModeSchema>;
62
+ export type OperationConnection = z.infer<typeof OperationConnectionSchema>;
63
+ export type OperationRequest = z.infer<typeof OperationRequestSchema>;
64
+ export type OperationSuccessResponse = z.infer<
65
+ typeof OperationSuccessResponseSchema
66
+ >;
67
+ export type OperationErrorResponse = z.infer<
68
+ typeof OperationErrorResponseSchema
69
+ >;
70
+ export type OperationResponse =
71
+ | OperationSuccessResponse
72
+ | OperationErrorResponse;
73
+ export type AuthFlowRequest = z.infer<typeof AuthFlowRequestSchema>;
74
+ export type AuthFlowSuccessResponse = z.infer<
75
+ typeof AuthFlowSuccessResponseSchema
76
+ >;
77
+ export type AuthFlowErrorResponse = z.infer<typeof AuthFlowErrorResponseSchema>;
78
+ export type AuthFlowResponse = AuthFlowSuccessResponse | AuthFlowErrorResponse;