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

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 (79) hide show
  1. package/AUTHORING.md +93 -0
  2. package/CHANGELOG.md +21 -0
  3. package/README.md +133 -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 +87 -0
  8. package/bin/apifuse-pack-smoke.ts +122 -0
  9. package/bin/apifuse-perf.ts +33 -32
  10. package/bin/apifuse-record.ts +17 -7
  11. package/bin/apifuse-test.ts +6 -4
  12. package/bin/apifuse.ts +36 -35
  13. package/package.json +29 -9
  14. package/src/ceremonies/index.ts +768 -0
  15. package/src/cli/commands.ts +87 -0
  16. package/src/cli/create.ts +845 -0
  17. package/src/cli/templates/provider/Dockerfile.tpl +7 -0
  18. package/src/cli/templates/provider/README.md.tpl +41 -0
  19. package/src/cli/templates/provider/dev.ts.tpl +5 -0
  20. package/src/cli/templates/provider/index.test.ts.tpl +13 -0
  21. package/src/cli/templates/provider/index.ts.tpl +58 -0
  22. package/src/cli/templates/provider/start.ts.tpl +5 -0
  23. package/src/config/loader.ts +61 -1
  24. package/src/define.ts +565 -41
  25. package/src/dev.ts +2 -6
  26. package/src/errors.ts +42 -0
  27. package/src/index.ts +44 -38
  28. package/src/lint.ts +574 -0
  29. package/src/provider.ts +13 -0
  30. package/src/runtime/auth-flow.ts +67 -0
  31. package/src/runtime/credential.ts +95 -0
  32. package/src/runtime/env.ts +13 -0
  33. package/src/runtime/executor.ts +13 -14
  34. package/src/runtime/http.ts +36 -12
  35. package/src/runtime/insights.ts +3 -3
  36. package/src/runtime/key-derivation.ts +122 -0
  37. package/src/runtime/keyring.ts +148 -0
  38. package/src/runtime/namespace.ts +33 -0
  39. package/src/runtime/prevalidate.ts +252 -0
  40. package/src/runtime/tls.ts +41 -17
  41. package/src/runtime/waterfall.ts +0 -1
  42. package/src/schema.ts +77 -0
  43. package/src/serve.ts +1 -664
  44. package/src/server/index.ts +22 -0
  45. package/src/server/serve.ts +624 -0
  46. package/src/server/types.ts +78 -0
  47. package/src/stealth/profiles.ts +10 -93
  48. package/src/testing/run.ts +391 -32
  49. package/src/types.ts +390 -41
  50. package/bin/apifuse-init.ts +0 -387
  51. package/src/__tests__/auth.test.ts +0 -396
  52. package/src/__tests__/browser-auth.test.ts +0 -180
  53. package/src/__tests__/browser.test.ts +0 -632
  54. package/src/__tests__/define.test.ts +0 -225
  55. package/src/__tests__/errors.test.ts +0 -69
  56. package/src/__tests__/executor.test.ts +0 -214
  57. package/src/__tests__/http.test.ts +0 -238
  58. package/src/__tests__/insights.test.ts +0 -210
  59. package/src/__tests__/instrumentation.test.ts +0 -290
  60. package/src/__tests__/otlp.test.ts +0 -141
  61. package/src/__tests__/perf.test.ts +0 -60
  62. package/src/__tests__/providers-yaml.test.ts +0 -135
  63. package/src/__tests__/proxy.test.ts +0 -359
  64. package/src/__tests__/recipes.test.ts +0 -36
  65. package/src/__tests__/serve.test.ts +0 -233
  66. package/src/__tests__/session.test.ts +0 -231
  67. package/src/__tests__/state.test.ts +0 -100
  68. package/src/__tests__/stealth.test.ts +0 -57
  69. package/src/__tests__/testing.test.ts +0 -97
  70. package/src/__tests__/tls.test.ts +0 -345
  71. package/src/__tests__/types.test.ts +0 -142
  72. package/src/__tests__/utils.test.ts +0 -62
  73. package/src/__tests__/waterfall.test.ts +0 -270
  74. package/src/config/providers-yaml.ts +0 -370
  75. package/src/index.test.ts +0 -1
  76. package/src/protocol.ts +0 -183
  77. package/src/runtime/auth.ts +0 -245
  78. package/src/runtime/session.ts +0 -573
  79. package/src/runtime/state.ts +0 -124
@@ -0,0 +1,624 @@
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: publicProviderErrorMessage(error),
219
+ ...(requestId ? { requestId } : {}),
220
+ ...(error instanceof TransportError && error.status
221
+ ? { details: { upstreamStatus: error.status } }
222
+ : {}),
223
+ },
224
+ };
225
+ }
226
+
227
+ if (error instanceof z.ZodError) {
228
+ return {
229
+ error: {
230
+ code: "invalid_request",
231
+ message: "Invalid request body",
232
+ ...(requestId ? { requestId } : {}),
233
+ details: zodDetails(error),
234
+ },
235
+ };
236
+ }
237
+
238
+ return {
239
+ error: {
240
+ code: "internal_error",
241
+ message: "Internal error",
242
+ ...(requestId ? { requestId } : {}),
243
+ },
244
+ };
245
+ }
246
+
247
+ function publicProviderErrorMessage(error: ProviderError): string {
248
+ if (error instanceof TransportError) {
249
+ if (error.code === "transport_timeout") return "Request timed out";
250
+ if (error.code === "transport_network_error") return "Network error";
251
+ if (error.code === "upstream_http_error" && error.status) {
252
+ return `Upstream request failed with status ${error.status}`;
253
+ }
254
+ if (error.status) {
255
+ return `Upstream request failed with status ${error.status}`;
256
+ }
257
+ return "Upstream request failed";
258
+ }
259
+ return error.message;
260
+ }
261
+
262
+ function toStatusCode(error: unknown): 400 | 404 | 500 | 502 | 504 {
263
+ if (error instanceof z.ZodError) {
264
+ return 400;
265
+ }
266
+
267
+ if (error instanceof TransportError) {
268
+ return error.code === "transport_timeout" ? 504 : 502;
269
+ }
270
+
271
+ if (error instanceof ProviderError) {
272
+ if (error.code === "NOT_FOUND" || error.code === "NO_DATA") {
273
+ return 404;
274
+ }
275
+
276
+ return 400;
277
+ }
278
+
279
+ return 500;
280
+ }
281
+
282
+ function extractRequestId(raw: unknown): string | undefined {
283
+ if (!raw || typeof raw !== "object") {
284
+ return undefined;
285
+ }
286
+
287
+ const value = Object.getOwnPropertyDescriptor(raw, "requestId")?.value;
288
+ return typeof value === "string" ? value : undefined;
289
+ }
290
+
291
+ function logProviderError(
292
+ logger: ProviderServerLogger | unknown,
293
+ provider: ProviderDefinition,
294
+ kind: "operation" | "auth",
295
+ route: string,
296
+ requestId: string | undefined,
297
+ error: unknown,
298
+ status: number,
299
+ ): void {
300
+ const code =
301
+ error instanceof ProviderError
302
+ ? (error.code ?? "provider_error")
303
+ : error instanceof z.ZodError
304
+ ? "invalid_request"
305
+ : "internal_error";
306
+ const errorClass = error instanceof Error ? error.name : typeof error;
307
+ const message = error instanceof Error ? error.message : String(error);
308
+ const emit =
309
+ typeof logger === "function" ? logger : defaultProviderServerLogger;
310
+ emit({
311
+ level: status >= 500 ? "error" : "warn",
312
+ event: "provider_request_failed",
313
+ providerId: provider.id,
314
+ kind,
315
+ route,
316
+ ...(requestId ? { requestId } : {}),
317
+ status,
318
+ code,
319
+ errorClass,
320
+ message,
321
+ ...(error instanceof TransportError && error.status
322
+ ? { upstreamStatus: error.status }
323
+ : {}),
324
+ ...(error instanceof z.ZodError ? { issues: zodDetails(error) } : {}),
325
+ });
326
+ }
327
+
328
+ function toJsonSuccessResponse(
329
+ result: unknown,
330
+ ): Response | OperationSuccessResponse {
331
+ if (result instanceof Response) {
332
+ return result;
333
+ }
334
+
335
+ if (result instanceof ReadableStream) {
336
+ return new Response(result);
337
+ }
338
+
339
+ return { data: result };
340
+ }
341
+
342
+ function toAuthFlowResponse(
343
+ result: unknown,
344
+ contextPatch: Record<string, unknown | null> | undefined,
345
+ ): Response | AuthFlowSuccessResponse {
346
+ if (result instanceof Response) {
347
+ return result;
348
+ }
349
+
350
+ if (result instanceof ReadableStream) {
351
+ return new Response(result);
352
+ }
353
+
354
+ return {
355
+ data: result,
356
+ ...(contextPatch ? { contextPatch } : {}),
357
+ };
358
+ }
359
+
360
+ async function handleOperation(
361
+ provider: ProviderDefinition,
362
+ request: OperationRequest,
363
+ operationId: string,
364
+ ): Promise<Response | OperationResponse> {
365
+ const ctx = createProviderContext(provider, request);
366
+ const result = await executeOperation(
367
+ provider,
368
+ operationId,
369
+ ctx,
370
+ request.input,
371
+ );
372
+ return toJsonSuccessResponse(result);
373
+ }
374
+
375
+ type AuthRoute = "start" | "continue" | "poll" | "abort";
376
+
377
+ async function handleAuthFlow(
378
+ provider: ProviderDefinition,
379
+ request: AuthFlowRequest,
380
+ route: AuthRoute,
381
+ ): Promise<Response | AuthFlowResponse> {
382
+ const flow = provider.auth?.flow;
383
+ if (!flow) {
384
+ throw new ProviderError("Auth flow is not configured", {
385
+ code: "AUTH_FLOW_NOT_CONFIGURED",
386
+ });
387
+ }
388
+
389
+ const { context, getPatch } = createAuthFlowContext(provider, request);
390
+
391
+ const result =
392
+ route === "start"
393
+ ? await flow.start(context)
394
+ : route === "continue"
395
+ ? await flow.continue(context, request.input ?? {})
396
+ : route === "poll"
397
+ ? flow.poll
398
+ ? await flow.poll(context)
399
+ : null
400
+ : flow.abort
401
+ ? await flow.abort(context)
402
+ : null;
403
+
404
+ return toAuthFlowResponse(result, getPatch());
405
+ }
406
+
407
+ export function createServerApp(
408
+ provider: ProviderDefinition,
409
+ options: ProviderServerOptions = {},
410
+ ): Hono {
411
+ const app = new Hono();
412
+ const logger = options.logger ?? defaultProviderServerLogger;
413
+
414
+ app.notFound((c) =>
415
+ c.json(
416
+ {
417
+ error: {
418
+ code: "not_found",
419
+ message: "Not found",
420
+ },
421
+ },
422
+ 404,
423
+ ),
424
+ );
425
+
426
+ app.get("/health", (c) =>
427
+ c.json({
428
+ status: "ok",
429
+ provider: provider.id,
430
+ version: provider.version,
431
+ }),
432
+ );
433
+
434
+ app.post("/v1/:operation", async (c) => {
435
+ let rawBody: unknown;
436
+ const operation = c.req.param("operation");
437
+ try {
438
+ rawBody = await c.req.raw
439
+ .clone()
440
+ .json()
441
+ .catch(() => undefined);
442
+ const body = OperationRequestSchema.parse(rawBody);
443
+ const requestHeaders = Object.fromEntries(c.req.raw.headers.entries());
444
+ body.headers = { ...requestHeaders, ...body.headers };
445
+ const response = await handleOperation(provider, body, operation);
446
+ return response instanceof Response ? response : c.json(response);
447
+ } catch (error) {
448
+ const status = toStatusCode(error);
449
+ const requestId = extractRequestId(rawBody);
450
+ logProviderError(
451
+ logger,
452
+ provider,
453
+ "operation",
454
+ operation,
455
+ requestId,
456
+ error,
457
+ status,
458
+ );
459
+ return c.json(toErrorResponse(error, requestId), status);
460
+ }
461
+ });
462
+
463
+ app.post("/auth/start", async (c) => {
464
+ let rawBody: unknown;
465
+ try {
466
+ rawBody = await c.req.raw
467
+ .clone()
468
+ .json()
469
+ .catch(() => undefined);
470
+ const body = AuthFlowRequestSchema.parse(rawBody);
471
+ const response = await handleAuthFlow(provider, body, "start");
472
+ return response instanceof Response ? response : c.json(response);
473
+ } catch (error) {
474
+ const status = toStatusCode(error);
475
+ const requestId = extractRequestId(rawBody);
476
+ logProviderError(
477
+ logger,
478
+ provider,
479
+ "auth",
480
+ "start",
481
+ requestId,
482
+ error,
483
+ status,
484
+ );
485
+ return c.json(toErrorResponse(error, requestId), status);
486
+ }
487
+ });
488
+
489
+ app.post("/auth/continue", async (c) => {
490
+ let rawBody: unknown;
491
+ try {
492
+ rawBody = await c.req.raw
493
+ .clone()
494
+ .json()
495
+ .catch(() => undefined);
496
+ const body = AuthFlowRequestSchema.parse(rawBody);
497
+ const response = await handleAuthFlow(provider, body, "continue");
498
+ return response instanceof Response ? response : c.json(response);
499
+ } catch (error) {
500
+ const status = toStatusCode(error);
501
+ const requestId = extractRequestId(rawBody);
502
+ logProviderError(
503
+ logger,
504
+ provider,
505
+ "auth",
506
+ "continue",
507
+ requestId,
508
+ error,
509
+ status,
510
+ );
511
+ return c.json(toErrorResponse(error, requestId), status);
512
+ }
513
+ });
514
+
515
+ app.post("/auth/poll", async (c) => {
516
+ let rawBody: unknown;
517
+ try {
518
+ rawBody = await c.req.raw
519
+ .clone()
520
+ .json()
521
+ .catch(() => undefined);
522
+ const body = AuthFlowRequestSchema.parse(rawBody);
523
+ const response = await handleAuthFlow(provider, body, "poll");
524
+ return response instanceof Response ? response : c.json(response);
525
+ } catch (error) {
526
+ const status = toStatusCode(error);
527
+ const requestId = extractRequestId(rawBody);
528
+ logProviderError(
529
+ logger,
530
+ provider,
531
+ "auth",
532
+ "poll",
533
+ requestId,
534
+ error,
535
+ status,
536
+ );
537
+ return c.json(toErrorResponse(error, requestId), status);
538
+ }
539
+ });
540
+
541
+ app.post("/auth/disconnect", async (c) => {
542
+ let rawBody: unknown;
543
+ try {
544
+ rawBody = await c.req.raw
545
+ .clone()
546
+ .json()
547
+ .catch(() => undefined);
548
+ const body = AuthFlowRequestSchema.parse(rawBody);
549
+ const response = await handleAuthFlow(provider, body, "abort");
550
+ return response instanceof Response ? response : c.json(response);
551
+ } catch (error) {
552
+ const status = toStatusCode(error);
553
+ const requestId = extractRequestId(rawBody);
554
+ logProviderError(
555
+ logger,
556
+ provider,
557
+ "auth",
558
+ "disconnect",
559
+ requestId,
560
+ error,
561
+ status,
562
+ );
563
+ return c.json(toErrorResponse(error, requestId), status);
564
+ }
565
+ });
566
+
567
+ return app;
568
+ }
569
+
570
+ type BunServeRuntime = {
571
+ serve: (options: {
572
+ port: number;
573
+ hostname: string;
574
+ fetch: (request: Request) => Response | Promise<Response>;
575
+ }) => unknown;
576
+ };
577
+
578
+ function getBunServeRuntime(): BunServeRuntime | undefined {
579
+ const bunValue = Object.getOwnPropertyDescriptor(globalThis, "Bun")?.value;
580
+ if (!bunValue || typeof bunValue !== "object") {
581
+ return undefined;
582
+ }
583
+
584
+ const serve = Object.getOwnPropertyDescriptor(bunValue, "serve")?.value;
585
+ if (typeof serve !== "function") {
586
+ return undefined;
587
+ }
588
+
589
+ return {
590
+ serve(options) {
591
+ return serve(options);
592
+ },
593
+ };
594
+ }
595
+
596
+ export interface ServeOptions extends ProviderServerOptions {
597
+ host?: string;
598
+ port?: number;
599
+ }
600
+
601
+ export async function serve(
602
+ provider: ProviderDefinition,
603
+ options: ServeOptions = {},
604
+ ): Promise<void> {
605
+ const bunRuntime = getBunServeRuntime();
606
+
607
+ if (bunRuntime === undefined) {
608
+ throw new ProviderError(
609
+ "Bun runtime is required to start the provider server",
610
+ {
611
+ code: "RUNTIME_UNSUPPORTED",
612
+ },
613
+ );
614
+ }
615
+
616
+ const app = createServerApp(provider, { logger: options.logger });
617
+
618
+ bunRuntime.serve({
619
+ port: options.port ?? DEFAULT_PORT,
620
+ hostname: options.host ?? DEFAULT_HOST,
621
+ fetch: app.fetch,
622
+ });
623
+ await Promise.resolve();
624
+ }
@@ -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;