History

Move product access rules out of the SDK

Rhys Sullivan committed 1 month ago

Commit c676e561 parent a72e51d161 files · +3935 −867Browse files

Showing the changes to packages/plugins/openapi/src (15 of 161 files). Show all

Unified · Split

15 files
  1. packages/plugins/openapi/src/providers/google/spec-format-adapter.test.ts +4 −0
  2. packages/plugins/openapi/src/sdk/configure.test.ts +25 −8
  3. packages/plugins/openapi/src/sdk/form-urlencoded-body.test.ts +22 −23
  4. packages/plugins/openapi/src/sdk/health-check-redaction.test.ts +2 −0
  5. packages/plugins/openapi/src/sdk/multi-scope-bearer.test.ts +4 −1
  6. packages/plugins/openapi/src/sdk/non-json-body.test.ts +106 −35
  7. packages/plugins/openapi/src/sdk/plugin.test.ts +104 −35
  8. packages/plugins/openapi/src/sdk/real-specs.test.ts +2 −0
  9. packages/plugins/openapi/src/sdk/response-body-timeout.test.ts +4 −1
  10. packages/plugins/openapi/src/sdk/response-headers-timeout.test.ts +4 −1
  11. packages/plugins/openapi/src/sdk/spec-blob.test.ts +15 −6
  12. packages/plugins/openapi/src/sdk/spec-overrides-lifecycle.test.ts +10 −3
  13. packages/plugins/openapi/src/sdk/streaming-response.test.ts +7 −2
  14. packages/plugins/openapi/src/sdk/tool-row-projection.test.ts +4 −1
  15. packages/plugins/openapi/src/sdk/upstream-failures.test.ts +8 −3
packages/plugins/openapi/src/providers/google/spec-format-adapter.test.ts+4−0
@@ -9,6 +9,7 @@ import type { AuthenticationInput } from "@executor-js/plugin-openapi"; · 8 unmodified lines
9 9
10import { deriveGoogleDiscoveryIdentity, googleDiscoveryAdapter } from "./spec-format-adapter";10import { deriveGoogleDiscoveryIdentity, googleDiscoveryAdapter } from "./spec-format-adapter";
11import { googleCatalog } from "./presets";11import { googleCatalog } from "./presets";
12import { testAccess } from "@executor-js/product-access/testing";
12 13
13const TASKS_URL = "https://www.googleapis.com/discovery/v1/apis/tasks/v1/rest";14const TASKS_URL = "https://www.googleapis.com/discovery/v1/apis/tasks/v1/rest";
14const GMAIL_URL = "https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest";15const GMAIL_URL = "https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest";
@@ -179,6 +180,7 @@ it.effect("adds a Google Discovery URL through the OpenAPI plugin with derived i · 164 unmodified lines
179 Effect.gen(function* () {180 Effect.gen(function* () {
180 const executor = yield* createExecutor(181 const executor = yield* createExecutor(
181 makeTestConfig({182 makeTestConfig({
183 access: testAccess.member(),
182 plugins: [184 plugins: [
183 openApiPlugin({185 openApiPlugin({
184 httpClientLayer: discoveryHttpClientLayer,186 httpClientLayer: discoveryHttpClientLayer,
@@ -211,6 +213,7 @@ it.effect( · 26 unmodified lines
211 );213 );
212 const executor = yield* createExecutor(214 const executor = yield* createExecutor(
213 makeTestConfig({215 makeTestConfig({
216 access: testAccess.member(),
214 plugins: [217 plugins: [
215 openApiPlugin({218 openApiPlugin({
216 httpClientLayer: discoveryHttpClientLayer,219 httpClientLayer: discoveryHttpClientLayer,
@@ -257,6 +260,7 @@ it.effect("preserves a Google preset's full consumer consent boundary when refre · 40 unmodified lines
257 );260 );
258 const executor = yield* createExecutor(261 const executor = yield* createExecutor(
259 makeTestConfig({262 makeTestConfig({
263 access: testAccess.member(),
260 plugins: [264 plugins: [
261 openApiPlugin({265 openApiPlugin({
262 httpClientLayer: gmailDiscoveryHttpClientLayer,266 httpClientLayer: gmailDiscoveryHttpClientLayer,
packages/plugins/openapi/src/sdk/configure.test.ts+25−8
@@ -35,6 +35,7 @@ import { · 34 unmodified lines
35 serveOpenApiHttpApiTestServer,35 serveOpenApiHttpApiTestServer,
36 unwrapInvocation,36 unwrapInvocation,
37} from "../testing";37} from "../testing";
38import { testAccess } from "@executor-js/product-access/testing";
38 39
39const testPlugins = (httpClientLayer = FetchHttpClient.layer) =>40const testPlugins = (httpClientLayer = FetchHttpClient.layer) =>
40 [openApiPlugin({ httpClientLayer }), memoryCredentialsPlugin()] as const;41 [openApiPlugin({ httpClientLayer }), memoryCredentialsPlugin()] as const;
@@ -90,7 +91,9 @@ describe("OpenAPI Plugin — configure (custom auth method)", () => { · 49 unmodified lines
90 it.effect("adds a custom apiKey method and getConfig reflects it", () =>91 it.effect("adds a custom apiKey method and getConfig reflects it", () =>
91 Effect.scoped(92 Effect.scoped(
92 Effect.gen(function* () {93 Effect.gen(function* () {
93 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));94 const executor = yield* createExecutor(
95 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
96 );
94 97
95 yield* executor.openapi.addSpec({98 yield* executor.openapi.addSpec({
96 spec: { kind: "blob", value: specText() },99 spec: { kind: "blob", value: specText() },
@@ -119,7 +122,9 @@ describe("OpenAPI Plugin — configure (custom auth method)", () => { · 22 unmodified lines
119 it.effect("appends to an existing spec-derived template without dropping entries", () =>122 it.effect("appends to an existing spec-derived template without dropping entries", () =>
120 Effect.scoped(123 Effect.scoped(
121 Effect.gen(function* () {124 Effect.gen(function* () {
122 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));125 const executor = yield* createExecutor(
126 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
127 );
123 128
124 const seedTemplate: AuthenticationInput = {129 const seedTemplate: AuthenticationInput = {
125 slug: "seed",130 slug: "seed",
@@ -145,7 +150,9 @@ describe("OpenAPI Plugin — configure (custom auth method)", () => { · 19 unmodified lines
145 it.effect("generates a custom_<id> slug for a method submitted without one", () =>150 it.effect("generates a custom_<id> slug for a method submitted without one", () =>
146 Effect.scoped(151 Effect.scoped(
147 Effect.gen(function* () {152 Effect.gen(function* () {
148 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));153 const executor = yield* createExecutor(
154 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
155 );
149 156
150 yield* executor.openapi.addSpec({157 yield* executor.openapi.addSpec({
151 spec: { kind: "blob", value: specText() },158 spec: { kind: "blob", value: specText() },
@@ -167,7 +174,9 @@ describe("OpenAPI Plugin — configure (custom auth method)", () => { · 15 unmodified lines
167 it.effect("dedupes: a matching slug replaces in place; two slugless get distinct slugs", () =>174 it.effect("dedupes: a matching slug replaces in place; two slugless get distinct slugs", () =>
168 Effect.scoped(175 Effect.scoped(
169 Effect.gen(function* () {176 Effect.gen(function* () {
170 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));177 const executor = yield* createExecutor(
178 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
179 );
171 180
172 yield* executor.openapi.addSpec({181 yield* executor.openapi.addSpec({
173 spec: { kind: "blob", value: specText() },182 spec: { kind: "blob", value: specText() },
@@ -208,7 +217,9 @@ describe("OpenAPI Plugin — configure (custom auth method)", () => { · 34 unmodified lines
208 it.effect("replace mode overwrites the auth template array", () =>217 it.effect("replace mode overwrites the auth template array", () =>
209 Effect.scoped(218 Effect.scoped(
210 Effect.gen(function* () {219 Effect.gen(function* () {
211 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));220 const executor = yield* createExecutor(
221 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
222 );
212 223
213 const seedTemplate: AuthenticationInput = {224 const seedTemplate: AuthenticationInput = {
214 slug: "seed",225 slug: "seed",
@@ -236,7 +247,9 @@ describe("OpenAPI Plugin — configure (custom auth method)", () => { · 21 unmodified lines
236 Effect.scoped(247 Effect.scoped(
237 Effect.gen(function* () {248 Effect.gen(function* () {
238 const server = yield* servePluginTestApi();249 const server = yield* servePluginTestApi();
239 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));250 const executor = yield* createExecutor(
251 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
252 );
240 253
241 yield* executor.openapi.addSpec({254 yield* executor.openapi.addSpec({
242 spec: { kind: "blob", value: server.specJson },255 spec: { kind: "blob", value: server.specJson },
@@ -272,7 +285,9 @@ describe("OpenAPI Plugin — configure (custom auth method)", () => { · 29 unmodified lines
272 Effect.scoped(285 Effect.scoped(
273 Effect.gen(function* () {286 Effect.gen(function* () {
274 const server = yield* servePluginTestApi();287 const server = yield* servePluginTestApi();
275 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));288 const executor = yield* createExecutor(
289 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
290 );
276 291
277 yield* executor.openapi.addSpec({292 yield* executor.openapi.addSpec({
278 spec: { kind: "blob", value: server.specJson },293 spec: { kind: "blob", value: server.specJson },
@@ -320,7 +335,9 @@ describe("OpenAPI Plugin — configure (custom auth method)", () => { · 41 unmodified lines
320 it.effect("getConfig returns null for an unknown integration", () =>335 it.effect("getConfig returns null for an unknown integration", () =>
321 Effect.scoped(336 Effect.scoped(
322 Effect.gen(function* () {337 Effect.gen(function* () {
323 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));338 const executor = yield* createExecutor(
339 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
340 );
324 expect(yield* executor.openapi.getConfig("nope")).toBeNull();341 expect(yield* executor.openapi.getConfig("nope")).toBeNull();
325 }),342 }),
326 ),343 ),
packages/plugins/openapi/src/sdk/form-urlencoded-body.test.ts+22−23
@@ -30,6 +30,7 @@ import { · 29 unmodified lines
30} from "@executor-js/plugin-openapi/testing";30} from "@executor-js/plugin-openapi/testing";
31 31
32import { openApiPlugin } from "./plugin";32import { openApiPlugin } from "./plugin";
33import { testAccess } from "@executor-js/product-access/testing";
33 34
34type Captured = {35type Captured = {
35 contentType: string;36 contentType: string;
@@ -76,30 +77,28 @@ const plugins = [ · 40 unmodified lines
76 memoryCredentialsPlugin(),77 memoryCredentialsPlugin(),
77] as const;78] as const;
78 79
79layer(80layer(makeTestWorkspaceLayer({ access: testAccess.member(), plugins }), { timeout: "15 seconds" })(
80 makeTestWorkspaceLayer({81 "OpenAPI non-JSON request body serialization",
81 plugins,82 (it) => {
82 }),83 it.effect("form-urlencoded object body is properly encoded (no '[object Object]')", () =>
83 { timeout: "15 seconds" },84 Effect.gen(function* () {
84)("OpenAPI non-JSON request body serialization", (it) => {85 const { server, captured } = yield* startEchoServer();
85 it.effect("form-urlencoded object body is properly encoded (no '[object Object]')", () =>86 const { config } = yield* TestWorkspace;
86 Effect.gen(function* () {87 const executor = yield* createExecutor({ ...config, plugins });
87 const { server, captured } = yield* startEchoServer();
88 const { config } = yield* TestWorkspace;
89 const executor = yield* createExecutor({ ...config, plugins });
90 88
91 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "form" });89 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "form" });
92 90
93 yield* executor.execute(conn.address("forms.submit"), {91 yield* executor.execute(conn.address("forms.submit"), {
94 body: { name: "Acme", email: "a@b.com" },92 body: { name: "Acme", email: "a@b.com" },
95 });93 });
96 94
97 expect(captured.contentType).toBe("application/x-www-form-urlencoded");95 expect(captured.contentType).toBe("application/x-www-form-urlencoded");
98 expect(captured.body).not.toBe("[object Object]");96 expect(captured.body).not.toBe("[object Object]");
99 97
100 const parsed = new URLSearchParams(captured.body);98 const parsed = new URLSearchParams(captured.body);
101 expect(parsed.get("name")).toBe("Acme");99 expect(parsed.get("name")).toBe("Acme");
102 expect(parsed.get("email")).toBe("a@b.com");100 expect(parsed.get("email")).toBe("a@b.com");
103 }),101 }),
104 );102 );
105});103 },
104);
packages/plugins/openapi/src/sdk/health-check-redaction.test.ts+2−0
@@ -34,6 +34,7 @@ import { variable } from "@executor-js/sdk/http-auth"; · 33 unmodified lines
34 34
35import { serveOpenApiHttpApiTestServer } from "../testing";35import { serveOpenApiHttpApiTestServer } from "../testing";
36import { openApiPlugin } from "./plugin";36import { openApiPlugin } from "./plugin";
37import { testAccess } from "@executor-js/product-access/testing";
37 38
38/** The credential the connection authenticates with. Longer than the sample's39/** The credential the connection authenticates with. Longer than the sample's
39 * 120-char value cap on purpose: truncating before scrubbing would leave a40 * 120-char value cap on purpose: truncating before scrubbing would leave a
@@ -84,6 +85,7 @@ const withProbe = <A, E, R>( · 44 unmodified lines
84 });85 });
85 const executor = yield* createExecutor(86 const executor = yield* createExecutor(
86 makeTestConfig({87 makeTestConfig({
88 access: testAccess.member(),
87 plugins: [89 plugins: [
88 openApiPlugin({ httpClientLayer: FetchHttpClient.layer }),90 openApiPlugin({ httpClientLayer: FetchHttpClient.layer }),
89 memoryCredentialsPlugin(),91 memoryCredentialsPlugin(),
packages/plugins/openapi/src/sdk/multi-scope-bearer.test.ts+4−1
@@ -37,6 +37,7 @@ import { · 36 unmodified lines
37 37
38import { openApiPlugin } from "./plugin";38import { openApiPlugin } from "./plugin";
39import { type AuthenticationInput } from "./types";39import { type AuthenticationInput } from "./types";
40import { testAccess } from "@executor-js/product-access/testing";
40 41
41// ---------------------------------------------------------------------------42// ---------------------------------------------------------------------------
42// Test API — a single endpoint that echoes the Authorization header so the43// Test API — a single endpoint that echoes the Authorization header so the
@@ -86,7 +87,9 @@ describe("OpenAPI owner-isolated bearer", () => { · 43 unmodified lines
86 Effect.scoped(87 Effect.scoped(
87 Effect.gen(function* () {88 Effect.gen(function* () {
88 const server = yield* serveVercel();89 const server = yield* serveVercel();
89 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));90 const executor = yield* createExecutor(
91 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
92 );
90 93
91 // Admin uploads the spec once; the integration declares a bearer94 // Admin uploads the spec once; the integration declares a bearer
92 // template but no token value.95 // template but no token value.
packages/plugins/openapi/src/sdk/non-json-body.test.ts+106−35
@@ -32,6 +32,7 @@ import { · 31 unmodified lines
32} from "@executor-js/plugin-openapi/testing";32} from "@executor-js/plugin-openapi/testing";
33 33
34import { openApiPlugin } from "./plugin";34import { openApiPlugin } from "./plugin";
35import { testAccess } from "@executor-js/product-access/testing";
35 36
36const JsonNameBody = Schema.fromJsonString(37const JsonNameBody = Schema.fromJsonString(
37 Schema.Struct({38 Schema.Struct({
@@ -172,7 +173,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 134 unmodified lines
172 payload: ObjectBody.pipe(HttpApiSchema.asMultipart()),173 payload: ObjectBody.pipe(HttpApiSchema.asMultipart()),
173 });174 });
174 175
175 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));176 const executor = yield* createExecutor(
177 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
178 );
176 179
177 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "mp" });180 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "mp" });
178 181
@@ -222,7 +225,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 43 unmodified lines
222 ),225 ),
223 });226 });
224 227
225 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));228 const executor = yield* createExecutor(
229 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
230 );
226 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "paperless" });231 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "paperless" });
227 232
228 const schema = yield* executor.tools.schema(conn.address("body.upload"));233 const schema = yield* executor.tools.schema(conn.address("body.upload"));
@@ -298,7 +303,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 69 unmodified lines
298 ),303 ),
299 });304 });
300 305
301 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));306 const executor = yield* createExecutor(
307 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
308 );
302 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "pages" });309 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "pages" });
303 310
304 const schema = yield* executor.tools.schema(conn.address("body.uploadPages"));311 const schema = yield* executor.tools.schema(conn.address("body.uploadPages"));
@@ -378,7 +385,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 73 unmodified lines
378 }),385 }),
379 });386 });
380 387
381 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));388 const executor = yield* createExecutor(
389 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
390 );
382 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "broken" });391 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "broken" });
383 392
384 const exit = yield* executor393 const exit = yield* executor
@@ -424,7 +433,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 39 unmodified lines
424 }),433 }),
425 });434 });
426 435
427 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));436 const executor = yield* createExecutor(
437 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
438 );
428 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "notes" });439 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "notes" });
429 440
430 // The rewrite is scoped to multipart bodies: a JSON body keeps its441 // The rewrite is scoped to multipart bodies: a JSON body keeps its
@@ -465,7 +476,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 34 unmodified lines
465 }),476 }),
466 });477 });
467 478
468 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));479 const executor = yield* createExecutor(
480 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
481 );
469 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "notes-jsonapi" });482 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "notes-jsonapi" });
470 483
471 yield* executor.execute(conn.address("body.createNote"), {484 yield* executor.execute(conn.address("body.createNote"), {
@@ -511,7 +524,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 39 unmodified lines
511 }),524 }),
512 });525 });
513 526
514 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));527 const executor = yield* createExecutor(
528 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
529 );
515 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "mixed" });530 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "mixed" });
516 531
517 const schema = yield* executor.tools.schema(conn.address("body.uploadMixed"));532 const schema = yield* executor.tools.schema(conn.address("body.uploadMixed"));
@@ -564,7 +579,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 46 unmodified lines
564 },579 },
565 });580 });
566 581
567 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));582 const executor = yield* createExecutor(
583 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
584 );
568 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "reffed" });585 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "reffed" });
569 586
570 // Documented limitation: component schemas are carried through587 // Documented limitation: component schemas are carried through
@@ -584,7 +601,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 13 unmodified lines
584 payload: Schema.String.pipe(HttpApiSchema.asText({ contentType: "application/xml" })),601 payload: Schema.String.pipe(HttpApiSchema.asText({ contentType: "application/xml" })),
585 });602 });
586 603
587 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));604 const executor = yield* createExecutor(
605 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
606 );
588 607
589 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "xml" });608 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "xml" });
590 609
@@ -603,7 +622,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 12 unmodified lines
603 transformSpec: replaceRequestBodyContent("/submit", "post", contentFor("text/xml")),622 transformSpec: replaceRequestBodyContent("/submit", "post", contentFor("text/xml")),
604 });623 });
605 624
606 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));625 const executor = yield* createExecutor(
626 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
627 );
607 628
608 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "tx" });629 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "tx" });
609 630
@@ -622,7 +643,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 12 unmodified lines
622 payload: Schema.String.pipe(HttpApiSchema.asText()),643 payload: Schema.String.pipe(HttpApiSchema.asText()),
623 });644 });
624 645
625 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));646 const executor = yield* createExecutor(
647 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
648 );
626 649
627 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "tp" });650 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "tp" });
628 651
@@ -639,7 +662,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 10 unmodified lines
639 payload: Schema.Uint8Array.pipe(HttpApiSchema.asUint8Array()),662 payload: Schema.Uint8Array.pipe(HttpApiSchema.asUint8Array()),
640 });663 });
641 664
642 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));665 const executor = yield* createExecutor(
666 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
667 );
643 668
644 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "bin" });669 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "bin" });
645 670
@@ -658,7 +683,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 12 unmodified lines
658 payload: Schema.Uint8Array.pipe(HttpApiSchema.asUint8Array()),683 payload: Schema.Uint8Array.pipe(HttpApiSchema.asUint8Array()),
659 });684 });
660 685
661 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));686 const executor = yield* createExecutor(
687 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
688 );
662 689
663 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "bin_b64" });690 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "bin_b64" });
664 691
@@ -677,7 +704,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 12 unmodified lines
677 payload: Schema.Uint8Array.pipe(HttpApiSchema.asUint8Array()),704 payload: Schema.Uint8Array.pipe(HttpApiSchema.asUint8Array()),
678 });705 });
679 706
680 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));707 const executor = yield* createExecutor(
708 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
709 );
681 710
682 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "bin_b64_bad" });711 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "bin_b64_bad" });
683 712
@@ -699,7 +728,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 15 unmodified lines
699 payload: Schema.Uint8Array.pipe(HttpApiSchema.asUint8Array()),728 payload: Schema.Uint8Array.pipe(HttpApiSchema.asUint8Array()),
700 });729 });
701 730
702 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));731 const executor = yield* createExecutor(
732 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
733 );
703 734
704 const conn = yield* addOpenApiTestConnection(executor, server, {735 const conn = yield* addOpenApiTestConnection(executor, server, {
705 slug: "bin_nested_b64_bad",736 slug: "bin_nested_b64_bad",
@@ -723,7 +754,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 17 unmodified lines
723 payload: Schema.Uint8Array.pipe(HttpApiSchema.asUint8Array()),754 payload: Schema.Uint8Array.pipe(HttpApiSchema.asUint8Array()),
724 });755 });
725 756
726 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));757 const executor = yield* createExecutor(
758 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
759 );
727 760
728 const conn = yield* addOpenApiTestConnection(executor, server, {761 const conn = yield* addOpenApiTestConnection(executor, server, {
729 slug: "bin_b64_missing",762 slug: "bin_b64_missing",
@@ -743,7 +776,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 13 unmodified lines
743 payload: Schema.Uint8Array.pipe(HttpApiSchema.asUint8Array()),776 payload: Schema.Uint8Array.pipe(HttpApiSchema.asUint8Array()),
744 });777 });
745 778
746 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));779 const executor = yield* createExecutor(
780 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
781 );
747 782
748 const conn = yield* addOpenApiTestConnection(executor, server, {783 const conn = yield* addOpenApiTestConnection(executor, server, {
749 slug: "bin_object_body",784 slug: "bin_object_body",
@@ -767,7 +802,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 17 unmodified lines
767 payload: Schema.Uint8Array.pipe(HttpApiSchema.asUint8Array()),802 payload: Schema.Uint8Array.pipe(HttpApiSchema.asUint8Array()),
768 });803 });
769 804
770 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));805 const executor = yield* createExecutor(
806 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
807 );
771 808
772 const conn = yield* addOpenApiTestConnection(executor, server, {809 const conn = yield* addOpenApiTestConnection(executor, server, {
773 slug: "bin_string_body",810 slug: "bin_string_body",
@@ -837,7 +874,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 63 unmodified lines
837 }),874 }),
838 });875 });
839 876
840 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));877 const executor = yield* createExecutor(
878 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
879 );
841 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "gmail" });880 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "gmail" });
842 881
843 const schema = yield* executor.tools.schema(conn.address("gmail.getAttachment"));882 const schema = yield* executor.tools.schema(conn.address("gmail.getAttachment"));
@@ -921,7 +960,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 77 unmodified lines
921 }),960 }),
922 });961 });
923 962
924 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));963 const executor = yield* createExecutor(
964 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
965 );
925 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "gmail_text" });966 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "gmail_text" });
926 967
927 const result = yield* executor.execute(conn.address("gmailText.getAttachment"), {968 const result = yield* executor.execute(conn.address("gmailText.getAttachment"), {
@@ -989,7 +1030,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 61 unmodified lines
989 }),1030 }),
990 });1031 });
991 1032
992 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1033 const executor = yield* createExecutor(
1034 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1035 );
993 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "zip_attachment" });1036 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "zip_attachment" });
994 1037
995 const result = yield* executor.execute(conn.address("zipAttachment.getAttachment"), {1038 const result = yield* executor.execute(conn.address("zipAttachment.getAttachment"), {
@@ -1107,7 +1150,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 111 unmodified lines
1107 ),1150 ),
1108 });1151 });
1109 1152
1110 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1153 const executor = yield* createExecutor(
1154 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1155 );
1111 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "gmail_meta" });1156 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "gmail_meta" });
1112 1157
1113 const result = yield* executor.execute(conn.address("gmailMeta.getAttachment"), {1158 const result = yield* executor.execute(conn.address("gmailMeta.getAttachment"), {
@@ -1156,7 +1201,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 42 unmodified lines
1156 }),1201 }),
1157 });1202 });
1158 1203
1159 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1204 const executor = yield* createExecutor(
1205 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1206 );
1160 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "files" });1207 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "files" });
1161 1208
1162 const schema = yield* executor.tools.schema(conn.address("files.download"));1209 const schema = yield* executor.tools.schema(conn.address("files.download"));
@@ -1210,7 +1257,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 47 unmodified lines
1210 }),1257 }),
1211 });1258 });
1212 1259
1213 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1260 const executor = yield* createExecutor(
1261 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1262 );
1214 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "files" });1263 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "files" });
1215 1264
1216 const result = yield* executor.execute(conn.address("files.download"), {1265 const result = yield* executor.execute(conn.address("files.download"), {
@@ -1247,7 +1296,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 30 unmodified lines
1247 payload: multiContentPayload,1296 payload: multiContentPayload,
1248 });1297 });
1249 1298
1250 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1299 const executor = yield* createExecutor(
1300 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1301 );
1251 1302
1252 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "mc" });1303 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "mc" });
1253 1304
@@ -1265,7 +1316,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 11 unmodified lines
1265 payload: multiContentPayload,1316 payload: multiContentPayload,
1266 });1317 });
1267 1318
1268 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1319 const executor = yield* createExecutor(
1320 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1321 );
1269 1322
1270 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "mc2" });1323 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "mc2" });
1271 1324
@@ -1295,7 +1348,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 23 unmodified lines
1295 }),1348 }),
1296 });1349 });
1297 1350
1298 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1351 const executor = yield* createExecutor(
1352 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1353 );
1299 1354
1300 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "mc_b64" });1355 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "mc_b64" });
1301 1356
@@ -1322,7 +1377,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 20 unmodified lines
1322 }),1377 }),
1323 });1378 });
1324 1379
1325 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1380 const executor = yield* createExecutor(
1381 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1382 );
1326 1383
1327 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "mc_b64_bad_ct" });1384 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "mc_b64_bad_ct" });
1328 1385
@@ -1352,7 +1409,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 23 unmodified lines
1352 },1409 },
1353 }),1410 }),
1354 });1411 });
1355 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1412 const executor = yield* createExecutor(
1413 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1414 );
1356 1415
1357 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "mc_b64_schema" });1416 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "mc_b64_schema" });
1358 1417
@@ -1375,7 +1434,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 16 unmodified lines
1375 const { server } = yield* startEchoServer({1434 const { server } = yield* startEchoServer({
1376 payload: multiContentPayload,1435 payload: multiContentPayload,
1377 });1436 });
1378 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1437 const executor = yield* createExecutor(
1438 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1439 );
1379 1440
1380 const conn = yield* addOpenApiTestConnection(executor, server, {1441 const conn = yield* addOpenApiTestConnection(executor, server, {
1381 slug: "mc3",1442 slug: "mc3",
@@ -1404,7 +1465,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 22 unmodified lines
1404 const { server } = yield* startEchoServer({1465 const { server } = yield* startEchoServer({
1405 payload: Schema.Uint8Array.pipe(HttpApiSchema.asUint8Array()),1466 payload: Schema.Uint8Array.pipe(HttpApiSchema.asUint8Array()),
1406 });1467 });
1407 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1468 const executor = yield* createExecutor(
1469 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1470 );
1408 1471
1409 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "bin_schema" });1472 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "bin_schema" });
1410 1473
@@ -1450,7 +1513,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 39 unmodified lines
1450 ),1513 ),
1451 });1514 });
1452 1515
1453 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1516 const executor = yield* createExecutor(
1517 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1518 );
1454 1519
1455 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "mpe" });1520 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "mpe" });
1456 1521
@@ -1492,7 +1557,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 35 unmodified lines
1492 ),1557 ),
1493 });1558 });
1494 1559
1495 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1560 const executor = yield* createExecutor(
1561 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1562 );
1496 1563
1497 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "fe" });1564 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "fe" });
1498 1565
@@ -1523,7 +1590,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 24 unmodified lines
1523 ),1590 ),
1524 });1591 });
1525 1592
1526 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1593 const executor = yield* createExecutor(
1594 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1595 );
1527 1596
1528 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "fd" });1597 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "fd" });
1529 1598
@@ -1550,7 +1619,9 @@ describe("OpenAPI non-JSON request body dispatch", () => { · 20 unmodified lines
1550 ),1619 ),
1551 });1620 });
1552 1621
1553 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1622 const executor = yield* createExecutor(
1623 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1624 );
1554 1625
1555 // No encoding → OAS3 defaults: style=form, explode=true.1626 // No encoding → OAS3 defaults: style=form, explode=true.
1556 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "fdx" });1627 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "fdx" });
packages/plugins/openapi/src/sdk/plugin.test.ts+104−35
@@ -49,6 +49,7 @@ import { · 48 unmodified lines
49 serveOpenApiHttpApiTestServer,49 serveOpenApiHttpApiTestServer,
50 unwrapInvocation,50 unwrapInvocation,
51} from "../testing";51} from "../testing";
52import { testAccess } from "@executor-js/product-access/testing";
52 53
53const TOOL_ERROR_TYPESCRIPT =54const TOOL_ERROR_TYPESCRIPT =
54 "{ code: string; message: string; status?: number; details?: unknown; retryable?: boolean }";55 "{ code: string; message: string; status?: number; details?: unknown; retryable?: boolean }";
@@ -393,7 +394,9 @@ describe("OpenAPI Plugin", () => { · 338 unmodified lines
393 Effect.gen(function* () {394 Effect.gen(function* () {
394 const server = yield* servePluginTestApi();395 const server = yield* servePluginTestApi();
395 396
396 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));397 const executor = yield* createExecutor(
398 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
399 );
397 400
398 const preview = yield* executor.openapi.previewSpec(server.specJson);401 const preview = yield* executor.openapi.previewSpec(server.specJson);
399 402
@@ -408,7 +411,10 @@ describe("OpenAPI Plugin", () => { · 8 unmodified lines
408 Effect.gen(function* () {411 Effect.gen(function* () {
409 const server = yield* serveOAuthDiscoverableOpenApiSpec();412 const server = yield* serveOAuthDiscoverableOpenApiSpec();
410 const executor = yield* createExecutor(413 const executor = yield* createExecutor(
411 makeTestConfig({ plugins: testPlugins(server.httpClientLayer) }),414 makeTestConfig({
415 access: testAccess.member(),
416 plugins: testPlugins(server.httpClientLayer),
417 }),
412 );418 );
413 419
414 const preview = yield* executor.openapi.previewSpec(server.url("/api/schema/"));420 const preview = yield* executor.openapi.previewSpec(server.url("/api/schema/"));
@@ -456,7 +462,9 @@ describe("OpenAPI Plugin", () => { · 41 unmodified lines
456 462
457 it.effect("exposes static openapi executor control tools via execute", () =>463 it.effect("exposes static openapi executor control tools via execute", () =>
458 Effect.gen(function* () {464 Effect.gen(function* () {
459 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));465 const executor = yield* createExecutor(
466 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
467 );
460 468
461 // v2: static control tools are NOT part of `tools.list()` (that's the469 // v2: static control tools are NOT part of `tools.list()` (that's the
462 // persisted per-connection catalog) and aren't `tools.schema()`-resolvable;470 // persisted per-connection catalog) and aren't `tools.schema()`-resolvable;
@@ -473,7 +481,9 @@ describe("OpenAPI Plugin", () => { · 10 unmodified lines
473 481
474 it.effect("invokes static previewSpec through executor.execute", () =>482 it.effect("invokes static previewSpec through executor.execute", () =>
475 Effect.gen(function* () {483 Effect.gen(function* () {
476 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));484 const executor = yield* createExecutor(
485 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
486 );
477 487
478 const preview = unwrapInvocation(488 const preview = unwrapInvocation(
479 yield* executor.execute(ToolAddress.make("executor.openapi.previewSpec"), {489 yield* executor.execute(ToolAddress.make("executor.openapi.previewSpec"), {
@@ -495,7 +505,9 @@ describe("OpenAPI Plugin", () => { · 15 unmodified lines
495 505
496 it.effect("invokes static addSpec through executor.execute", () =>506 it.effect("invokes static addSpec through executor.execute", () =>
497 Effect.gen(function* () {507 Effect.gen(function* () {
498 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));508 const executor = yield* createExecutor(
509 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
510 );
499 511
500 const result = unwrapInvocation(512 const result = unwrapInvocation(
501 yield* executor.execute(ToolAddress.make("executor.openapi.addSpec"), {513 yield* executor.execute(ToolAddress.make("executor.openapi.addSpec"), {
@@ -517,7 +529,9 @@ describe("OpenAPI Plugin", () => { · 15 unmodified lines
517 Effect.scoped(529 Effect.scoped(
518 Effect.gen(function* () {530 Effect.gen(function* () {
519 const specServer = yield* serveMutableOpenApiSpecTestServer({ initialApi: TestApi });531 const specServer = yield* serveMutableOpenApiSpecTestServer({ initialApi: TestApi });
520 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));532 const executor = yield* createExecutor(
533 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
534 );
521 535
522 yield* executor.openapi.addSpec({536 yield* executor.openapi.addSpec({
523 spec: { kind: "url", url: specServer.specUrl },537 spec: { kind: "url", url: specServer.specUrl },
@@ -565,7 +579,10 @@ describe("OpenAPI Plugin", () => { · 41 unmodified lines
565 579
566 it.effect("static previewSpec returns actionable tool failures", () =>580 it.effect("static previewSpec returns actionable tool failures", () =>
567 Effect.gen(function* () {581 Effect.gen(function* () {
568 const config = makeTestConfig({ plugins: [openApiPlugin()] as const });582 const config = makeTestConfig({
583 access: testAccess.member(),
584 plugins: [openApiPlugin()] as const,
585 });
569 const executor = yield* createExecutor(config);586 const executor = yield* createExecutor(config);
570 587
571 const result = yield* executor.execute(ToolAddress.make("executor.openapi.previewSpec"), {588 const result = yield* executor.execute(ToolAddress.make("executor.openapi.previewSpec"), {
@@ -587,7 +604,7 @@ describe("OpenAPI Plugin", () => { · 15 unmodified lines
587 it.effect("requires approval before adding an integration through the runtime tool", () =>604 it.effect("requires approval before adding an integration through the runtime tool", () =>
588 Effect.gen(function* () {605 Effect.gen(function* () {
589 const executor = yield* createExecutor(606 const executor = yield* createExecutor(
590 makeTestConfig({ plugins: [openApiPlugin()] as const }),607 makeTestConfig({ access: testAccess.member(), plugins: [openApiPlugin()] as const }),
591 );608 );
592 609
593 const declined = yield* executor610 const declined = yield* executor
@@ -607,7 +624,9 @@ describe("OpenAPI Plugin", () => { · 13 unmodified lines
607 Effect.scoped(624 Effect.scoped(
608 Effect.gen(function* () {625 Effect.gen(function* () {
609 const server = yield* servePluginTestApi();626 const server = yield* servePluginTestApi();
610 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));627 const executor = yield* createExecutor(
628 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
629 );
611 630
612 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "test" });631 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "test" });
613 632
@@ -625,7 +644,9 @@ describe("OpenAPI Plugin", () => { · 11 unmodified lines
625 Effect.scoped(644 Effect.scoped(
626 Effect.gen(function* () {645 Effect.gen(function* () {
627 const server = yield* servePluginTestApi();646 const server = yield* servePluginTestApi();
628 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));647 const executor = yield* createExecutor(
648 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
649 );
629 650
630 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "test" });651 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "test" });
631 652
@@ -642,7 +663,9 @@ describe("OpenAPI Plugin", () => { · 10 unmodified lines
642 Effect.scoped(663 Effect.scoped(
643 Effect.gen(function* () {664 Effect.gen(function* () {
644 const server = yield* servePluginTestApi();665 const server = yield* servePluginTestApi();
645 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));666 const executor = yield* createExecutor(
667 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
668 );
646 669
647 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "test" });670 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "test" });
648 const calls = { count: 0 };671 const calls = { count: 0 };
@@ -671,7 +694,9 @@ describe("OpenAPI Plugin", () => { · 22 unmodified lines
671 Effect.scoped(694 Effect.scoped(
672 Effect.gen(function* () {695 Effect.gen(function* () {
673 const server = yield* servePluginTestApi();696 const server = yield* servePluginTestApi();
674 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));697 const executor = yield* createExecutor(
698 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
699 );
675 700
676 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "test" });701 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "test" });
677 const calls = { count: 0 };702 const calls = { count: 0 };
@@ -705,7 +730,9 @@ describe("OpenAPI Plugin", () => { · 27 unmodified lines
705 Effect.scoped(730 Effect.scoped(
706 Effect.gen(function* () {731 Effect.gen(function* () {
707 const server = yield* servePluginTestApi();732 const server = yield* servePluginTestApi();
708 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));733 const executor = yield* createExecutor(
734 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
735 );
709 736
710 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "test" });737 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "test" });
711 const calls = { count: 0 };738 const calls = { count: 0 };
@@ -738,7 +765,9 @@ describe("OpenAPI Plugin", () => { · 26 unmodified lines
738 Effect.scoped(765 Effect.scoped(
739 Effect.gen(function* () {766 Effect.gen(function* () {
740 const server = yield* servePluginTestApi();767 const server = yield* servePluginTestApi();
741 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));768 const executor = yield* createExecutor(
769 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
770 );
742 771
743 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "test" });772 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "test" });
744 const calls = { count: 0 };773 const calls = { count: 0 };
@@ -771,7 +800,9 @@ describe("OpenAPI Plugin", () => { · 26 unmodified lines
771 Effect.scoped(800 Effect.scoped(
772 Effect.gen(function* () {801 Effect.gen(function* () {
773 const server = yield* servePluginTestApi();802 const server = yield* servePluginTestApi();
774 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));803 const executor = yield* createExecutor(
804 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
805 );
775 806
776 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "test" });807 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "test" });
777 808
@@ -812,7 +843,9 @@ describe("OpenAPI Plugin", () => { · 34 unmodified lines
812 Effect.scoped(843 Effect.scoped(
813 Effect.gen(function* () {844 Effect.gen(function* () {
814 const server = yield* servePluginTestApi();845 const server = yield* servePluginTestApi();
815 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));846 const executor = yield* createExecutor(
847 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
848 );
816 849
817 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "test" });850 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "test" });
818 851
@@ -829,7 +862,9 @@ describe("OpenAPI Plugin", () => { · 10 unmodified lines
829 Effect.scoped(862 Effect.scoped(
830 Effect.gen(function* () {863 Effect.gen(function* () {
831 const server = yield* servePluginTestApi();864 const server = yield* servePluginTestApi();
832 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));865 const executor = yield* createExecutor(
866 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
867 );
833 868
834 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "test" });869 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "test" });
835 const failure = yield* executor870 const failure = yield* executor
@@ -853,7 +888,9 @@ describe("OpenAPI Plugin", () => { · 17 unmodified lines
853 Effect.scoped(888 Effect.scoped(
854 Effect.gen(function* () {889 Effect.gen(function* () {
855 const server = yield* servePluginTestApi();890 const server = yield* servePluginTestApi();
856 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));891 const executor = yield* createExecutor(
892 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
893 );
857 const multiServer = {894 const multiServer = {
858 ...server,895 ...server,
859 specJson: makeOpenApiTestSpecJson(TestApi, {896 specJson: makeOpenApiTestSpecJson(TestApi, {
@@ -889,7 +926,9 @@ describe("OpenAPI Plugin", () => { · 29 unmodified lines
889 const server = yield* serveOpenApiEchoTestServer({926 const server = yield* serveOpenApiEchoTestServer({
890 transformSpec: withEchoCookieParameter,927 transformSpec: withEchoCookieParameter,
891 });928 });
892 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));929 const executor = yield* createExecutor(
930 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
931 );
893 const conn = yield* addOpenApiTestConnection(executor, server, {932 const conn = yield* addOpenApiTestConnection(executor, server, {
894 slug: "cookie_params",933 slug: "cookie_params",
895 headers: { Cookie: "configured=yes" },934 headers: { Cookie: "configured=yes" },
@@ -923,7 +962,9 @@ describe("OpenAPI Plugin", () => { · 27 unmodified lines
923 const server = yield* serveOpenApiEchoTestServer({962 const server = yield* serveOpenApiEchoTestServer({
924 transformSpec: withEchoCookieParameter,963 transformSpec: withEchoCookieParameter,
925 });964 });
926 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));965 const executor = yield* createExecutor(
966 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
967 );
927 const conn = yield* addOpenApiTestConnection(executor, server, {968 const conn = yield* addOpenApiTestConnection(executor, server, {
928 slug: "cookie_unknown",969 slug: "cookie_unknown",
929 });970 });
@@ -951,7 +992,9 @@ describe("OpenAPI Plugin", () => { · 21 unmodified lines
951 Effect.scoped(992 Effect.scoped(
952 Effect.gen(function* () {993 Effect.gen(function* () {
953 const server = yield* servePluginTestApi();994 const server = yield* servePluginTestApi();
954 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));995 const executor = yield* createExecutor(
996 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
997 );
955 998
956 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "records" });999 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "records" });
957 1000
@@ -980,7 +1023,9 @@ describe("OpenAPI Plugin", () => { · 22 unmodified lines
980 Effect.scoped(1023 Effect.scoped(
981 Effect.gen(function* () {1024 Effect.gen(function* () {
982 const server = yield* servePluginTestApi();1025 const server = yield* servePluginTestApi();
983 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1026 const executor = yield* createExecutor(
1027 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1028 );
984 1029
985 yield* executor.openapi.addSpec({1030 yield* executor.openapi.addSpec({
986 spec: { kind: "blob", value: server.specJson },1031 spec: { kind: "blob", value: server.specJson },
@@ -1012,7 +1057,9 @@ describe("OpenAPI Plugin", () => { · 25 unmodified lines
1012 Effect.scoped(1057 Effect.scoped(
1013 Effect.gen(function* () {1058 Effect.gen(function* () {
1014 const server = yield* servePluginTestApi();1059 const server = yield* servePluginTestApi();
1015 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1060 const executor = yield* createExecutor(
1061 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1062 );
1016 1063
1017 yield* executor.openapi.addSpec({1064 yield* executor.openapi.addSpec({
1018 spec: { kind: "blob", value: server.specJson },1065 spec: { kind: "blob", value: server.specJson },
@@ -1044,7 +1091,9 @@ describe("OpenAPI Plugin", () => { · 25 unmodified lines
1044 Effect.scoped(1091 Effect.scoped(
1045 Effect.gen(function* () {1092 Effect.gen(function* () {
1046 const server = yield* servePluginTestApi();1093 const server = yield* servePluginTestApi();
1047 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1094 const executor = yield* createExecutor(
1095 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1096 );
1048 1097
1049 // The spec declares bearer auth; the caller passes NO template — the1098 // The spec declares bearer auth; the caller passes NO template — the
1050 // agentic add path (MCP/API) does exactly this. Without server-side1099 // agentic add path (MCP/API) does exactly this. Without server-side
@@ -1097,7 +1146,9 @@ describe("OpenAPI Plugin", () => { · 46 unmodified lines
1097 Effect.scoped(1146 Effect.scoped(
1098 Effect.gen(function* () {1147 Effect.gen(function* () {
1099 const server = yield* servePluginTestApi();1148 const server = yield* servePluginTestApi();
1100 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1149 const executor = yield* createExecutor(
1150 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1151 );
1101 1152
1102 // No baseUrl override: the spec declares `servers`, so the host is1153 // No baseUrl override: the spec declares `servers`, so the host is
1103 // resolved per call from the operation's servers rather than baked into1154 // resolved per call from the operation's servers rather than baked into
@@ -1127,7 +1178,9 @@ describe("OpenAPI Plugin", () => { · 23 unmodified lines
1127 Effect.scoped(1178 Effect.scoped(
1128 Effect.gen(function* () {1179 Effect.gen(function* () {
1129 const server = yield* servePluginTestApi();1180 const server = yield* servePluginTestApi();
1130 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1181 const executor = yield* createExecutor(
1182 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1183 );
1131 1184
1132 // The add page sends [] when the user deletes every detected method.1185 // The add page sends [] when the user deletes every detected method.
1133 // That intent must survive — deriving methods back from the spec here1186 // That intent must survive — deriving methods back from the spec here
@@ -1158,7 +1211,9 @@ describe("OpenAPI Plugin", () => { · 24 unmodified lines
1158 1211
1159 it.effect("addSpec accepts Graph-sized OpenAPI blobs", () =>1212 it.effect("addSpec accepts Graph-sized OpenAPI blobs", () =>
1160 Effect.gen(function* () {1213 Effect.gen(function* () {
1161 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1214 const executor = yield* createExecutor(
1215 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1216 );
1162 const largeDescription = "x".repeat(36 * 1024 * 1024);1217 const largeDescription = "x".repeat(36 * 1024 * 1024);
1163 1218
1164 const added = yield* executor.openapi.addSpec({1219 const added = yield* executor.openapi.addSpec({
@@ -1191,7 +1246,9 @@ paths: · 26 unmodified lines
1191 "addSpec accepts Microsoft Graph-scale operation catalogs from one spec",1246 "addSpec accepts Microsoft Graph-scale operation catalogs from one spec",
1192 () =>1247 () =>
1193 Effect.gen(function* () {1248 Effect.gen(function* () {
1194 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1249 const executor = yield* createExecutor(
1250 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1251 );
1195 1252
1196 const added = yield* executor.openapi.addSpec({1253 const added = yield* executor.openapi.addSpec({
1197 spec: { kind: "blob", value: microsoftGraphScaleSpecText() },1254 spec: { kind: "blob", value: microsoftGraphScaleSpecText() },
@@ -1208,7 +1265,9 @@ paths: · 10 unmodified lines
1208 Effect.scoped(1265 Effect.scoped(
1209 Effect.gen(function* () {1266 Effect.gen(function* () {
1210 const server = yield* servePluginTestApi();1267 const server = yield* servePluginTestApi();
1211 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1268 const executor = yield* createExecutor(
1269 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1270 );
1212 1271
1213 yield* addOpenApiTestConnection(executor, server, { slug: "removable" });1272 yield* addOpenApiTestConnection(executor, server, { slug: "removable" });
1214 expect((yield* executor.tools.list()).map((t) => String(t.name))).toContain(1273 expect((yield* executor.tools.list()).map((t) => String(t.name))).toContain(
@@ -1232,7 +1291,9 @@ paths: · 17 unmodified lines
1232 Effect.scoped(1291 Effect.scoped(
1233 Effect.gen(function* () {1292 Effect.gen(function* () {
1234 const server = yield* servePluginTestApi();1293 const server = yield* servePluginTestApi();
1235 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1294 const executor = yield* createExecutor(
1295 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1296 );
1236 1297
1237 // First add carries an apiKey auth template + a distinctive description.1298 // First add carries an apiKey auth template + a distinctive description.
1238 // A silent upsert on re-add would clobber both.1299 // A silent upsert on re-add would clobber both.
@@ -1294,7 +1355,9 @@ paths: · 55 unmodified lines
1294 // The mutable spec server is a real 127.0.0.1 listener — reach it over1355 // The mutable spec server is a real 127.0.0.1 listener — reach it over
1295 // the default fetch-based client, like production would.1356 // the default fetch-based client, like production would.
1296 const specServer = yield* serveMutableOpenApiSpecTestServer({ initialApi: TestApi });1357 const specServer = yield* serveMutableOpenApiSpecTestServer({ initialApi: TestApi });
1297 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1358 const executor = yield* createExecutor(
1359 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1360 );
1298 1361
1299 const added = yield* executor.openapi.addSpec({1362 const added = yield* executor.openapi.addSpec({
1300 spec: { kind: "url", url: specServer.specUrl },1363 spec: { kind: "url", url: specServer.specUrl },
@@ -1370,7 +1433,7 @@ paths: · 69 unmodified lines
1370 it.effect("denies member updateSpec before writing an org blob", () =>1433 it.effect("denies member updateSpec before writing an org blob", () =>
1371 Effect.gen(function* () {1434 Effect.gen(function* () {
1372 const blobs = recordingBlobStore();1435 const blobs = recordingBlobStore();
1373 const config = makeTestConfig({ plugins: testPlugins() });1436 const config = makeTestConfig({ access: testAccess.member(), plugins: testPlugins() });
1374 const admin = yield* createExecutor({ ...config, blobs: blobs.store });1437 const admin = yield* createExecutor({ ...config, blobs: blobs.store });
1375 yield* admin.openapi.addSpec({1438 yield* admin.openapi.addSpec({
1376 spec: { kind: "blob", value: testApiSpecText() },1439 spec: { kind: "blob", value: testApiSpecText() },
@@ -1380,7 +1443,7 @@ paths: · 3 unmodified lines
1380 const member = yield* createExecutor({1443 const member = yield* createExecutor({
1381 ...config,1444 ...config,
1382 blobs: blobs.store,1445 blobs: blobs.store,
1383 orgWrites: "denied",1446 access: testAccess.member("denied"),
1384 });1447 });
1385 1448
1386 const error = yield* member.openapi1449 const error = yield* member.openapi
@@ -1398,7 +1461,9 @@ paths: · 11 unmodified lines
1398 Effect.scoped(1461 Effect.scoped(
1399 Effect.gen(function* () {1462 Effect.gen(function* () {
1400 const server = yield* servePluginTestApi();1463 const server = yield* servePluginTestApi();
1401 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1464 const executor = yield* createExecutor(
1465 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1466 );
1402 yield* addOpenApiTestConnection(executor, server, { slug: "pasted" });1467 yield* addOpenApiTestConnection(executor, server, { slug: "pasted" });
1403 1468
1404 // A pasted-blob integration has no source URL — re-fetch must say so.1469 // A pasted-blob integration has no source URL — re-fetch must say so.
@@ -1450,6 +1515,7 @@ paths: · 45 unmodified lines
1450 const plugins = testPlugins();1515 const plugins = testPlugins();
1451 1516
1452 const alice = yield* makeTestWorkspaceHarness({1517 const alice = yield* makeTestWorkspaceHarness({
1518 access: testAccess.member(),
1453 plugins,1519 plugins,
1454 tenant,1520 tenant,
1455 subject: "alice",1521 subject: "alice",
@@ -1470,6 +1536,7 @@ paths: · 14 unmodified lines
1470 });1536 });
1471 1537
1472 const bob = yield* makeTestWorkspaceHarness({1538 const bob = yield* makeTestWorkspaceHarness({
1539 access: testAccess.member(),
1473 plugins,1540 plugins,
1474 tenant,1541 tenant,
1475 subject: "bob",1542 subject: "bob",
@@ -1513,7 +1580,9 @@ paths: · 37 unmodified lines
1513 1580
1514 it.effect("updateSpec on an unknown slug fails with IntegrationNotFoundError", () =>1581 it.effect("updateSpec on an unknown slug fails with IntegrationNotFoundError", () =>
1515 Effect.gen(function* () {1582 Effect.gen(function* () {
1516 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));1583 const executor = yield* createExecutor(
1584 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
1585 );
1517 const error = yield* executor.openapi.updateSpec("missing").pipe(Effect.flip);1586 const error = yield* executor.openapi.updateSpec("missing").pipe(Effect.flip);
1518 expect(Predicate.isTagged(error, "IntegrationNotFoundError")).toBe(true);1587 expect(Predicate.isTagged(error, "IntegrationNotFoundError")).toBe(true);
1519 }),1588 }),
packages/plugins/openapi/src/sdk/real-specs.test.ts+2−0
@@ -28,6 +28,7 @@ import { openApiPlugin } from "./plugin"; · 27 unmodified lines
28import { deriveAuthenticationTemplateFromPreview } from "./derive-auth";28import { deriveAuthenticationTemplateFromPreview } from "./derive-auth";
29import { previewSpec as previewSpecRaw } from "./preview";29import { previewSpec as previewSpecRaw } from "./preview";
30import type { ExtractionResult } from "./types";30import type { ExtractionResult } from "./types";
31import { testAccess } from "@executor-js/product-access/testing";
31 32
32const previewSpec = (input: string) =>33const previewSpec = (input: string) =>
33 previewSpecRaw(input).pipe(Effect.provide(FetchHttpClient.layer));34 previewSpecRaw(input).pipe(Effect.provide(FetchHttpClient.layer));
@@ -91,6 +92,7 @@ const getRegisteredToolSchema = (slug: string, specText: string, toolName: strin · 57 unmodified lines
91 92
92 const executor = yield* createExecutor(93 const executor = yield* createExecutor(
93 makeTestConfig({94 makeTestConfig({
95 access: testAccess.member(),
94 plugins: [openApiPlugin(), memoryCredentialsPlugin()] as const,96 plugins: [openApiPlugin(), memoryCredentialsPlugin()] as const,
95 }),97 }),
96 );98 );
packages/plugins/openapi/src/sdk/response-body-timeout.test.ts+4−1
@@ -16,6 +16,7 @@ import { makeTestConfig, memoryCredentialsPlugin } from "@executor-js/sdk/testin · 15 unmodified lines
16import { makeOpenApiHttpApiTestIntegrationConfig } from "../testing";16import { makeOpenApiHttpApiTestIntegrationConfig } from "../testing";
17 17
18import { openApiPlugin } from "./plugin";18import { openApiPlugin } from "./plugin";
19import { testAccess } from "@executor-js/product-access/testing";
19 20
20const BODY_READ_DEADLINE_MS = 15_000;21const BODY_READ_DEADLINE_MS = 15_000;
21const RESPONSE_BODY_TIMEOUT_MS = 100;22const RESPONSE_BODY_TIMEOUT_MS = 100;
@@ -42,7 +43,9 @@ const testPlugins = () => · 20 unmodified lines
42 43
43const buildExecutor = (baseUrl: string) =>44const buildExecutor = (baseUrl: string) =>
44 Effect.gen(function* () {45 Effect.gen(function* () {
45 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));46 const executor = yield* createExecutor(
47 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
48 );
46 yield* executor.openapi.addSpec(49 yield* executor.openapi.addSpec(
47 makeOpenApiHttpApiTestIntegrationConfig(TimeoutApi, {50 makeOpenApiHttpApiTestIntegrationConfig(TimeoutApi, {
48 slug: "body_timeout",51 slug: "body_timeout",
packages/plugins/openapi/src/sdk/response-headers-timeout.test.ts+4−1
@@ -18,6 +18,7 @@ import { makeOpenApiHttpApiTestIntegrationConfig, unwrapInvocation } from "../te · 17 unmodified lines
18import { invokeWithLayer } from "./invoke";18import { invokeWithLayer } from "./invoke";
19import { openApiPlugin } from "./plugin";19import { openApiPlugin } from "./plugin";
20import type { OperationBinding } from "./types";20import type { OperationBinding } from "./types";
21import { testAccess } from "@executor-js/product-access/testing";
21 22
22const RESPONSE_HEADERS_TIMEOUT_MS = 100;23const RESPONSE_HEADERS_TIMEOUT_MS = 100;
23const STREAM_TOOL = "logs.getLogs";24const STREAM_TOOL = "logs.getLogs";
@@ -44,7 +45,9 @@ const testPlugins = () => · 20 unmodified lines
44 45
45const buildExecutor = (baseUrl: string) =>46const buildExecutor = (baseUrl: string) =>
46 Effect.gen(function* () {47 Effect.gen(function* () {
47 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));48 const executor = yield* createExecutor(
49 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
50 );
48 yield* executor.openapi.addSpec(51 yield* executor.openapi.addSpec(
49 makeOpenApiHttpApiTestIntegrationConfig(TimeoutApi, { slug: "headers_timeout", baseUrl }),52 makeOpenApiHttpApiTestIntegrationConfig(TimeoutApi, { slug: "headers_timeout", baseUrl }),
50 );53 );
packages/plugins/openapi/src/sdk/spec-blob.test.ts+15−6
@@ -38,6 +38,7 @@ import { · 37 unmodified lines
38 serveOpenApiHttpApiTestServer,38 serveOpenApiHttpApiTestServer,
39 unwrapInvocation,39 unwrapInvocation,
40} from "../testing";40} from "../testing";
41import { testAccess } from "@executor-js/product-access/testing";
41 42
42const testPlugins = (httpClientLayer = FetchHttpClient.layer) =>43const testPlugins = (httpClientLayer = FetchHttpClient.layer) =>
43 [openApiPlugin({ httpClientLayer }), memoryCredentialsPlugin()] as const;44 [openApiPlugin({ httpClientLayer }), memoryCredentialsPlugin()] as const;
@@ -113,7 +114,9 @@ describe("OpenAPI plugin — spec blob storage", () => { · 69 unmodified lines
113 it.effect("addSpec stores a content pointer, not the inline spec text", () =>114 it.effect("addSpec stores a content pointer, not the inline spec text", () =>
114 Effect.scoped(115 Effect.scoped(
115 Effect.gen(function* () {116 Effect.gen(function* () {
116 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));117 const executor = yield* createExecutor(
118 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
119 );
117 const text = specText();120 const text = specText();
118 121
119 yield* executor.openapi.addSpec({122 yield* executor.openapi.addSpec({
@@ -135,7 +138,9 @@ describe("OpenAPI plugin — spec blob storage", () => { · 15 unmodified lines
135 api: TestApi,138 api: TestApi,
136 handlersLayer: EchoGroupLive,139 handlersLayer: EchoGroupLive,
137 });140 });
138 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));141 const executor = yield* createExecutor(
142 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
143 );
139 144
140 yield* executor.openapi.addSpec({145 yield* executor.openapi.addSpec({
141 spec: { kind: "blob", value: server.specJson },146 spec: { kind: "blob", value: server.specJson },
@@ -168,7 +173,7 @@ describe("OpenAPI plugin — spec blob storage", () => { · 26 unmodified lines
168 () =>173 () =>
169 Effect.scoped(174 Effect.scoped(
170 Effect.gen(function* () {175 Effect.gen(function* () {
171 const config = makeTestConfig({ plugins: testPlugins() });176 const config = makeTestConfig({ access: testAccess.member(), plugins: testPlugins() });
172 const executor = yield* createExecutor(config);177 const executor = yield* createExecutor(config);
173 const text = specTextWithDefinition();178 const text = specTextWithDefinition();
174 const hash = yield* sha256Hex(text);179 const hash = yield* sha256Hex(text);
@@ -245,7 +250,7 @@ describe("OpenAPI plugin — spec blob storage", () => { · 70 unmodified lines
245 it.effect("stale sync preserves tools and definitions when the spec blob is missing", () =>250 it.effect("stale sync preserves tools and definitions when the spec blob is missing", () =>
246 Effect.scoped(251 Effect.scoped(
247 Effect.gen(function* () {252 Effect.gen(function* () {
248 const config = makeTestConfig({ plugins: testPlugins() });253 const config = makeTestConfig({ access: testAccess.member(), plugins: testPlugins() });
249 const executor = yield* createExecutor(config);254 const executor = yield* createExecutor(config);
250 const text = specTextWithDefinition();255 const text = specTextWithDefinition();
251 const hash = yield* sha256Hex(text);256 const hash = yield* sha256Hex(text);
@@ -318,7 +323,9 @@ describe("OpenAPI plugin — spec blob storage", () => { · 66 unmodified lines
318 it.effect("explicit spec refresh accepts a valid OpenAPI document with zero operations", () =>323 it.effect("explicit spec refresh accepts a valid OpenAPI document with zero operations", () =>
319 Effect.scoped(324 Effect.scoped(
320 Effect.gen(function* () {325 Effect.gen(function* () {
321 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));326 const executor = yield* createExecutor(
327 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
328 );
322 const emptySpec = JSON.stringify({329 const emptySpec = JSON.stringify({
323 openapi: "3.1.0",330 openapi: "3.1.0",
324 info: { title: "Empty", version: "1.0.0" },331 info: { title: "Empty", version: "1.0.0" },
@@ -409,7 +416,9 @@ describe("OpenAPI plugin — spec blob storage", () => { · 84 unmodified lines
409 it.effect("remove + re-add of the same spec is idempotent over the shared blob", () =>416 it.effect("remove + re-add of the same spec is idempotent over the shared blob", () =>
410 Effect.scoped(417 Effect.scoped(
411 Effect.gen(function* () {418 Effect.gen(function* () {
412 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));419 const executor = yield* createExecutor(
420 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
421 );
413 const text = specText();422 const text = specText();
414 423
415 yield* executor.openapi.addSpec({ spec: { kind: "blob", value: text }, slug: "re_add" });424 yield* executor.openapi.addSpec({ spec: { kind: "blob", value: text }, slug: "re_add" });
packages/plugins/openapi/src/sdk/spec-overrides-lifecycle.test.ts+10−3
@@ -9,6 +9,7 @@ import { makeTestConfig, memoryCredentialsPlugin } from "@executor-js/sdk/testin · 8 unmodified lines
9import { openApiPlugin } from "./plugin";9import { openApiPlugin } from "./plugin";
10import { applySpecOverrides, type SpecOverrides } from "./spec-overrides";10import { applySpecOverrides, type SpecOverrides } from "./spec-overrides";
11import { serveMutableOpenApiSpecTestServer } from "../testing";11import { serveMutableOpenApiSpecTestServer } from "../testing";
12import { testAccess } from "@executor-js/product-access/testing";
12 13
13const testPlugins = () =>14const testPlugins = () =>
14 [openApiPlugin({ httpClientLayer: FetchHttpClient.layer }), memoryCredentialsPlugin()] as const;15 [openApiPlugin({ httpClientLayer: FetchHttpClient.layer }), memoryCredentialsPlugin()] as const;
@@ -60,7 +61,9 @@ describe("OpenAPI spec override lifecycle", () => { · 45 unmodified lines
60 it.effect("applies scope overrides to preview and persists raw and patched hashes", () =>61 it.effect("applies scope overrides to preview and persists raw and patched hashes", () =>
61 Effect.scoped(62 Effect.scoped(
62 Effect.gen(function* () {63 Effect.gen(function* () {
63 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));64 const executor = yield* createExecutor(
65 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
66 );
64 const sourceText = encodeJsonText(oauthSpec);67 const sourceText = encodeJsonText(oauthSpec);
65 68
66 const preview = yield* executor.openapi.previewSpec({69 const preview = yield* executor.openapi.previewSpec({
@@ -93,7 +96,9 @@ describe("OpenAPI spec override lifecycle", () => { · 26 unmodified lines
93 it.effect("changes and clears overrides for an inline spec without repasting the source", () =>96 it.effect("changes and clears overrides for an inline spec without repasting the source", () =>
94 Effect.scoped(97 Effect.scoped(
95 Effect.gen(function* () {98 Effect.gen(function* () {
96 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));99 const executor = yield* createExecutor(
100 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
101 );
97 const sourceText = encodeJsonText(oauthSpec);102 const sourceText = encodeJsonText(oauthSpec);
98 yield* executor.openapi.addSpec({103 yield* executor.openapi.addSpec({
99 spec: { kind: "blob", value: sourceText },104 spec: { kind: "blob", value: sourceText },
@@ -130,7 +135,9 @@ describe("OpenAPI spec override lifecycle", () => { · 30 unmodified lines
130 .add(HttpApiEndpoint.post("create", "/items", { success: Schema.String }));135 .add(HttpApiEndpoint.post("create", "/items", { success: Schema.String }));
131 const InitialApi = HttpApi.make("initial").add(Items);136 const InitialApi = HttpApi.make("initial").add(Items);
132 const server = yield* serveMutableOpenApiSpecTestServer({ initialApi: InitialApi });137 const server = yield* serveMutableOpenApiSpecTestServer({ initialApi: InitialApi });
133 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));138 const executor = yield* createExecutor(
139 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
140 );
134 const removeList: SpecOverrides = [{ op: "remove", path: "/paths/~1items/get" }];141 const removeList: SpecOverrides = [{ op: "remove", path: "/paths/~1items/get" }];
135 142
136 yield* executor.openapi.addSpec({143 yield* executor.openapi.addSpec({
packages/plugins/openapi/src/sdk/streaming-response.test.ts+7−2
@@ -17,6 +17,7 @@ import { makeOpenApiHttpApiTestIntegrationConfig, unwrapInvocation } from "../te · 16 unmodified lines
17 17
18import { collectStreamingBody, STREAM_MAX_BYTES } from "./invoke";18import { collectStreamingBody, STREAM_MAX_BYTES } from "./invoke";
19import { openApiPlugin } from "./plugin";19import { openApiPlugin } from "./plugin";
20import { testAccess } from "@executor-js/product-access/testing";
20 21
21const testPlugins = () =>22const testPlugins = () =>
22 [openApiPlugin({ httpClientLayer: FetchHttpClient.layer }), memoryCredentialsPlugin()] as const;23 [openApiPlugin({ httpClientLayer: FetchHttpClient.layer }), memoryCredentialsPlugin()] as const;
@@ -35,7 +36,9 @@ const StreamingApi = HttpApi.make("streamingResponseTest") · 12 unmodified lines
35 36
36const buildExecutor = (baseUrl: string) =>37const buildExecutor = (baseUrl: string) =>
37 Effect.gen(function* () {38 Effect.gen(function* () {
38 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));39 const executor = yield* createExecutor(
40 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
41 );
39 yield* executor.openapi.addSpec(42 yield* executor.openapi.addSpec(
40 makeOpenApiHttpApiTestIntegrationConfig(StreamingApi, { slug: "streaming", baseUrl }),43 makeOpenApiHttpApiTestIntegrationConfig(StreamingApi, { slug: "streaming", baseUrl }),
41 );44 );
@@ -293,7 +296,9 @@ describe("OpenAPI streaming responses", () => { · 251 unmodified lines
293 );296 );
294 });297 });
295 298
296 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));299 const executor = yield* createExecutor(
300 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
301 );
297 yield* executor.openapi.addSpec({302 yield* executor.openapi.addSpec({
298 spec: {303 spec: {
299 kind: "blob",304 kind: "blob",
packages/plugins/openapi/src/sdk/tool-row-projection.test.ts+4−1
@@ -25,6 +25,7 @@ import { variable } from "@executor-js/sdk/http-auth"; · 24 unmodified lines
25 25
26import { openApiPlugin } from "./plugin";26import { openApiPlugin } from "./plugin";
27import { serveOpenApiHttpApiTestServer, unwrapInvocation } from "../testing";27import { serveOpenApiHttpApiTestServer, unwrapInvocation } from "../testing";
28import { testAccess } from "@executor-js/product-access/testing";
28 29
29const testPlugins = (httpClientLayer = FetchHttpClient.layer) =>30const testPlugins = (httpClientLayer = FetchHttpClient.layer) =>
30 [openApiPlugin({ httpClientLayer }), memoryCredentialsPlugin()] as const;31 [openApiPlugin({ httpClientLayer }), memoryCredentialsPlugin()] as const;
@@ -58,7 +59,9 @@ const setup = Effect.gen(function* () { · 27 unmodified lines
58 api: TestApi,59 api: TestApi,
59 handlersLayer: EchoGroupLive,60 handlersLayer: EchoGroupLive,
60 });61 });
61 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));62 const executor = yield* createExecutor(
63 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
64 );
62 yield* executor.openapi.addSpec({65 yield* executor.openapi.addSpec({
63 spec: { kind: "blob", value: server.specJson },66 spec: { kind: "blob", value: server.specJson },
64 slug: "proj_api",67 slug: "proj_api",
packages/plugins/openapi/src/sdk/upstream-failures.test.ts+8−3
@@ -48,6 +48,7 @@ import { · 47 unmodified lines
48} from "../testing";48} from "../testing";
49 49
50import { openApiPlugin } from "./plugin";50import { openApiPlugin } from "./plugin";
51import { testAccess } from "@executor-js/product-access/testing";
51 52
52class AdapterDefect extends Data.TaggedError("AdapterDefect") {}53class AdapterDefect extends Data.TaggedError("AdapterDefect") {}
53 54
@@ -149,7 +150,7 @@ const FailureApi = HttpApi.make("failuresTest") · 95 unmodified lines
149const buildExecutor = (baseUrl: string, httpClientLayer = FetchHttpClient.layer) =>150const buildExecutor = (baseUrl: string, httpClientLayer = FetchHttpClient.layer) =>
150 Effect.gen(function* () {151 Effect.gen(function* () {
151 const executor = yield* createExecutor(152 const executor = yield* createExecutor(
152 makeTestConfig({ plugins: testPlugins(httpClientLayer) }),153 makeTestConfig({ access: testAccess.member(), plugins: testPlugins(httpClientLayer) }),
153 );154 );
154 yield* executor.openapi.addSpec(155 yield* executor.openapi.addSpec(
155 makeOpenApiHttpApiTestIntegrationConfig(FailureApi, { slug: "f", baseUrl }),156 makeOpenApiHttpApiTestIntegrationConfig(FailureApi, { slug: "f", baseUrl }),
@@ -167,7 +168,9 @@ const buildExecutor = (baseUrl: string, httpClientLayer = FetchHttpClient.layer) · 11 unmodified lines
167 168
168const buildExecutorForOpenApiServer = (server: OpenApiTestServerShape) =>169const buildExecutorForOpenApiServer = (server: OpenApiTestServerShape) =>
169 Effect.gen(function* () {170 Effect.gen(function* () {
170 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));171 const executor = yield* createExecutor(
172 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
173 );
171 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "f" });174 const conn = yield* addOpenApiTestConnection(executor, server, { slug: "f" });
172 return { executor, address: conn.address(LIST_THINGS) };175 return { executor, address: conn.address(LIST_THINGS) };
173 });176 });
@@ -349,7 +352,9 @@ describe("OpenAPI upstream failure modes", () => { · 175 unmodified lines
349 headers: { "content-type": "application/json" },352 headers: { "content-type": "application/json" },
350 body: '{"error":{"status":"PERMISSION_DENIED","details":[{"reason":"ACCESS_TOKEN_SCOPE_INSUFFICIENT"}]}}',353 body: '{"error":{"status":"PERMISSION_DENIED","details":[{"reason":"ACCESS_TOKEN_SCOPE_INSUFFICIENT"}]}}',
351 }));354 }));
352 const executor = yield* createExecutor(makeTestConfig({ plugins: testPlugins() }));355 const executor = yield* createExecutor(
356 makeTestConfig({ access: testAccess.member(), plugins: testPlugins() }),
357 );
353 // Declare the operation's scope in the spec blob before registering it,358 // Declare the operation's scope in the spec blob before registering it,
354 // so the extracted binding carries requiredScopes.359 // so the extracted binding carries requiredScopes.
355 const SpecJson = Schema.fromJsonString(Schema.Record(Schema.String, Schema.Unknown));360 const SpecJson = Schema.fromJsonString(Schema.Record(Schema.String, Schema.Unknown));