diff --git a/frontend/src/lib/components/DBSchemaExplorer.svelte b/frontend/src/lib/components/DBSchemaExplorer.svelte index b1fc1a60da..d403c42e77 100644 --- a/frontend/src/lib/components/DBSchemaExplorer.svelte +++ b/frontend/src/lib/components/DBSchemaExplorer.svelte @@ -32,10 +32,10 @@ {/if} {#if dbSchema.lang === 'graphql'} - {#await import('$lib/components/GraphqlSchemaViewer.svelte')} + {#await Promise.all([import('$lib/components/GraphqlSchemaViewer.svelte'), formatGraphqlSchema(dbSchema.schema)])} - {:then Module} - + {:then [Module, code]} + {/await} {:else} diff --git a/frontend/src/lib/components/apps/components/display/dbtable/metadata.ts b/frontend/src/lib/components/apps/components/display/dbtable/metadata.ts index 840a7a71d9..a44cab88fa 100644 --- a/frontend/src/lib/components/apps/components/display/dbtable/metadata.ts +++ b/frontend/src/lib/components/apps/components/display/dbtable/metadata.ts @@ -13,7 +13,7 @@ import { import { type Preview } from '$lib/gen' import type { DBSchema, GraphqlSchema, SQLSchema } from '$lib/stores' -import { stringifySchema } from '$lib/components/copilot/lib' +import { stringifyGraphqlSchema, stringifySchema } from '$lib/components/copilot/lib' import type { DbType } from '$lib/components/dbTypes' import { getDatabaseArg } from '$lib/components/dbOps' @@ -416,7 +416,7 @@ export async function getDbSchemas( workspace, requestBody: { language: sqlScript.lang as Preview['language'], - content: sqlScript.code, + content: typeof sqlScript.code === 'function' ? await sqlScript.code() : sqlScript.code, tag: options.customTag, args: { [sqlScript.argName]: resourcePath.startsWith('datatable://') @@ -458,7 +458,10 @@ export async function getDbSchemas( lang: 'graphql' as GraphqlSchema['lang'], schema: result } - return { ...(dbSchema as any), stringified: stringifySchema(dbSchema as any) } + return { + ...(dbSchema as any), + stringified: await stringifyGraphqlSchema(result) + } } } } diff --git a/frontend/src/lib/components/apps/components/display/dbtable/utils.ts b/frontend/src/lib/components/apps/components/display/dbtable/utils.ts index 961fac9b5b..ee30619366 100644 --- a/frontend/src/lib/components/apps/components/display/dbtable/utils.ts +++ b/frontend/src/lib/components/apps/components/display/dbtable/utils.ts @@ -1,11 +1,6 @@ import type { ScriptLang } from '$lib/gen' import type { SQLSchema } from '$lib/stores' -import { - buildClientSchema, - getIntrospectionQuery, - printSchema, - type IntrospectionQuery -} from 'graphql' +import type { IntrospectionQuery } from 'graphql' import type { DbType } from '$lib/components/dbTypes' @@ -64,7 +59,7 @@ export function resourceTypeToLang(rt: string) { const legacyScripts: Record< string, { - code: string + code: string | (() => Promise) lang: string processingFn?: (any: any) => SQLSchema['schema'] argName: string @@ -146,7 +141,7 @@ const legacyScripts: Record< argName: 'database' }, graphql: { - code: getIntrospectionQuery(), + code: () => import('graphql').then((m) => m.getIntrospectionQuery()), lang: 'graphql', argName: 'api' }, @@ -305,7 +300,8 @@ export function formatSchema(dbSchema: { } } -export function formatGraphqlSchema(schema: IntrospectionQuery): string { +export async function formatGraphqlSchema(schema: IntrospectionQuery): Promise { + const { buildClientSchema, printSchema } = await import('graphql') return printSchema(buildClientSchema(schema)) } diff --git a/frontend/src/lib/components/apps/editor/appPolicy.ts b/frontend/src/lib/components/apps/editor/appPolicy.ts index afa6962361..ee1f29babd 100644 --- a/frontend/src/lib/components/apps/editor/appPolicy.ts +++ b/frontend/src/lib/components/apps/editor/appPolicy.ts @@ -1,4 +1,3 @@ -import { Sha256 } from '@aws-crypto/sha256-js' import { getCountInput } from '../components/display/dbtable/queries/count' import { getDeleteInput } from '../components/display/dbtable/queries/delete' import { getInsertInput } from '../components/display/dbtable/queries/insert' @@ -236,6 +235,7 @@ async function hash(message) { return hashHex } catch { //subtle not available, trying pure js + const { Sha256 } = await import('@aws-crypto/sha256-js') const hash = new Sha256() hash.update(message ?? '') const result = Array.from(await hash.digest()) diff --git a/frontend/src/lib/components/apps/editor/commonAppUtils.ts b/frontend/src/lib/components/apps/editor/commonAppUtils.ts index 6cc5fbb3b4..3dc4139295 100644 --- a/frontend/src/lib/components/apps/editor/commonAppUtils.ts +++ b/frontend/src/lib/components/apps/editor/commonAppUtils.ts @@ -1,37 +1,35 @@ -import type { StaticAppInput } from "../inputType" -import { Sha256 } from '@aws-crypto/sha256-js' +import type { StaticAppInput } from '../inputType' -export function collectStaticFields( - fields: Record -) { - return Object.fromEntries( - Object.entries(fields ?? {}) - .filter(([k, v]) => v.type == 'static') - .map(([k, v]) => { - return [k, v['value']] - }) - ) +export function collectStaticFields(fields: Record) { + return Object.fromEntries( + Object.entries(fields ?? {}) + .filter(([k, v]) => v.type == 'static') + .map(([k, v]) => { + return [k, v['value']] + }) + ) } export type TriggerableV2 = { - static_inputs: Record - one_of_inputs?: Record - allow_user_resources?: string[] + static_inputs: Record + one_of_inputs?: Record + allow_user_resources?: string[] } export async function hash(message) { - try { - const msgUint8 = new TextEncoder().encode(message) // encode as (utf-8) Uint8Array - const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8) // hash the message - const hashArray = Array.from(new Uint8Array(hashBuffer)) // convert buffer to byte array - const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('') // convert bytes to hex string - return hashHex - } catch { - //subtle not available, trying pure js - const hash = new Sha256() - hash.update(message ?? '') - const result = Array.from(await hash.digest()) - const hex = result.map((b) => b.toString(16).padStart(2, '0')).join('') // convert bytes to hex string - return hex - } -} \ No newline at end of file + try { + const msgUint8 = new TextEncoder().encode(message) // encode as (utf-8) Uint8Array + const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8) // hash the message + const hashArray = Array.from(new Uint8Array(hashBuffer)) // convert buffer to byte array + const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('') // convert bytes to hex string + return hashHex + } catch { + //subtle not available, trying pure js + const { Sha256 } = await import('@aws-crypto/sha256-js') + const hash = new Sha256() + hash.update(message ?? '') + const result = Array.from(await hash.digest()) + const hex = result.map((b) => b.toString(16).padStart(2, '0')).join('') // convert bytes to hex string + return hex + } +} diff --git a/frontend/src/lib/components/copilot/chat/ContextElementBadge.svelte b/frontend/src/lib/components/copilot/chat/ContextElementBadge.svelte index 186414c8dd..f30bdbe48f 100644 --- a/frontend/src/lib/components/copilot/chat/ContextElementBadge.svelte +++ b/frontend/src/lib/components/copilot/chat/ContextElementBadge.svelte @@ -64,13 +64,10 @@ {:else if contextElement.type === 'db'}
{#if contextElement.schema && contextElement.schema.lang === 'graphql'} - {#await import('$lib/components/GraphqlSchemaViewer.svelte')} + {#await Promise.all([import('$lib/components/GraphqlSchemaViewer.svelte'), formatGraphqlSchema(contextElement.schema.schema)])} - {:then Module} - + {:then [Module, code]} + {/await} {:else if contextElement.schema} diff --git a/frontend/src/lib/components/copilot/lib.ts b/frontend/src/lib/components/copilot/lib.ts index 538ab2a103..4d77ebd01a 100644 --- a/frontend/src/lib/components/copilot/lib.ts +++ b/frontend/src/lib/components/copilot/lib.ts @@ -1,6 +1,6 @@ import type { AIProvider, AIProviderModel } from '$lib/gen' -import { workspaceStore, type DBSchema, type GraphqlSchema, type SQLSchema } from '$lib/stores' -import { buildClientSchema, printSchema } from 'graphql' +import { workspaceStore, type DBSchema, type SQLSchema } from '$lib/stores' +import type { IntrospectionQuery } from 'graphql' import OpenAI from 'openai' import type { ChatCompletionChunk, @@ -587,43 +587,40 @@ export function addThousandsSeparator(n: number) { return n.toFixed().replace(/\B(?=(\d{3})+(?!\d))/g, "'") } -export function stringifySchema( - dbSchema: Omit | Omit -) { +export function stringifySchema(dbSchema: Omit): string { const { schema, lang } = dbSchema - if (lang === 'graphql') { - let graphqlSchema = printSchema(buildClientSchema(schema)) - return graphqlSchema - } else { - let smallerSchema: { - [schemaKey: string]: { - [tableKey: string]: Array<[string, string, boolean, string?]> - } - } = {} - for (const schemaKey in schema) { - smallerSchema[schemaKey] = {} - for (const tableKey in schema[schemaKey]) { - smallerSchema[schemaKey][tableKey] = [] - for (const colKey in schema[schemaKey][tableKey]) { - const col = schema[schemaKey][tableKey][colKey] - const p: [string, string, boolean, string?] = [colKey, col.type, col.required] - if (col.default) { - p.push(col.default) - } - smallerSchema[schemaKey][tableKey].push(p) + let smallerSchema: { + [schemaKey: string]: { + [tableKey: string]: Array<[string, string, boolean, string?]> + } + } = {} + for (const schemaKey in schema) { + smallerSchema[schemaKey] = {} + for (const tableKey in schema[schemaKey]) { + smallerSchema[schemaKey][tableKey] = [] + for (const colKey in schema[schemaKey][tableKey]) { + const col = schema[schemaKey][tableKey][colKey] + const p: [string, string, boolean, string?] = [colKey, col.type, col.required] + if (col.default) { + p.push(col.default) } + smallerSchema[schemaKey][tableKey].push(p) } } - - let finalSchema: typeof smallerSchema | (typeof smallerSchema)['schemaKey'] = smallerSchema - if (dbSchema.publicOnly) { - finalSchema = - smallerSchema.public || smallerSchema.PUBLIC || smallerSchema.dbo || smallerSchema - } else if (lang === 'mysql' && Object.keys(smallerSchema).length === 1) { - finalSchema = smallerSchema[Object.keys(smallerSchema)[0]] - } - return JSON.stringify(finalSchema) } + + let finalSchema: typeof smallerSchema | (typeof smallerSchema)['schemaKey'] = smallerSchema + if (dbSchema.publicOnly) { + finalSchema = smallerSchema.public || smallerSchema.PUBLIC || smallerSchema.dbo || smallerSchema + } else if (lang === 'mysql' && Object.keys(smallerSchema).length === 1) { + finalSchema = smallerSchema[Object.keys(smallerSchema)[0]] + } + return JSON.stringify(finalSchema) +} + +export async function stringifyGraphqlSchema(schema: unknown): Promise { + const { buildClientSchema, printSchema } = await import('graphql') + return printSchema(buildClientSchema(schema as IntrospectionQuery)) } function addDBSChema(scriptOptions: CopilotOptions, prompt: string) { diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts index 3fa1b3256a..1cf01ba344 100644 --- a/frontend/src/lib/utils.ts +++ b/frontend/src/lib/utils.ts @@ -17,8 +17,6 @@ export { sendUserToast } import type { AnyMeltElement } from '@melt-ui/svelte' import type { TriggerKind } from './components/triggers' import { stateSnapshot } from './svelte5Utils.svelte' -import { validate, dereference } from '@scalar/openapi-parser' - export namespace OpenApi { export enum OpenApiVersion { V2, @@ -59,6 +57,7 @@ export namespace OpenApi { * @throws Will throw an error if the specification is invalid or cannot be parsed. */ export async function parse(api: string): Promise<[OpenAPI.Document, OpenApiVersion]> { + const { validate, dereference } = await import('@scalar/openapi-parser') const { valid, errors } = await validate(api) if (!valid) {