History

ralph

Rhys Sullivan committed 7 months ago

Commit 01ee9a61 parent 263c9a378 files · +13644 −179Browse files

Showing the changes to plugins/openapi (1 of 78 files). Show all

Unified · Split

plugins/openapi/sdk/index.ts+143−92
@@ -9,9 +9,12 @@ import { · 8 unmodified lines
9import type { Source } from "@executor/platform-sdk/schema";9import type { Source } from "@executor/platform-sdk/schema";
10import type {10import type {
11 ExecutorSdkPlugin,11 ExecutorSdkPlugin,
12 ExecutorSdkPluginHost,
13 ExecutorSourceConnector,
12 SourcePluginRuntime,14 SourcePluginRuntime,
13} from "@executor/platform-sdk/plugins";15} from "@executor/platform-sdk/plugins";
14import {16import {
17 OpenApiConnectionAuthSchema,
15 deriveOpenApiNamespace,18 deriveOpenApiNamespace,
16 previewOpenApiDocument,19 previewOpenApiDocument,
17 type OpenApiConnectInput,20 type OpenApiConnectInput,
@@ -90,6 +93,16 @@ export type OpenApiSdkPluginOptions = { · 72 unmodified lines
90 secrets?: OpenApiSecrets;93 secrets?: OpenApiSecrets;
91};94};
92 95
96const OpenApiExecutorAddInputSchema = Schema.Struct({
97 kind: Schema.Literal("openapi"),
98 name: Schema.String,
99 specUrl: Schema.String,
100 baseUrl: Schema.NullOr(Schema.String),
101 auth: OpenApiConnectionAuthSchema,
102});
103
104type OpenApiExecutorAddInput = typeof OpenApiExecutorAddInputSchema.Type;
105
93const createStoredSourceData = (106const createStoredSourceData = (
94 input: OpenApiConnectInput,107 input: OpenApiConnectInput,
95): OpenApiStoredSourceData => ({108): OpenApiStoredSourceData => ({
@@ -249,6 +262,117 @@ const responseHeadersRecord = (response: Response): Record<string, string> => { · 153 unmodified lines
249 return headers;262 return headers;
250};263};
251 264
265const createOpenApiSourceSdk = (
266 options: OpenApiSdkPluginOptions,
267 host: ExecutorSdkPluginHost,
268) => ({
269 getSourceConfig: (sourceId: Source["id"]) =>
270 Effect.gen(function* () {
271 const source = yield* host.sources.get(sourceId);
272 if (source.kind !== "openapi") {
273 return yield* Effect.fail(
274 new Error(`Source ${sourceId} is not an OpenAPI source.`),
275 );
276 }
277
278 const stored = yield* options.storage.get({
279 scopeId: source.scopeId,
280 sourceId: source.id,
281 });
282 if (stored === null) {
283 return yield* Effect.fail(
284 new Error(`OpenAPI source storage missing for ${source.id}`),
285 );
286 }
287
288 return configFromStoredSourceData(source, stored);
289 }),
290 createSource: (input: OpenApiConnectInput) =>
291 Effect.gen(function* () {
292 const stored = createStoredSourceData(input);
293 const createdSource = yield* host.sources.create({
294 source: {
295 name: input.name.trim(),
296 kind: "openapi",
297 status: "connected",
298 enabled: true,
299 namespace: deriveOpenApiNamespace({
300 specUrl: input.specUrl,
301 title: input.name,
302 }),
303 },
304 });
305
306 yield* options.storage.put({
307 scopeId: createdSource.scopeId,
308 sourceId: createdSource.id,
309 value: stored,
310 });
311
312 return yield* host.sources.refreshCatalog(createdSource.id);
313 }),
314 updateSource: (input: OpenApiUpdateSourceInput) =>
315 Effect.gen(function* () {
316 const source = yield* host.sources.get(input.sourceId as Source["id"]);
317 if (source.kind !== "openapi") {
318 return yield* Effect.fail(
319 new Error(`Source ${input.sourceId} is not an OpenAPI source.`),
320 );
321 }
322
323 const nextStored = createStoredSourceData(input.config);
324 const savedSource = yield* host.sources.save({
325 ...source,
326 name: input.config.name.trim(),
327 namespace: deriveOpenApiNamespace({
328 specUrl: input.config.specUrl,
329 title: input.config.name,
330 }),
331 });
332
333 yield* options.storage.put({
334 scopeId: savedSource.scopeId,
335 sourceId: savedSource.id,
336 value: nextStored,
337 });
338
339 return yield* host.sources.refreshCatalog(savedSource.id);
340 }),
341 removeSource: (sourceId: Source["id"]) =>
342 Effect.gen(function* () {
343 const source = yield* host.sources.get(sourceId);
344 if (source.kind !== "openapi") {
345 return yield* Effect.fail(
346 new Error(`Source ${sourceId} is not an OpenAPI source.`),
347 );
348 }
349
350 if (options.storage.remove) {
351 yield* options.storage.remove({
352 scopeId: source.scopeId,
353 sourceId: source.id,
354 });
355 }
356
357 return yield* host.sources.remove(source.id);
358 }),
359});
360
361const openApiSourceConnector = (
362 options: OpenApiSdkPluginOptions,
363): ExecutorSourceConnector<OpenApiExecutorAddInput> => ({
364 kind: "openapi",
365 displayName: "OpenAPI",
366 inputSchema: OpenApiExecutorAddInputSchema,
367 inputSignatureWidth: 280,
368 helpText: [
369 "Provide the OpenAPI document URL and optional base URL override.",
370 "Use `auth.kind = \"bearer\"` with a stored secret ref when required.",
371 ],
372 createSource: ({ args, host }) =>
373 createOpenApiSourceSdk(options, host).createSource(args),
374});
375
252const decodeResponseBody = async (response: Response): Promise<unknown> => {376const decodeResponseBody = async (response: Response): Promise<unknown> => {
253 if (response.status === 204) {377 if (response.status === 204) {
254 return null;378 return null;
@@ -541,102 +665,29 @@ export const openApiSdkPlugin = ( · 286 unmodified lines
541): ExecutorSdkPlugin<"openapi", OpenApiSdk> => ({665): ExecutorSdkPlugin<"openapi", OpenApiSdk> => ({
542 key: "openapi",666 key: "openapi",
543 sources: [createOpenApiSourceRuntime(options)],667 sources: [createOpenApiSourceRuntime(options)],
544 extendExecutor: ({ host }) => ({668 sourceConnectors: [openApiSourceConnector(options)],
669 extendExecutor: ({ host, executor }) => {
670 const sourceSdk = createOpenApiSourceSdk(options, host);
671 const provideRuntime = <A>(
672 effect: Effect.Effect<A, Error, any>,
673 ): Effect.Effect<A, Error, never> =>
674 effect.pipe(Effect.provide(executor.runtime.managedRuntime));
675
676 return {
545 previewDocument: (input) =>677 previewDocument: (input) =>
546 Effect.tryPromise({678 Effect.tryPromise({
547 try: () => previewOpenApiDocument(input),679 try: () => previewOpenApiDocument(input),
548 catch: (cause) =>680 catch: (cause) =>
549 cause instanceof Error ? cause : new Error(String(cause)),681 cause instanceof Error ? cause : new Error(String(cause)),
550 }),682 }),
551 getSourceConfig: (sourceId) =>683 getSourceConfig: (sourceId) =>
552 Effect.gen(function* () {684 provideRuntime(sourceSdk.getSourceConfig(sourceId)),
553 const source = yield* host.sources.get(sourceId);685 createSource: (input) =>
554 if (source.kind !== "openapi") {686 provideRuntime(sourceSdk.createSource(input)),
555 return yield* Effect.fail(687 updateSource: (input) =>
556 new Error(`Source ${sourceId} is not an OpenAPI source.`),688 provideRuntime(sourceSdk.updateSource(input)),
557 );689 removeSource: (sourceId) =>
558 }690 provideRuntime(sourceSdk.removeSource(sourceId)),
559 691 };
560 const stored = yield* options.storage.get({692 },
561 scopeId: source.scopeId,
562 sourceId: source.id,
563 });
564 if (stored === null) {
565 return yield* Effect.fail(
566 new Error(`OpenAPI source storage missing for ${source.id}`),
567 );
568 }
569
570 return configFromStoredSourceData(source, stored);
571 }),
572 createSource: (input) =>
573 Effect.gen(function* () {
574 const stored = createStoredSourceData(input);
575 const createdSource = yield* host.sources.create({
576 source: {
577 name: input.name.trim(),
578 kind: "openapi",
579 status: "connected",
580 enabled: true,
581 namespace: deriveOpenApiNamespace({
582 specUrl: input.specUrl,
583 title: input.name,
584 }),
585 },
586 });
587
588 yield* options.storage.put({
589 scopeId: createdSource.scopeId,
590 sourceId: createdSource.id,
591 value: stored,
592 });
593
594 return yield* host.sources.refreshCatalog(createdSource.id);
595 }),
596 updateSource: (input) =>
597 Effect.gen(function* () {
598 const source = yield* host.sources.get(input.sourceId as Source["id"]);
599 if (source.kind !== "openapi") {
600 return yield* Effect.fail(
601 new Error(`Source ${input.sourceId} is not an OpenAPI source.`),
602 );
603 }
604
605 const nextStored = createStoredSourceData(input.config);
606 const savedSource = yield* host.sources.save({
607 ...source,
608 name: input.config.name.trim(),
609 namespace: deriveOpenApiNamespace({
610 specUrl: input.config.specUrl,
611 title: input.config.name,
612 }),
613 });
614
615 yield* options.storage.put({
616 scopeId: savedSource.scopeId,
617 sourceId: savedSource.id,
618 value: nextStored,
619 });
620
621 return yield* host.sources.refreshCatalog(savedSource.id);
622 }),
623 removeSource: (sourceId) =>
624 Effect.gen(function* () {
625 const source = yield* host.sources.get(sourceId);
626 if (source.kind !== "openapi") {
627 return yield* Effect.fail(
628 new Error(`Source ${sourceId} is not an OpenAPI source.`),
629 );
630 }
631
632 if (options.storage.remove) {
633 yield* options.storage.remove({
634 scopeId: source.scopeId,
635 sourceId: source.id,
636 });
637 }
638
639 return yield* host.sources.remove(source.id);
640 }),
641 }),
642});693});

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t