History

Reduce Microsoft Graph full import memory

Rhys Sullivan committed 4 months ago

Commit 12b09311 parent 1f696d02 files · +56 −12Browse files

Unified · Split

2 files
  1. packages/plugins/microsoft/src/sdk/graph.ts +47 −10
  2. packages/plugins/microsoft/src/sdk/plugin.ts +9 −2
packages/plugins/microsoft/src/sdk/graph.ts+47−10
@@ -9,6 +9,7 @@ import { · 8 unmodified lines
9 OpenApiParseError,9 OpenApiParseError,
10 type Authentication,10 type Authentication,
11 type OpenApiIntegrationConfig,11 type OpenApiIntegrationConfig,
12 type ParsedDocument,
12} from "@executor-js/plugin-openapi";13} from "@executor-js/plugin-openapi";
13 14
14import {15import {
@@ -41,6 +42,7 @@ export interface MicrosoftGraphSelectionInput { · 26 unmodified lines
41 42
42export interface MicrosoftGraphSpecBuild {43export interface MicrosoftGraphSpecBuild {
43 readonly specText: string;44 readonly specText: string;
45 readonly parsedDocument?: ParsedDocument;
44 readonly specUrl: string;46 readonly specUrl: string;
45 readonly baseUrl?: string;47 readonly baseUrl?: string;
46 readonly authorizationUrl: string;48 readonly authorizationUrl: string;
@@ -90,6 +92,8 @@ const MicrosoftGraphIntegrationConfigSchema = Schema.Struct({ · 43 unmodified lines
90 92
91const decodeMicrosoftConfig = Schema.decodeUnknownOption(MicrosoftGraphIntegrationConfigSchema);93const decodeMicrosoftConfig = Schema.decodeUnknownOption(MicrosoftGraphIntegrationConfigSchema);
92 94
95type MicrosoftGraphOpenApiDocument = ParsedDocument & Record<string, unknown>;
96
93export const decodeMicrosoftGraphIntegrationConfig = (97export const decodeMicrosoftGraphIntegrationConfig = (
94 value: unknown,98 value: unknown,
95): MicrosoftGraphIntegrationConfig | null =>99): MicrosoftGraphIntegrationConfig | null =>
@@ -478,7 +482,7 @@ export const fetchMicrosoftGraphPermissionsReference = Effect.fn( · 382 unmodified lines
478 482
479const parseMicrosoftGraphOpenApiDocument = (483const parseMicrosoftGraphOpenApiDocument = (
480 specText: string,484 specText: string,
481): Effect.Effect<Record<string, unknown>, OpenApiParseError> =>485): Effect.Effect<MicrosoftGraphOpenApiDocument, OpenApiParseError> =>
482 Effect.gen(function* () {486 Effect.gen(function* () {
483 const parsed = yield* Effect.try({487 const parsed = yield* Effect.try({
484 try: () => YAML.parse(specText) as unknown,488 try: () => YAML.parse(specText) as unknown,
@@ -492,11 +496,16 @@ const parseMicrosoftGraphOpenApiDocument = ( · 7 unmodified lines
492 message: "Microsoft Graph OpenAPI document must be an object",496 message: "Microsoft Graph OpenAPI document must be an object",
493 });497 });
494 }498 }
495 return parsed;499 if (typeof parsed.openapi !== "string" || !parsed.openapi.startsWith("3.")) {
500 return yield* new OpenApiParseError({
501 message: "Microsoft Graph OpenAPI document must be OpenAPI 3.x",
502 });
503 }
504 return parsed as MicrosoftGraphOpenApiDocument;
496 });505 });
497 506
498export const buildFilteredMicrosoftGraphOpenApiSpec = (507export const buildFilteredMicrosoftGraphOpenApiSpecFromDocument = (
499 specText: string,508 parsed: MicrosoftGraphOpenApiDocument,
500 options: {509 options: {
501 readonly scopes: readonly string[];510 readonly scopes: readonly string[];
502 readonly exactPaths: readonly string[];511 readonly exactPaths: readonly string[];
@@ -510,7 +519,6 @@ export const buildFilteredMicrosoftGraphOpenApiSpec = ( · 7 unmodified lines
510 },519 },
511): Effect.Effect<MicrosoftGraphFilterResult, OpenApiParseError> =>520): Effect.Effect<MicrosoftGraphFilterResult, OpenApiParseError> =>
512 Effect.gen(function* () {521 Effect.gen(function* () {
513 const parsed = yield* parseMicrosoftGraphOpenApiDocument(specText);
514 const paths = parsed.paths;522 const paths = parsed.paths;
515 if (!isRecord(paths)) {523 if (!isRecord(paths)) {
516 return yield* new OpenApiParseError({524 return yield* new OpenApiParseError({
@@ -578,6 +586,15 @@ export const buildFilteredMicrosoftGraphOpenApiSpec = ( · 61 unmodified lines
578 return { specText: filteredSpecText, scopes };586 return { specText: filteredSpecText, scopes };
579 });587 });
580 588
589export const buildFilteredMicrosoftGraphOpenApiSpec = (
590 specText: string,
591 options: Parameters<typeof buildFilteredMicrosoftGraphOpenApiSpecFromDocument>[1],
592): Effect.Effect<MicrosoftGraphFilterResult, OpenApiParseError> =>
593 Effect.gen(function* () {
594 const parsed = yield* parseMicrosoftGraphOpenApiDocument(specText);
595 return yield* buildFilteredMicrosoftGraphOpenApiSpecFromDocument(parsed, options);
596 });
597
581export const filterMicrosoftGraphOpenApiSpec = (598export const filterMicrosoftGraphOpenApiSpec = (
582 specText: string,599 specText: string,
583 options: Parameters<typeof buildFilteredMicrosoftGraphOpenApiSpec>[1],600 options: Parameters<typeof buildFilteredMicrosoftGraphOpenApiSpec>[1],
@@ -604,12 +621,32 @@ export const buildMicrosoftGraphOpenApiSpec = ( · 20 unmodified lines
604 : [];621 : [];
605 const parsed = yield* parseMicrosoftGraphOpenApiDocument(sourceText);622 const parsed = yield* parseMicrosoftGraphOpenApiDocument(sourceText);
606 const endpoints = resolveOAuthEndpoints(parsed, selection);623 const endpoints = resolveOAuthEndpoints(parsed, selection);
607 const filtered = yield* buildFilteredMicrosoftGraphOpenApiSpec(sourceText, {624 const graphPaths = parsed.paths;
625 if (!isRecord(graphPaths)) {
626 return yield* new OpenApiParseError({
627 message: "Microsoft Graph OpenAPI document is missing paths",
628 });
629 }
630 if (selection.coversFullGraph === true) {
631 const scopes = selectedOAuthScopesForPaths(
632 graphPaths,
633 uniqueStrings([...MICROSOFT_GRAPH_BASE_SCOPES, ...selection.customScopes]),
634 fullGraphScopes,
635 );
636 return {
637 ...selection,
638 specText: sourceText,
639 parsedDocument: parsed,
640 scopes,
641 authorizationUrl: endpoints.authorizationUrl,
642 tokenUrl: endpoints.tokenUrl,
643 clientCredentialsTokenUrl: endpoints.clientCredentialsTokenUrl,
644 authenticationTemplate: microsoftOAuthTemplate(scopes, endpoints),
645 };
646 }
647 const filtered = yield* buildFilteredMicrosoftGraphOpenApiSpecFromDocument(parsed, {
608 ...selection,648 ...selection,
609 scopes:649 scopes: selection.scopes,
610 selection.coversFullGraph === true
611 ? uniqueStrings([...MICROSOFT_GRAPH_BASE_SCOPES, ...selection.customScopes])
612 : selection.scopes,
613 fullGraphScopes,650 fullGraphScopes,
614 });651 });
615 return {652 return {
packages/plugins/microsoft/src/sdk/plugin.ts+9−2
@@ -18,6 +18,7 @@ import { · 17 unmodified lines
18} from "@executor-js/sdk/core";18} from "@executor-js/sdk/core";
19import { describeApiKeyAuthMethod } from "@executor-js/sdk/http-auth";19import { describeApiKeyAuthMethod } from "@executor-js/sdk/http-auth";
20import {20import {
21 compileOpenApiDocument,
21 compileOpenApiSpec,22 compileOpenApiSpec,
22 decodeOpenApiIntegrationConfig,23 decodeOpenApiIntegrationConfig,
23 invokeOpenApiBackedTool,24 invokeOpenApiBackedTool,
@@ -124,7 +125,10 @@ const makeMicrosoftPluginExtension = ( · 100 unmodified lines
124 const addGraph = (config: MicrosoftGraphConfig) =>125 const addGraph = (config: MicrosoftGraphConfig) =>
125 Effect.gen(function* () {126 Effect.gen(function* () {
126 const graph = yield* buildMicrosoftGraphOpenApiSpec(config, httpClientLayer);127 const graph = yield* buildMicrosoftGraphOpenApiSpec(config, httpClientLayer);
127 const compiled = yield* compileOpenApiSpec(graph.specText);128 const compiled =
129 graph.parsedDocument !== undefined
130 ? yield* compileOpenApiDocument(graph.parsedDocument)
131 : yield* compileOpenApiSpec(graph.specText);
128 const slug = IntegrationSlug.make(config.slug?.trim() || DEFAULT_MICROSOFT_SLUG);132 const slug = IntegrationSlug.make(config.slug?.trim() || DEFAULT_MICROSOFT_SLUG);
129 133
130 const existing = yield* ctx.core.integrations.get(slug);134 const existing = yield* ctx.core.integrations.get(slug);
@@ -195,7 +199,10 @@ const makeMicrosoftPluginExtension = ( · 64 unmodified lines
195 },199 },
196 httpClientLayer,200 httpClientLayer,
197 );201 );
198 const compiled = yield* compileOpenApiSpec(graph.specText);202 const compiled =
203 graph.parsedDocument !== undefined
204 ? yield* compileOpenApiDocument(graph.parsedDocument)
205 : yield* compileOpenApiSpec(graph.specText);
199 206
200 const previousOperations = yield* ctx.storage.listOperations(rawSlug);207 const previousOperations = yield* ctx.storage.listOperations(rawSlug);
201 const previousNames = new Set(previousOperations.map((op) => op.toolName));208 const previousNames = new Set(previousOperations.map((op) => op.toolName));