From df508fc047d4da81b69d34332e103e4cfa988305 Mon Sep 17 00:00:00 2001 From: Neko Ayaka Date: Tue, 7 Oct 2025 23:43:39 +0800 Subject: [PATCH] feat(injecta): logger support for easier debugging --- packages/injecta/package.json | 3 + packages/injecta/src/global.ts | 6 +- packages/injecta/src/index.ts | 11 ++- packages/injecta/src/logger.ts | 139 +++++++++++++++++++++++++++++++ packages/injecta/src/scoped.ts | 48 +++++++++-- pnpm-lock.yaml | 146 ++++++--------------------------- pnpm-workspace.yaml | 2 +- 7 files changed, 223 insertions(+), 132 deletions(-) create mode 100644 packages/injecta/src/logger.ts diff --git a/packages/injecta/package.json b/packages/injecta/package.json index 3e528c13b..855bfb939 100644 --- a/packages/injecta/package.json +++ b/packages/injecta/package.json @@ -23,5 +23,8 @@ "scripts": { "typecheck": "tsc --noEmit", "build": "tsdown" + }, + "dependencies": { + "@guiiai/logg": "catalog:" } } diff --git a/packages/injecta/src/global.ts b/packages/injecta/src/global.ts index b796de50d..1658993ac 100644 --- a/packages/injecta/src/global.ts +++ b/packages/injecta/src/global.ts @@ -1,9 +1,13 @@ -import type { DependencyMap, InvokeOption, ProvideOption } from '.' +import type { DependencyMap, InvokeOption, Logger, ProvideOption } from '.' import { createContainer, provide as indexProvide, start as indexStart, stop as indexStop } from '.' const globalContainer = createContainer() +export function setLogger(logger: Logger) { + globalContainer.logger = logger +} + export function provide( name: string, option: ProvideOption, diff --git a/packages/injecta/src/index.ts b/packages/injecta/src/index.ts index 9585829be..534a50e1d 100644 --- a/packages/injecta/src/index.ts +++ b/packages/injecta/src/index.ts @@ -1,12 +1,21 @@ import { invoke as globalInvoke, provide as globalProvide, + setLogger as globalSetLogger, start as globalStart, stop as globalStop, } from './global' export type { Lifecycle } from './builtin' +export type { Logger, LoggerOptions } from './logger' + +export { + createDefaultLogger, + createLoggLogger, + createNoopLogger, +} from './logger' + export { createContainer, invoke, @@ -14,7 +23,6 @@ export { start, stop, } from './scoped' - export type { BuildContext, Container, @@ -32,4 +40,5 @@ export const injecta = { invoke: globalInvoke, start: globalStart, stop: globalStop, + setLogger: globalSetLogger, } diff --git a/packages/injecta/src/logger.ts b/packages/injecta/src/logger.ts new file mode 100644 index 000000000..66cad8702 --- /dev/null +++ b/packages/injecta/src/logger.ts @@ -0,0 +1,139 @@ +import { useLogg } from '@guiiai/logg' + +import { name } from '../package.json' + +export interface Logger { + provide: (name: string, dependencies: string[]) => void + invoke: (dependencies: string[]) => void + beforeRun: (name: string) => void + run: (name: string, duration: number) => void + hookOnStart: (name: string) => void + hookOnStartComplete: (name: string, duration: number) => void + hookOnStop: (name: string) => void + hookOnStopComplete: (name: string, duration: number) => void + running: () => void +} + +export interface LoggerOptions { + enabled?: boolean + logger?: Logger +} + +function formatDuration(ms: number): string { + if (ms < 1) { + return `${(ms * 1000).toFixed(3)}µs` + } + if (ms < 1000) { + return `${ms.toFixed(3)}ms` + } + return `${(ms / 1000).toFixed(3)}s` +} + +export function createDefaultLogger(): Logger { + return { + provide: (name: string, dependencies: string[]) => { + const depsStr = dependencies.length > 0 ? ` (depends on: ${dependencies.join(', ')})` : '' + // eslint-disable-next-line no-console + console.log(`[${name}] PROVIDE ${name}${depsStr}`) + }, + + invoke: (dependencies: string[]) => { + const depsStr = dependencies.length > 0 ? ` (depends on: ${dependencies.join(', ')})` : '' + // eslint-disable-next-line no-console + console.log(`[${name}] INVOKE${depsStr}`) + }, + + beforeRun: (name: string) => { + // eslint-disable-next-line no-console + console.log(`[${name}] BEFORE RUN provide: ${name}()`) + }, + + run: (name: string, duration: number) => { + // eslint-disable-next-line no-console + console.log(`[${name}] RUN provide: ${name}() in ${formatDuration(duration)}`) + }, + + hookOnStart: (name: string) => { + // eslint-disable-next-line no-console + console.log(`[${name}] HOOK OnStart ${name}() executing`) + }, + + hookOnStartComplete: (name: string, duration: number) => { + // eslint-disable-next-line no-console + console.log(`[${name}] HOOK OnStart ${name}() ran successfully in ${formatDuration(duration)}`) + }, + + hookOnStop: (name: string) => { + // eslint-disable-next-line no-console + console.log(`[${name}] HOOK OnStop ${name}() executing`) + }, + + hookOnStopComplete: (name: string, duration: number) => { + // eslint-disable-next-line no-console + console.log(`[${name}] HOOK OnStop ${name}() ran successfully in ${formatDuration(duration)}`) + }, + + running: () => { + // eslint-disable-next-line no-console + console.log(`[${name}] RUNNING`) + }, + } +} + +export function createLoggLogger(): Logger { + const logg = useLogg(name).useGlobalConfig() + + return { + provide: (name: string, dependencies: string[]) => { + const depsStr = dependencies.length > 0 ? ` (depends on: ${dependencies.join(', ')})` : '' + logg.log(`PROVIDE ${name}${depsStr}`) + }, + + invoke: (dependencies: string[]) => { + const depsStr = dependencies.length > 0 ? ` (depends on: ${dependencies.join(', ')})` : '' + logg.log(`INVOKE${depsStr}`) + }, + + beforeRun: (name: string) => { + logg.log(`BEFORE RUN provide: ${name}()`) + }, + + run: (name: string, duration: number) => { + logg.log(`RUN provide: ${name}() in ${formatDuration(duration)}`) + }, + + hookOnStart: (name: string) => { + logg.log(`HOOK OnStart ${name}() executing`) + }, + + hookOnStartComplete: (name: string, duration: number) => { + logg.log(`HOOK OnStart ${name}() ran successfully in ${formatDuration(duration)}`) + }, + + hookOnStop: (name: string) => { + logg.log(`HOOK OnStop ${name}() executing`) + }, + + hookOnStopComplete: (name: string, duration: number) => { + logg.log(`HOOK OnStop ${name}() ran successfully in ${formatDuration(duration)}`) + }, + + running: () => { + logg.log(`RUNNING`) + }, + } +} + +export function createNoopLogger(): Logger { + return { + provide: () => {}, + invoke: () => {}, + beforeRun: () => {}, + run: () => {}, + hookOnStart: () => {}, + hookOnStartComplete: () => {}, + hookOnStop: () => {}, + hookOnStopComplete: () => {}, + running: () => {}, + } +} diff --git a/packages/injecta/src/scoped.ts b/packages/injecta/src/scoped.ts index 3eddaf2e6..6e7263423 100644 --- a/packages/injecta/src/scoped.ts +++ b/packages/injecta/src/scoped.ts @@ -1,4 +1,7 @@ import type { LifecycleTriggerable } from './builtin' +import type { Logger, LoggerOptions } from './logger' + +import { createDefaultLogger, createNoopLogger } from './logger' export type DependencyMap = Record @@ -8,6 +11,7 @@ export interface Container { lifecycleHooks: Map dependencyGraph: Map invocations: InvokeOptionObject[] + logger: Logger } export type BuildContext = { @@ -23,13 +27,18 @@ export type InvokeOptionObject export type InvokeOptionFunc = (dependencies: D) => void | Promise export type InvokeOption = InvokeOptionObject | InvokeOptionFunc -export function createContainer(): Container { +export function createContainer(options?: LoggerOptions): Container { + const logger = options?.enabled === false + ? createNoopLogger() + : (options?.logger ?? createDefaultLogger()) + return { providers: new Map(), instances: new Map(), lifecycleHooks: new Map(), dependencyGraph: new Map(), invocations: [], + logger, } } @@ -46,16 +55,20 @@ export function provide( // Track dependencies for lifecycle ordering const dependencies = providerObject.dependsOn ? Object.values(providerObject.dependsOn) : [] + + container.logger.provide(name, dependencies) container.dependencyGraph.set(name, dependencies) } export function invoke(container: Container, option: InvokeOption): void { - if (typeof option === 'function') { - container.invocations.push({ callback: option } as InvokeOptionObject) - } - else { - container.invocations.push(option as InvokeOptionObject) - } + const invocationObject = typeof option === 'function' + ? { callback: option } as InvokeOptionObject + : option as InvokeOptionObject + + const dependencies = invocationObject.dependsOn ? Object.values(invocationObject.dependsOn) : [] + + container.logger.invoke(dependencies) + container.invocations.push(invocationObject) } async function resolveInstance(container: Container, name: string): Promise { @@ -93,7 +106,14 @@ async function resolveInstance(container: Container, name: string): Promise { for (const serviceName of sortedServices) { const lifecycle = container.lifecycleHooks.get(serviceName) if (lifecycle?.emitOnStart) { + container.logger.hookOnStart(serviceName) + + const startTime = performance.now() await lifecycle.emitOnStart() + const duration = performance.now() - startTime + + container.logger.hookOnStartComplete(serviceName, duration) } } } @@ -149,7 +175,13 @@ export async function stopLifecycleHooks(container: Container): Promise { for (const serviceName of sortedServices.reverse()) { const lifecycle = container.lifecycleHooks.get(serviceName) if (lifecycle?.emitOnStop) { + container.logger.hookOnStop(serviceName) + + const startTime = performance.now() await lifecycle.emitOnStop() + const duration = performance.now() - startTime + + container.logger.hookOnStopComplete(serviceName, duration) } } } @@ -168,6 +200,8 @@ export async function start(container: Container): Promise { await invocation.callback(resolvedDependencies) } + + container.logger.running() } export async function stop(container: Container): Promise { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4a5d0065d..5149451f5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,7 +7,7 @@ settings: catalogs: default: '@guiiai/logg': - specifier: ^1.1.0 + specifier: 1.1.0 version: 1.1.0 '@moeru/std': specifier: 0.1.0-beta.7 @@ -1133,9 +1133,13 @@ importers: devDependencies: unplugin-yaml: specifier: ^3.0.6 - version: 3.0.6(@nuxt/kit@4.0.3(magicast@0.3.5))(@nuxt/schema@4.0.3)(astro@5.10.1(@netlify/blobs@9.1.2)(@types/node@24.6.2)(db0@0.3.2(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(gel@2.0.0)(pg@8.16.3)(postgres@3.4.7)))(ioredis@5.7.0)(jiti@2.5.1)(less@4.4.1)(lightningcss@1.30.2)(rollup@4.52.4)(terser@5.43.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))(esbuild@0.25.9)(rolldown@1.0.0-beta.42)(rollup@4.52.4)(vite@7.1.9(@types/node@24.6.2)(jiti@2.5.1)(less@4.4.1)(lightningcss@1.30.2)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1)) + version: 3.0.6(@nuxt/kit@4.0.3(magicast@0.3.5))(@nuxt/schema@4.0.3)(astro@5.10.1(@netlify/blobs@9.1.2)(@types/node@24.6.2)(db0@0.3.2(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(gel@2.0.0)(pg@8.16.3)(postgres@3.4.7)))(encoding@0.1.13)(ioredis@5.7.0)(jiti@2.5.1)(less@4.4.1)(lightningcss@1.30.2)(rollup@4.52.4)(terser@5.43.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))(esbuild@0.25.9)(rolldown@1.0.0-beta.42)(rollup@4.52.4)(vite@7.1.9(@types/node@24.6.2)(jiti@2.5.1)(less@4.4.1)(lightningcss@1.30.2)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1)) - packages/injecta: {} + packages/injecta: + dependencies: + '@guiiai/logg': + specifier: 'catalog:' + version: 1.1.0 packages/memory-pgvector: dependencies: @@ -1773,7 +1777,7 @@ importers: version: rolldown-vite@7.1.15(@types/node@24.6.2)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1) vite-plugin-vue-devtools: specifier: ^8.0.2 - version: 8.0.2(@nuxt/kit@4.0.3(magicast@0.3.5))(rolldown-vite@7.1.15(@types/node@24.6.2)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3)) + version: 8.0.2(rolldown-vite@7.1.15(@types/node@24.6.2)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3)) vue-router: specifier: ^4.5.1 version: 4.5.1(vue@3.5.22(typescript@5.9.3)) @@ -1807,7 +1811,7 @@ importers: version: rolldown-vite@7.1.15(@types/node@24.6.2)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1) vite-plugin-vue-devtools: specifier: ^8.0.2 - version: 8.0.2(@nuxt/kit@4.0.3(magicast@0.3.5))(rolldown-vite@7.1.15(@types/node@24.6.2)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3)) + version: 8.0.2(rolldown-vite@7.1.15(@types/node@24.6.2)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3)) vue-router: specifier: ^4.5.1 version: 4.5.1(vue@3.5.22(typescript@5.9.3)) @@ -23457,108 +23461,6 @@ snapshots: - yaml optional: true - astro@5.10.1(@netlify/blobs@9.1.2)(@types/node@24.6.2)(db0@0.3.2(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(gel@2.0.0)(pg@8.16.3)(postgres@3.4.7)))(ioredis@5.7.0)(jiti@2.5.1)(less@4.4.1)(lightningcss@1.30.2)(rollup@4.52.4)(terser@5.43.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1): - dependencies: - '@astrojs/compiler': 2.12.2 - '@astrojs/internal-helpers': 0.6.1 - '@astrojs/markdown-remark': 6.3.2 - '@astrojs/telemetry': 3.3.0 - '@capsizecss/unpack': 2.4.0(encoding@0.1.13) - '@oslojs/encoding': 1.1.0 - '@rollup/pluginutils': 5.3.0(rollup@4.52.4) - acorn: 8.15.0 - aria-query: 5.3.2 - axobject-query: 4.1.0 - boxen: 8.0.1 - ci-info: 4.3.0 - clsx: 2.1.1 - common-ancestor-path: 1.0.1 - cookie: 1.0.2 - cssesc: 3.0.0 - debug: 4.4.3 - deterministic-object-hash: 2.0.2 - devalue: 5.3.2 - diff: 5.2.0 - dlv: 1.1.3 - dset: 3.1.4 - es-module-lexer: 1.7.0 - esbuild: 0.25.9 - estree-walker: 3.0.3 - flattie: 1.1.1 - fontace: 0.3.0 - github-slugger: 2.0.0 - html-escaper: 3.0.3 - http-cache-semantics: 4.2.0 - import-meta-resolve: 4.2.0 - js-yaml: 4.1.0 - kleur: 4.1.5 - magic-string: 0.30.19 - magicast: 0.3.5 - mrmime: 2.0.1 - neotraverse: 0.6.18 - p-limit: 6.2.0 - p-queue: 8.1.0 - package-manager-detector: 1.3.0 - picomatch: 4.0.3 - prompts: 2.4.2 - rehype: 13.0.2 - semver: 7.7.2 - shiki: 3.13.0 - tinyexec: 0.3.2 - tinyglobby: 0.2.15 - tsconfck: 3.1.6(typescript@5.9.3) - ultrahtml: 1.6.0 - unifont: 0.5.2 - unist-util-visit: 5.0.0 - unstorage: 1.17.0(@netlify/blobs@9.1.2)(db0@0.3.2(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(gel@2.0.0)(pg@8.16.3)(postgres@3.4.7)))(ioredis@5.7.0) - vfile: 6.0.3 - vite: 6.3.6(@types/node@24.6.2)(jiti@2.5.1)(less@4.4.1)(lightningcss@1.30.2)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1) - vitefu: 1.1.1(vite@6.3.6(@types/node@24.6.2)(jiti@2.5.1)(less@4.4.1)(lightningcss@1.30.2)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1)) - xxhash-wasm: 1.1.0 - yargs-parser: 21.1.1 - yocto-spinner: 0.2.3 - zod: 3.25.76 - zod-to-json-schema: 3.24.6(zod@3.25.76) - zod-to-ts: 1.2.0(typescript@5.9.3)(zod@3.25.76) - optionalDependencies: - sharp: 0.33.5 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@types/node' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - db0 - - encoding - - idb-keyval - - ioredis - - jiti - - less - - lightningcss - - rollup - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - typescript - - uploadthing - - yaml - optional: true - async-exit-hook@2.0.1: {} async-mutex@0.3.2: @@ -32512,20 +32414,6 @@ snapshots: rollup: 4.52.4 vite: 7.1.9(@types/node@24.6.2)(jiti@2.5.1)(less@4.4.1)(lightningcss@1.30.2)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1) - unplugin-yaml@3.0.6(@nuxt/kit@4.0.3(magicast@0.3.5))(@nuxt/schema@4.0.3)(astro@5.10.1(@netlify/blobs@9.1.2)(@types/node@24.6.2)(db0@0.3.2(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(gel@2.0.0)(pg@8.16.3)(postgres@3.4.7)))(ioredis@5.7.0)(jiti@2.5.1)(less@4.4.1)(lightningcss@1.30.2)(rollup@4.52.4)(terser@5.43.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1))(esbuild@0.25.9)(rolldown@1.0.0-beta.42)(rollup@4.52.4)(vite@7.1.9(@types/node@24.6.2)(jiti@2.5.1)(less@4.4.1)(lightningcss@1.30.2)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1)): - dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.52.4) - unplugin: 2.3.10 - yaml: 2.8.1 - optionalDependencies: - '@nuxt/kit': 4.0.3(magicast@0.3.5) - '@nuxt/schema': 4.0.3 - astro: 5.10.1(@netlify/blobs@9.1.2)(@types/node@24.6.2)(db0@0.3.2(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/pg@8.15.5)(gel@2.0.0)(pg@8.16.3)(postgres@3.4.7)))(ioredis@5.7.0)(jiti@2.5.1)(less@4.4.1)(lightningcss@1.30.2)(rollup@4.52.4)(terser@5.43.1)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.8.1) - esbuild: 0.25.9 - rolldown: 1.0.0-beta.42 - rollup: 4.52.4 - vite: 7.1.9(@types/node@24.6.2)(jiti@2.5.1)(less@4.4.1)(lightningcss@1.30.2)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1) - unplugin@1.16.1: dependencies: acorn: 8.15.0 @@ -32836,7 +32724,6 @@ snapshots: '@nuxt/kit': 3.18.1(magicast@0.3.5) transitivePeerDependencies: - supports-color - optional: true vite-plugin-inspect@11.3.3(@nuxt/kit@3.18.1(magicast@0.3.5))(vite@6.3.6(@types/node@24.6.2)(jiti@2.5.1)(less@4.4.1)(lightningcss@1.30.2)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1)): dependencies: @@ -32916,6 +32803,21 @@ snapshots: - supports-color - vue + vite-plugin-vue-devtools@8.0.2(rolldown-vite@7.1.15(@types/node@24.6.2)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3)): + dependencies: + '@vue/devtools-core': 8.0.2(rolldown-vite@7.1.15(@types/node@24.6.2)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1))(vue@3.5.22(typescript@5.9.3)) + '@vue/devtools-kit': 8.0.2 + '@vue/devtools-shared': 8.0.2 + execa: 9.6.0 + sirv: 3.0.2 + vite: rolldown-vite@7.1.15(@types/node@24.6.2)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1) + vite-plugin-inspect: 11.3.3(@nuxt/kit@3.18.1(magicast@0.3.5))(rolldown-vite@7.1.15(@types/node@24.6.2)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1)) + vite-plugin-vue-inspector: 5.3.2(rolldown-vite@7.1.15(@types/node@24.6.2)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1)) + transitivePeerDependencies: + - '@nuxt/kit' + - supports-color + - vue + vite-plugin-vue-inspector@5.3.2(rolldown-vite@7.1.15(@types/node@24.6.2)(esbuild@0.25.9)(jiti@2.5.1)(less@4.4.1)(terser@5.43.1)(tsx@4.20.6)(yaml@2.8.1)): dependencies: '@babel/core': 7.28.3 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 1566250b5..81c029c48 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -8,7 +8,7 @@ packages: - '!**/dist/**' catalog: - '@guiiai/logg': ^1.1.0 + '@guiiai/logg': 1.1.0 '@moeru/std': 0.1.0-beta.7 '@proj-airi/drizzle-duckdb-wasm': ^0.4.28 '@xsai-ext/providers-cloud': ^0.4.0-beta.4