Unified · Split
| @@ -37,10 +37,7 @@ interface CloudPluginDeps { · 36 unmodified lines | |||
| 37 | 37 | ||
| 38 | export default defineExecutorConfig({ | 38 | export default defineExecutorConfig({ |
| 39 | dialect: "pg", | 39 | dialect: "pg", |
| 40 | plugins: ({ | 40 | plugins: ({ workosCredentials, workosVaultClient }: CloudPluginDeps = {}) => |
| 41 | workosCredentials, | ||
| 42 | workosVaultClient, | ||
| 43 | }: CloudPluginDeps = {}) => | ||
| 44 | [ | 41 | [ |
| 45 | openApiPlugin(), | 42 | openApiPlugin(), |
| 46 | mcpPlugin({ | 43 | mcpPlugin({ |
| @@ -26,12 +26,7 @@ import { · 25 unmodified lines | |||
| 26 | } from "@executor-js/api/server"; | 26 | } from "@executor-js/api/server"; |
| 27 | import { createExecutionEngine } from "@executor-js/execution"; | 27 | import { createExecutionEngine } from "@executor-js/execution"; |
| 28 | import { makeQuickJsExecutor } from "@executor-js/runtime-quickjs"; | 28 | import { makeQuickJsExecutor } from "@executor-js/runtime-quickjs"; |
| 29 | import { | 29 | import { Scope, ScopeId, collectSchemas, createExecutor } from "@executor-js/sdk"; |
| 30 | Scope, | ||
| 31 | ScopeId, | ||
| 32 | collectSchemas, | ||
| 33 | createExecutor, | ||
| 34 | } from "@executor-js/sdk"; | ||
| 35 | import { makePostgresAdapter, makePostgresBlobStore } from "@executor-js/storage-postgres"; | 30 | import { makePostgresAdapter, makePostgresBlobStore } from "@executor-js/storage-postgres"; |
| 36 | import { makeTestWorkOSVaultClient } from "@executor-js/plugin-workos-vault/testing"; | 31 | import { makeTestWorkOSVaultClient } from "@executor-js/plugin-workos-vault/testing"; |
| 37 | 32 | ||
| @@ -64,7 +64,9 @@ export const createScopedExecutor = ( · 63 unmodified lines | |||
| 64 | const { db } = yield* DbService; | 64 | const { db } = yield* DbService; |
| 65 | 65 | ||
| 66 | const plugins = orgPlugins(); | 66 | const plugins = orgPlugins(); |
| 67 | const httpClientLayer = makeHostedHttpClientLayer(); | 67 | const httpClientLayer = makeHostedHttpClientLayer({ |
| 68 | allowLocalNetwork: env.NODE_ENV === "test", | ||
| 69 | }); | ||
| 68 | const schema = collectSchemas(plugins); | 70 | const schema = collectSchemas(plugins); |
| 69 | const adapter = makePostgresAdapter({ db, schema }); | 71 | const adapter = makePostgresAdapter({ db, schema }); |
| 70 | const blobs = makePostgresBlobStore({ db }); | 72 | const blobs = makePostgresBlobStore({ db }); |
| @@ -336,9 +336,9 @@ describe("tenant isolation (HTTP)", () => { · 335 unmodified lines | |||
| 336 | client.connections.usages({ | 336 | client.connections.usages({ |
| 337 | params: { scopeId: ScopeId.make(orgB), connectionId: connectionIdA }, | 337 | params: { scopeId: ScopeId.make(orgB), connectionId: connectionIdA }, |
| 338 | }), | 338 | }), |
| 339 | ).pipe(Effect.result); | 339 | ); |
| 340 | 340 | ||
| 341 | if (Result.isSuccess(usages)) expect(usages.success).toEqual([]); | 341 | expect(usages).toEqual([]); |
| 342 | }), | 342 | }), |
| 343 | ); | 343 | ); |
| 344 | 344 | ||
| @@ -2458,7 +2458,7 @@ export const createExecutor = <const TPlugins extends readonly AnyPlugin[] = []> · 2457 unmodified lines | |||
| 2458 | usagesForConnection: credentialBindingUsagesForConnection, | 2458 | usagesForConnection: credentialBindingUsagesForConnection, |
| 2459 | }; | 2459 | }; |
| 2460 | 2460 | ||
| 2461 | const oauthBundle = makeOAuth2Service({ | 2461 | const oauthBundle = makeOAuth2Service({ |
| 2462 | adapter: core, | 2462 | adapter: core, |
| 2463 | rawAdapter: adapter, | 2463 | rawAdapter: adapter, |
| 2464 | secretsGet: (id) => | 2464 | secretsGet: (id) => |
| @@ -26,11 +26,8 @@ describe("hosted outbound HTTP client", () => { · 25 unmodified lines | |||
| 26 | "http://192.168.1.10/mcp", | 26 | "http://192.168.1.10/mcp", |
| 27 | "http://169.254.169.254/latest/meta-data/", | 27 | "http://169.254.169.254/latest/meta-data/", |
| 28 | ]) { | 28 | ]) { |
| 29 | const result = yield* validateHostedOutboundUrl(url).pipe(Effect.result); | 29 | const error = yield* validateHostedOutboundUrl(url).pipe(Effect.flip); |
| 30 | expect(Result.isFailure(result)).toBe(true); | 30 | expect(error).toBeInstanceOf(HostedOutboundRequestBlocked); |
| 31 | if (Result.isFailure(result)) { | ||
| 32 | expect(result.failure).toBeInstanceOf(HostedOutboundRequestBlocked); | ||
| 33 | } | ||
| 34 | } | 31 | } |
| 35 | }), | 32 | }), |
| 36 | ); | 33 | ); |
| @@ -96,7 +96,7 @@ export const validateHostedOutboundUrl = ( · 95 unmodified lines | |||
| 96 | }); | 96 | }); |
| 97 | 97 | ||
| 98 | const guardFetch = ( | 98 | const guardFetch = ( |
| 99 | fetch: typeof globalThis.fetch, | 99 | underlying: typeof globalThis.fetch, |
| 100 | options: HostedHttpClientOptions, | 100 | options: HostedHttpClientOptions, |
| 101 | ): typeof globalThis.fetch => | 101 | ): typeof globalThis.fetch => |
| 102 | (async (input, init) => { | 102 | (async (input, init) => { |
| @@ -105,7 +105,7 @@ const guardFetch = ( · 2 unmodified lines | |||
| 105 | for (let redirects = 0; redirects <= maxRedirects; redirects++) { | 105 | for (let redirects = 0; redirects <= maxRedirects; redirects++) { |
| 106 | const url = current instanceof Request ? current.url : String(current); | 106 | const url = current instanceof Request ? current.url : String(current); |
| 107 | Effect.runSync(validateHostedOutboundUrl(url, options)); | 107 | Effect.runSync(validateHostedOutboundUrl(url, options)); |
| 108 | const response = await fetch(current, { ...init, redirect: "manual" }); | 108 | const response = await underlying(current, { ...init, redirect: "manual" }); |
| 109 | if ( | 109 | if ( |
| 110 | response.status >= 300 && | 110 | response.status >= 300 && |
| 111 | response.status < 400 && | 111 | response.status < 400 && |
| @@ -117,7 +117,7 @@ const guardFetch = ( · 5 unmodified lines | |||
| 117 | } | 117 | } |
| 118 | return response; | 118 | return response; |
| 119 | } | 119 | } |
| 120 | return fetch(current, { ...init, redirect: "manual" }); | 120 | return underlying(current, { ...init, redirect: "manual" }); |
| 121 | }) as typeof globalThis.fetch; | 121 | }) as typeof globalThis.fetch; |
| 122 | 122 | ||
| 123 | export const makeHostedHttpClientLayer = ( | 123 | export const makeHostedHttpClientLayer = ( |
| @@ -129,7 +129,9 @@ export const makeHostedHttpClientLayer = ( · 5 unmodified lines | |||
| 129 | ? Layer.succeed(FetchHttpClient.Fetch)(guardFetch(options.fetch, options)) | 129 | ? Layer.succeed(FetchHttpClient.Fetch)(guardFetch(options.fetch, options)) |
| 130 | : Layer.effect( | 130 | : Layer.effect( |
| 131 | FetchHttpClient.Fetch, | 131 | FetchHttpClient.Fetch, |
| 132 | Effect.map(Effect.service(FetchHttpClient.Fetch), (fetch) => guardFetch(fetch, options)), | 132 | Effect.map(Effect.service(FetchHttpClient.Fetch), (underlying) => |
| 133 | guardFetch(underlying, options), | ||
| 134 | ), | ||
| 133 | ), | 135 | ), |
| 134 | ), | 136 | ), |
| 135 | ); | 137 | ); |
| @@ -433,7 +433,7 @@ describe("beginDynamicAuthorization", () => { · 432 unmodified lines | |||
| 433 | ), | 433 | ), |
| 434 | ); | 434 | ); |
| 435 | 435 | ||
| 436 | it.effect("requests empty scope when only AS-level scopes_supported is advertised", () => | 436 | it.effect("omits scope when only AS-level scopes_supported is advertised", () => |
| 437 | withOAuthFixture( | 437 | withOAuthFixture( |
| 438 | (request, baseUrl) => { | 438 | (request, baseUrl) => { |
| 439 | if (request.url === "/.well-known/oauth-protected-resource") { | 439 | if (request.url === "/.well-known/oauth-protected-resource") { |
| @@ -475,7 +475,7 @@ describe("beginDynamicAuthorization", () => { · 35 unmodified lines | |||
| 475 | expect(body.scope).toBeUndefined(); | 475 | expect(body.scope).toBeUndefined(); |
| 476 | 476 | ||
| 477 | const authUrl = new URL(result.authorizationUrl); | 477 | const authUrl = new URL(result.authorizationUrl); |
| 478 | expect(authUrl.searchParams.get("scope")).toBe(""); | 478 | expect(authUrl.searchParams.has("scope")).toBe(false); |
| 479 | }), | 479 | }), |
| 480 | ), | 480 | ), |
| 481 | ); | 481 | ); |
| @@ -261,9 +261,9 @@ export const makeOAuth2Service = ( · 260 unmodified lines | |||
| 261 | })(); | 261 | })(); |
| 262 | 262 | ||
| 263 | const authServer = authorizationServerUrl | 263 | const authServer = authorizationServerUrl |
| 264 | ? yield* discoverAuthorizationServerMetadata(authorizationServerUrl, { httpClientLayer }).pipe( | 264 | ? yield* discoverAuthorizationServerMetadata(authorizationServerUrl, { |
| 265 | Effect.catchTag("OAuthDiscoveryError", () => Effect.succeed(null)), | 265 | httpClientLayer, |
| 266 | ) | 266 | }).pipe(Effect.catchTag("OAuthDiscoveryError", () => Effect.succeed(null))) |
| 267 | : null; | 267 | : null; |
| 268 | 268 | ||
| 269 | // Dynamic registration is only viable when the AS advertises a | 269 | // Dynamic registration is only viable when the AS advertises a |
| @@ -16,7 +16,11 @@ · 15 unmodified lines | |||
| 16 | ], | 16 | ], |
| 17 | "type": "module", | 17 | "type": "module", |
| 18 | "exports": { | 18 | "exports": { |
| 19 | ".": "./src/index.ts" | 19 | ".": { |
| 20 | "types": "./src/index.ts", | ||
| 21 | "bun": "./src/index.ts", | ||
| 22 | "default": "./dist/index.js" | ||
| 23 | } | ||
| 20 | }, | 24 | }, |
| 21 | "publishConfig": { | 25 | "publishConfig": { |
| 22 | "access": "public", | 26 | "access": "public", |
| @@ -923,7 +923,11 @@ export const graphqlPlugin = definePlugin((options?: GraphqlPluginOptions) => { · 922 unmodified lines | |||
| 923 | storage: (deps): GraphqlStore => makeDefaultGraphqlStore(deps), | 923 | storage: (deps): GraphqlStore => makeDefaultGraphqlStore(deps), |
| 924 | 924 | ||
| 925 | extension: (ctx) => | 925 | extension: (ctx) => |
| 926 | makeGraphqlExtension(ctx, options?.httpClientLayer ?? ctx.httpClientLayer, options?.configFile), | 926 | makeGraphqlExtension( |
| 927 | ctx, | ||
| 928 | options?.httpClientLayer ?? ctx.httpClientLayer, | ||
| 929 | options?.configFile, | ||
| 930 | ), | ||
| 927 | 931 | ||
| 928 | staticSources: (self) => [ | 932 | staticSources: (self) => [ |
| 929 | { | 933 | { |