perf: lazy-load heavy deps (graphql, openapi-parser, sha256) (#8145)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Ruben Fiszel
2026-02-28 09:11:00 +00:00
committed by GitHub
co-authored by Claude Opus 4.6
parent 3daf79efad
commit fcafc3b133
8 changed files with 78 additions and 88 deletions
@@ -32,10 +32,10 @@
</ToggleButtonGroup>
{/if}
{#if dbSchema.lang === 'graphql'}
{#await import('$lib/components/GraphqlSchemaViewer.svelte')}
{#await Promise.all([import('$lib/components/GraphqlSchemaViewer.svelte'), formatGraphqlSchema(dbSchema.schema)])}
<Loader2 class="animate-spin" />
{:then Module}
<Module.default code={formatGraphqlSchema(dbSchema.schema)} class="h-full" />
{:then [Module, code]}
<Module.default {code} class="h-full" />
{/await}
{:else}
<ObjectViewer json={formatSchema(dbSchema)} pureViewer collapseLevel={1} />
@@ -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)
}
}
}
}
@@ -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<string>)
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<string> {
const { buildClientSchema, printSchema } = await import('graphql')
return printSchema(buildClientSchema(schema))
}
@@ -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())
@@ -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<string, StaticAppInput>
) {
return Object.fromEntries(
Object.entries(fields ?? {})
.filter(([k, v]) => v.type == 'static')
.map(([k, v]) => {
return [k, v['value']]
})
)
export function collectStaticFields(fields: Record<string, StaticAppInput>) {
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<string, any>
one_of_inputs?: Record<string, any[] | undefined>
allow_user_resources?: string[]
static_inputs: Record<string, any>
one_of_inputs?: Record<string, any[] | undefined>
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
}
}
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
}
}
@@ -64,13 +64,10 @@
{:else if contextElement.type === 'db'}
<div class="p-2 max-w-96 max-h-[300px] text-xs overflow-auto">
{#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)])}
<Loader2 class="animate-spin" />
{:then Module}
<Module.default
code={formatGraphqlSchema(contextElement.schema.schema)}
class="h-full"
/>
{:then [Module, code]}
<Module.default {code} class="h-full" />
{/await}
{:else if contextElement.schema}
<ObjectViewer json={formatSchema(contextElement.schema)} pureViewer collapseLevel={1} />
+31 -34
View File
@@ -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<SQLSchema, 'stringified'> | Omit<GraphqlSchema, 'stringified'>
) {
export function stringifySchema(dbSchema: Omit<SQLSchema, 'stringified'>): 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<string> {
const { buildClientSchema, printSchema } = await import('graphql')
return printSchema(buildClientSchema(schema as IntrospectionQuery))
}
function addDBSChema(scriptOptions: CopilotOptions, prompt: string) {
+1 -2
View File
@@ -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) {