mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
fix(ui): fix canvas crash by rolling back swagger-parser (#3611)
The node polyfills needed to run the `swagger-parser` library (used to dereference the OpenAPI schema) cause the canvas tab to immediately crash when the package build is used in another react application. I'm sure this is fixable but it's not clear what is causing the issue and troubleshooting is very time consuming. Selectively rolling back the implementation of `swagger-parser`.
This commit is contained in:
commit
2b6c9c93e0
@ -3,12 +3,10 @@ import { visualizer } from 'rollup-plugin-visualizer';
|
||||
import { PluginOption, UserConfig } from 'vite';
|
||||
import eslint from 'vite-plugin-eslint';
|
||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||
import { nodePolyfills } from 'vite-plugin-node-polyfills';
|
||||
|
||||
export const commonPlugins: UserConfig['plugins'] = [
|
||||
react(),
|
||||
eslint(),
|
||||
tsconfigPaths(),
|
||||
visualizer() as unknown as PluginOption,
|
||||
nodePolyfills(),
|
||||
];
|
||||
|
@ -53,7 +53,6 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@apidevtools/swagger-parser": "^10.1.0",
|
||||
"@chakra-ui/anatomy": "^2.1.1",
|
||||
"@chakra-ui/icons": "^2.0.19",
|
||||
"@chakra-ui/react": "^2.7.1",
|
||||
@ -155,7 +154,6 @@
|
||||
"vite-plugin-css-injected-by-js": "^3.1.1",
|
||||
"vite-plugin-dts": "^2.3.0",
|
||||
"vite-plugin-eslint": "^1.8.1",
|
||||
"vite-plugin-node-polyfills": "^0.9.0",
|
||||
"vite-tsconfig-paths": "^4.2.0",
|
||||
"yarn": "^1.22.19"
|
||||
}
|
||||
|
@ -333,7 +333,7 @@ export type TypeHints = {
|
||||
};
|
||||
|
||||
export type InvocationSchemaExtra = {
|
||||
output: OpenAPIV3.SchemaObject; // the output of the invocation
|
||||
output: OpenAPIV3.ReferenceObject; // the output of the invocation
|
||||
ui?: {
|
||||
tags?: string[];
|
||||
type_hints?: TypeHints;
|
||||
|
@ -349,11 +349,21 @@ export const getFieldType = (
|
||||
|
||||
if (typeHints && name in typeHints) {
|
||||
rawFieldType = typeHints[name];
|
||||
} else if (!schemaObject.type && schemaObject.allOf) {
|
||||
// if schemaObject has no type, then it should have one of allOf
|
||||
rawFieldType =
|
||||
(schemaObject.allOf[0] as OpenAPIV3.SchemaObject).title ??
|
||||
'Missing Field Type';
|
||||
} else if (!schemaObject.type) {
|
||||
// if schemaObject has no type, then it should have one of allOf, anyOf, oneOf
|
||||
if (schemaObject.allOf) {
|
||||
rawFieldType = refObjectToFieldType(
|
||||
schemaObject.allOf![0] as OpenAPIV3.ReferenceObject
|
||||
);
|
||||
} else if (schemaObject.anyOf) {
|
||||
rawFieldType = refObjectToFieldType(
|
||||
schemaObject.anyOf![0] as OpenAPIV3.ReferenceObject
|
||||
);
|
||||
} else if (schemaObject.oneOf) {
|
||||
rawFieldType = refObjectToFieldType(
|
||||
schemaObject.oneOf![0] as OpenAPIV3.ReferenceObject
|
||||
);
|
||||
}
|
||||
} else if (schemaObject.enum) {
|
||||
rawFieldType = 'enum';
|
||||
} else if (schemaObject.type) {
|
||||
|
@ -5,48 +5,33 @@ import {
|
||||
InputFieldTemplate,
|
||||
InvocationSchemaObject,
|
||||
InvocationTemplate,
|
||||
isInvocationSchemaObject,
|
||||
OutputFieldTemplate,
|
||||
} from '../types/types';
|
||||
import { buildInputFieldTemplate, getFieldType } from './fieldTemplateBuilders';
|
||||
import { O } from 'ts-toolbelt';
|
||||
|
||||
// recursively exclude all properties of type U from T
|
||||
type DeepExclude<T, U> = T extends U
|
||||
? never
|
||||
: T extends object
|
||||
? {
|
||||
[K in keyof T]: DeepExclude<T[K], U>;
|
||||
}
|
||||
: T;
|
||||
|
||||
// The schema from swagger-parser is dereferenced, and we know `components` and `components.schemas` exist
|
||||
type DereferencedOpenAPIDocument = DeepExclude<
|
||||
O.Required<OpenAPIV3.Document, 'schemas' | 'components', 'deep'>,
|
||||
OpenAPIV3.ReferenceObject
|
||||
>;
|
||||
import {
|
||||
buildInputFieldTemplate,
|
||||
buildOutputFieldTemplates,
|
||||
} from './fieldTemplateBuilders';
|
||||
|
||||
const RESERVED_FIELD_NAMES = ['id', 'type', 'is_intermediate'];
|
||||
|
||||
const invocationDenylist = ['Graph', 'InvocationMeta'];
|
||||
|
||||
const nodeFilter = (
|
||||
schema: DereferencedOpenAPIDocument['components']['schemas'][string],
|
||||
key: string
|
||||
) =>
|
||||
export const parseSchema = (openAPI: OpenAPIV3.Document) => {
|
||||
// filter out non-invocation schemas, plus some tricky invocations for now
|
||||
const filteredSchemas = filter(
|
||||
openAPI.components!.schemas,
|
||||
(schema, key) =>
|
||||
key.includes('Invocation') &&
|
||||
!key.includes('InvocationOutput') &&
|
||||
!invocationDenylist.some((denylistItem) => key.includes(denylistItem));
|
||||
|
||||
export const parseSchema = (openAPI: DereferencedOpenAPIDocument) => {
|
||||
// filter out non-invocation schemas, plus some tricky invocations for now
|
||||
const filteredSchemas = filter(openAPI.components.schemas, nodeFilter);
|
||||
!invocationDenylist.some((denylistItem) => key.includes(denylistItem))
|
||||
) as (OpenAPIV3.ReferenceObject | InvocationSchemaObject)[];
|
||||
|
||||
const invocations = filteredSchemas.reduce<
|
||||
Record<string, InvocationTemplate>
|
||||
>((acc, s) => {
|
||||
// cast to InvocationSchemaObject, we know the shape
|
||||
const schema = s as InvocationSchemaObject;
|
||||
|
||||
>((acc, schema) => {
|
||||
// only want SchemaObjects
|
||||
if (isInvocationSchemaObject(schema)) {
|
||||
const type = schema.properties.type.default;
|
||||
|
||||
const title = schema.ui?.title ?? schema.title.replace('Invocation', '');
|
||||
@ -56,8 +41,10 @@ export const parseSchema = (openAPI: DereferencedOpenAPIDocument) => {
|
||||
const inputs: Record<string, InputFieldTemplate> = {};
|
||||
|
||||
if (type === 'collect') {
|
||||
// Special handling for the Collect node
|
||||
const itemProperty = schema.properties['item'] as InvocationSchemaObject;
|
||||
const itemProperty = schema.properties[
|
||||
'item'
|
||||
] as InvocationSchemaObject;
|
||||
// Handle the special Collect node
|
||||
inputs.item = {
|
||||
type: 'item',
|
||||
name: 'item',
|
||||
@ -68,7 +55,6 @@ export const parseSchema = (openAPI: DereferencedOpenAPIDocument) => {
|
||||
default: undefined,
|
||||
};
|
||||
} else if (type === 'iterate') {
|
||||
// Special handling for the Iterate node
|
||||
const itemProperty = schema.properties[
|
||||
'collection'
|
||||
] as InvocationSchemaObject;
|
||||
@ -105,12 +91,16 @@ export const parseSchema = (openAPI: DereferencedOpenAPIDocument) => {
|
||||
);
|
||||
}
|
||||
|
||||
const rawOutput = (schema as InvocationSchemaObject).output;
|
||||
|
||||
let outputs: Record<string, OutputFieldTemplate>;
|
||||
|
||||
// some special handling is needed for collect, iterate and range nodes
|
||||
if (type === 'iterate') {
|
||||
// Special handling for the Iterate node output
|
||||
const iterationOutput =
|
||||
openAPI.components.schemas['IterateInvocationOutput'];
|
||||
// this is guaranteed to be a SchemaObject
|
||||
const iterationOutput = openAPI.components!.schemas![
|
||||
'IterateInvocationOutput'
|
||||
] as OpenAPIV3.SchemaObject;
|
||||
|
||||
outputs = {
|
||||
item: {
|
||||
@ -121,25 +111,7 @@ export const parseSchema = (openAPI: DereferencedOpenAPIDocument) => {
|
||||
},
|
||||
};
|
||||
} else {
|
||||
// All other node outputs
|
||||
outputs = reduce(
|
||||
schema.output.properties as OpenAPIV3.SchemaObject,
|
||||
(outputsAccumulator, property, propertyName) => {
|
||||
if (!['type', 'id'].includes(propertyName)) {
|
||||
const fieldType = getFieldType(property, propertyName, typeHints);
|
||||
|
||||
outputsAccumulator[propertyName] = {
|
||||
name: propertyName,
|
||||
title: property.title ?? '',
|
||||
description: property.description ?? '',
|
||||
type: fieldType,
|
||||
};
|
||||
}
|
||||
|
||||
return outputsAccumulator;
|
||||
},
|
||||
{} as Record<string, OutputFieldTemplate>
|
||||
);
|
||||
outputs = buildOutputFieldTemplates(rawOutput, openAPI, typeHints);
|
||||
}
|
||||
|
||||
const invocation: InvocationTemplate = {
|
||||
@ -152,6 +124,7 @@ export const parseSchema = (openAPI: DereferencedOpenAPIDocument) => {
|
||||
};
|
||||
|
||||
Object.assign(acc, { [type]: invocation });
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
|
@ -1,7 +1,5 @@
|
||||
import SwaggerParser from '@apidevtools/swagger-parser';
|
||||
import { createAsyncThunk } from '@reduxjs/toolkit';
|
||||
import { log } from 'app/logging/useLogger';
|
||||
import { OpenAPIV3 } from 'openapi-types';
|
||||
|
||||
const schemaLog = log.child({ namespace: 'schema' });
|
||||
|
||||
@ -29,12 +27,13 @@ export const receivedOpenAPISchema = createAsyncThunk(
|
||||
'nodes/receivedOpenAPISchema',
|
||||
async (_, { dispatch, rejectWithValue }) => {
|
||||
try {
|
||||
const dereferencedSchema = (await SwaggerParser.dereference(
|
||||
'openapi.json'
|
||||
)) as OpenAPIV3.Document;
|
||||
const response = await fetch(`openapi.json`);
|
||||
const openAPISchema = await response.json();
|
||||
|
||||
schemaLog.info({ openAPISchema }, 'Received OpenAPI schema');
|
||||
|
||||
const schemaJSON = JSON.parse(
|
||||
JSON.stringify(dereferencedSchema, getCircularReplacer())
|
||||
JSON.stringify(openAPISchema, getCircularReplacer())
|
||||
);
|
||||
|
||||
return schemaJSON;
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user