@eclipse-lyra/extension-duckdb 0.7.10 → 0.7.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +1 -1
- package/dist/{duckdb-extension-D38fk4Ia.js → duckdb-extension-C_6Yn0IO.js} +2 -2
- package/dist/{duckdb-extension-D38fk4Ia.js.map → duckdb-extension-C_6Yn0IO.js.map} +1 -1
- package/dist/{duckdb-extension-manager-hie2HG1j.js → duckdb-extension-manager-6cjh-2v9.js} +12 -9
- package/dist/duckdb-extension-manager-6cjh-2v9.js.map +1 -0
- package/dist/duckdb-service.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/package.json +1 -1
- package/dist/duckdb-extension-manager-hie2HG1j.js.map +0 -1
package/dist/api.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LyraPart, activePartSignal, toastError, promptDialog, toastInfo, confirmDialog, rootContext, editorRegistry, File } from "@eclipse-lyra/core";
|
|
2
2
|
import { css, html } from "lit";
|
|
3
|
-
import { c as duckdbService, d as duckdbExtensionManagerService } from "./duckdb-extension-manager-
|
|
3
|
+
import { c as duckdbService, d as duckdbExtensionManagerService } from "./duckdb-extension-manager-6cjh-2v9.js";
|
|
4
4
|
import { property, state, customElement } from "lit/decorators.js";
|
|
5
5
|
import { createRef, ref } from "lit/directives/ref.js";
|
|
6
6
|
var __defProp = Object.defineProperty;
|
|
@@ -531,4 +531,4 @@ function duckdbExtension() {
|
|
|
531
531
|
export {
|
|
532
532
|
duckdbExtension as default
|
|
533
533
|
};
|
|
534
|
-
//# sourceMappingURL=duckdb-extension-
|
|
534
|
+
//# sourceMappingURL=duckdb-extension-C_6Yn0IO.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"duckdb-extension-D38fk4Ia.js","sources":["../src/duckdb-editor.ts","../src/duckdb-extension.ts"],"sourcesContent":["import { customElement, property, state } from \"lit/decorators.js\";\nimport { LyraPart } from \"@eclipse-lyra/core\";\nimport { css, html } from \"lit\";\nimport { createRef, ref } from \"lit/directives/ref.js\";\nimport { styleMap } from \"lit/directives/style-map.js\";\nimport { EditorInput, EditorContentProvider, toastError, toastInfo, promptDialog, confirmDialog, activePartSignal } from \"@eclipse-lyra/core\";\nimport { LyraMonacoWidget } from \"@eclipse-lyra/extension-monaco-editor\";\nimport { duckdbService, duckdbExtensionManagerService, type DuckDBDatabase, type DuckDBQueryResult } from \"./api\";\n\nconst MAX_TAB_LABEL = 28;\nconst DB_NAME_REGEX = /^[a-zA-Z0-9_.-]+$/;\n\ninterface ResultTab {\n id: string;\n label: string;\n sql: string;\n result: DuckDBQueryResult | { error: string };\n}\n\nfunction truncateLabel(sql: string): string {\n const oneLine = sql.replace(/\\s+/g, \" \").trim();\n if (oneLine.length <= MAX_TAB_LABEL) return oneLine;\n return oneLine.slice(0, MAX_TAB_LABEL) + \"…\";\n}\n\n@customElement(\"lyra-duckdb-editor\")\nexport class LyraDuckDBEditor extends LyraPart implements EditorContentProvider {\n @property({ attribute: false })\n public input?: EditorInput;\n\n @property({ type: Boolean })\n public readOnly = false;\n\n @state()\n private initialContent: string | undefined = undefined;\n\n @state()\n private initialUri: string | undefined = undefined;\n\n @state()\n private resultTabs: ResultTab[] = [];\n\n @state()\n private activeResultId: string | null = null;\n\n @state()\n private running = false;\n\n @state()\n private availableDatabases: string[] = [];\n\n @state()\n private selectedDbName: string | null = null;\n\n private widgetRef = createRef<LyraMonacoWidget>();\n private tabGroupRef = createRef<HTMLElement & { active: string }>();\n private tabIdCounter = 0;\n private db: DuckDBDatabase | null = null;\n\n protected async doInitUI() {\n const file = this.input!.data;\n const textContents = await file.getContents();\n this.initialContent = textContents;\n this.initialUri = file.getName();\n this.watch(activePartSignal, () => {\n if (activePartSignal.get() === this) this.refreshDatabaseList();\n });\n await this.refreshDatabaseList();\n this.requestUpdate();\n }\n\n private async refreshDatabaseList(): Promise<void> {\n try {\n this.availableDatabases = await duckdbService.listDatabases();\n } catch {\n this.availableDatabases = [];\n }\n this.requestUpdate();\n this.updateToolbar();\n }\n\n private _onContentChange = () => {\n this.markDirty(true);\n };\n\n save(): void {\n const value = this.widgetRef.value?.getContent() ?? \"\";\n this.input?.data.saveContents(value);\n this.markDirty(false);\n }\n\n protected doClose() {\n this.widgetRef.value?.dispose();\n if (this.db) {\n void this.db.close();\n this.db = null;\n }\n }\n\n public getLanguage(): string | null {\n return \"sql\";\n }\n\n public isLanguage(lang: string): boolean {\n return lang.toLowerCase() === \"sql\";\n }\n\n public getContent(): string | null {\n return this.widgetRef.value?.getContent() ?? null;\n }\n\n public getSelection(): string | null {\n return this.widgetRef.value?.getSelection() ?? null;\n }\n\n public getSnippet(lines: number = 5): { snippet: string; cursorLine: number } | null {\n return this.widgetRef.value?.getSnippet(lines) ?? null;\n }\n\n public getFilePath(): string | null {\n return this.input?.data?.getWorkspacePath() ?? null;\n }\n\n private async runQuery(useSelectionOnly = false): Promise<void> {\n const sql = useSelectionOnly\n ? this.getSelection()?.trim()\n : (this.getSelection()?.trim() || this.getContent()?.trim());\n if (!sql) {\n toastError(useSelectionOnly ? \"No selection to run\" : \"No SQL to run\");\n return;\n }\n if (this.running) return;\n\n this.running = true;\n const id = `result-${++this.tabIdCounter}`;\n const label = truncateLabel(sql);\n this.resultTabs = [...this.resultTabs, { id, label, sql, result: { columns: [], rows: [] } }];\n this.activeResultId = id;\n this.requestUpdate();\n this.updateToolbar();\n\n const timeoutMs = 60_000;\n const timeoutId = window.setTimeout(() => this.clearRunningState(), timeoutMs);\n\n try {\n const dbName = this.selectedDbName ?? undefined;\n if (!this.db || this.db.name !== (dbName ?? null)) {\n if (this.db) {\n void this.db.close();\n this.db = null;\n }\n this.db = await duckdbService.open(dbName);\n }\n const result = await this.db.runQuery(sql);\n this.resultTabs = this.resultTabs.map((t) =>\n t.id === id ? { ...t, result } : t\n );\n } catch (err) {\n const error = err instanceof Error ? err.message : String(err);\n this.resultTabs = this.resultTabs.map((t) =>\n t.id === id ? { ...t, result: { error } } : t\n );\n } finally {\n window.clearTimeout(timeoutId);\n this.running = false;\n this.activeResultId = id;\n this.requestUpdate();\n this.updateToolbar();\n }\n }\n\n private clearRunningState(): void {\n if (this.running) {\n this.running = false;\n this.requestUpdate();\n this.updateToolbar();\n }\n }\n\n private closeTab(id: string): void {\n const idx = this.resultTabs.findIndex((t) => t.id === id);\n if (idx < 0) return;\n const next = this.resultTabs.filter((t) => t.id !== id);\n this.resultTabs = next;\n if (this.activeResultId === id) {\n const prevIdx = Math.min(idx, next.length - 1);\n this.activeResultId = next[prevIdx]?.id ?? null;\n }\n this.requestUpdate();\n this.updateToolbar();\n }\n\n private renderResultPanel(tab: ResultTab) {\n if (\"error\" in tab.result) {\n return html`\n <div class=\"result-error\">\n <pre>${tab.result.error}</pre>\n </div>\n `;\n }\n const { columns, rows } = tab.result;\n if (columns.length === 0 && rows.length === 0) {\n return html`<div class=\"result-empty\">Query returned no rows.</div>`;\n }\n return html`\n <div class=\"result-table-wrap\">\n <table class=\"result-table\">\n <thead>\n <tr>\n ${columns.map((col) => html`<th>${col}</th>`)}\n </tr>\n </thead>\n <tbody>\n ${rows.map(\n (row) => html`\n <tr>\n ${row.map((cell) => html`<td>${String(cell ?? \"\")}</td>`)}\n </tr>\n `\n )}\n </tbody>\n </table>\n </div>\n `;\n }\n\n private onDatabaseChange(e: Event) {\n const select = e.target as { value?: string };\n const value = select?.value ?? \"\";\n const next = value === \"\" ? null : value;\n if (this.selectedDbName === next) return;\n this.selectedDbName = next;\n if (this.db) {\n void this.db.close();\n this.db = null;\n }\n this.requestUpdate();\n }\n\n private async addNewDatabase(): Promise<void> {\n const raw = await promptDialog(\"New database name\", \"\");\n if (raw == null) return;\n const name = raw.trim();\n if (!name) {\n toastError(\"Name cannot be empty\");\n return;\n }\n if (!DB_NAME_REGEX.test(name)) {\n toastError(\"Name may only contain letters, numbers, and . _ -\");\n return;\n }\n if (this.availableDatabases.includes(name)) {\n toastError(`Database \"${name}\" already exists`);\n return;\n }\n try {\n const newDb = await duckdbService.open(name);\n await newDb.close();\n this.selectedDbName = name;\n if (this.db) {\n void this.db.close();\n this.db = null;\n }\n await this.refreshDatabaseList();\n toastInfo(`Database \"${name}\" created`);\n } catch (err) {\n toastError(err instanceof Error ? err.message : String(err));\n }\n }\n\n private async deleteSelectedDatabase(): Promise<void> {\n const name = this.selectedDbName;\n const label = name === null ? \"In-memory\" : name;\n const ok = await confirmDialog(`Delete database \"${label}\"?`);\n if (!ok) return;\n if (name === null) {\n if (this.db) {\n void this.db.close();\n this.db = null;\n }\n } else {\n try {\n await duckdbService.delete(name);\n if (this.db?.name === name) this.db = null;\n this.selectedDbName = null;\n await this.refreshDatabaseList();\n } catch (err) {\n toastError(err instanceof Error ? err.message : String(err));\n return;\n }\n }\n this.requestUpdate();\n this.updateToolbar();\n }\n\n protected renderToolbar() {\n const dbValue = this.selectedDbName ?? \"\";\n return html`\n <wa-select\n class=\"db-select\"\n size=\"small\"\n value=${dbValue}\n title=\"Database (OPFS)\"\n @change=${(e: Event) => this.onDatabaseChange(e)}\n >\n <wa-option value=\"\">In-memory</wa-option>\n ${this.availableDatabases.map(\n (name) => html`<wa-option value=${name}>${name}</wa-option>`\n )}\n </wa-select>\n <wa-button\n size=\"small\"\n appearance=\"plain\"\n title=\"New database\"\n @click=${() => this.addNewDatabase()}\n >\n <wa-icon name=\"plus\" label=\"New\"></wa-icon>\n </wa-button>\n <wa-button\n size=\"small\"\n appearance=\"plain\"\n title=${this.selectedDbName === null ? \"Clear in-memory database\" : `Delete database \"${this.selectedDbName}\"`}\n @click=${() => this.deleteSelectedDatabase()}\n >\n <wa-icon name=\"trash\" label=\"Delete\"></wa-icon>\n </wa-button>\n <wa-button\n size=\"small\"\n appearance=\"plain\"\n title=\"Manage DuckDB extensions\"\n @click=${() =>\n duckdbExtensionManagerService.showExtensionManager({\n db: this.db,\n databaseLabel: this.selectedDbName === null ? \"In-memory\" : this.selectedDbName,\n })}\n >\n <wa-icon name=\"puzzle-piece\" label=\"Extensions\"></wa-icon>\n Extensions\n </wa-button>\n <wa-button\n size=\"small\"\n appearance=\"plain\"\n ?disabled=${this.running}\n @click=${() => this.runQuery(true)}\n title=\"Run selection only\"\n >\n <wa-icon name=\"i-cursor\" label=\"Run selection\"></wa-icon>\n ${this.running ? \"Running…\" : \"Run selection\"}\n </wa-button>\n <wa-button\n size=\"small\"\n appearance=\"plain\"\n ?disabled=${this.running}\n @click=${() => this.runQuery(false)}\n title=\"Run all SQL\"\n >\n <wa-icon name=\"play\" label=\"Run\"></wa-icon>\n ${this.running ? \"Running…\" : \"Run all\"}\n </wa-button>\n `;\n }\n\n protected updated(changedProperties: Map<string, unknown>) {\n super.updated(changedProperties);\n if (changedProperties.has(\"resultTabs\") || changedProperties.has(\"running\")) {\n this.updateToolbar();\n }\n const activeId = this.activeResultId ?? this.resultTabs[0]?.id ?? \"\";\n if (activeId && this.tabGroupRef.value && this.tabGroupRef.value.active !== activeId) {\n this.tabGroupRef.value.active = activeId;\n }\n }\n\n render() {\n if (this.initialContent === undefined) {\n return html`<div class=\"editor-placeholder\"></div>`;\n }\n\n const hasResults = this.resultTabs.length > 0;\n const activeId = this.activeResultId ?? this.resultTabs[0]?.id ?? \"\";\n\n return html`\n <wa-split-panel\n class=\"editor-split\"\n orientation=\"vertical\"\n position=\"60\"\n >\n <div slot=\"start\" class=\"editor-area\">\n <lyra-monaco-widget\n .value=${this.initialContent}\n .uri=${this.initialUri}\n .language=${\"sql\"}\n .readOnly=${this.readOnly}\n @content-change=${this._onContentChange}\n ${ref(this.widgetRef)}\n ></lyra-monaco-widget>\n </div>\n <div slot=\"end\" class=\"results-area\">\n ${hasResults\n ? html`\n <wa-tab-group\n class=\"result-tabs\"\n .active=${activeId}\n ${ref(this.tabGroupRef)}\n @wa-tab-show=${(e: CustomEvent<{ name: string }>) => {\n this.activeResultId = e.detail?.name ?? null;\n }}\n >\n ${this.resultTabs.flatMap((tab) => [\n html`<wa-tab panel=\"${tab.id}\">${tab.label}</wa-tab>`,\n html`<wa-button\n slot=\"nav\"\n tabindex=\"-1\"\n appearance=\"plain\"\n size=\"small\"\n class=\"tab-close\"\n title=\"Close tab\"\n @click=${() => this.closeTab(tab.id)}\n >\n <wa-icon name=\"xmark\" label=\"Close\"></wa-icon>\n </wa-button>`,\n html`<wa-tab-panel name=\"${tab.id}\">${this.renderResultPanel(tab)}</wa-tab-panel>`,\n ])}\n </wa-tab-group>\n `\n : html`\n <div class=\"results-empty\">\n Run a query to see results in a new tab.\n </div>\n `}\n </div>\n </wa-split-panel>\n `;\n }\n\n static styles = css`\n :host {\n display: flex;\n flex-direction: column;\n position: relative;\n width: 100%;\n height: 100%;\n }\n .db-select {\n max-width: 10rem;\n }\n .editor-split {\n flex: 1;\n min-height: 0;\n height: 100%;\n }\n .editor-area,\n .results-area {\n height: 100%;\n min-height: 0;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n .editor-area monaco-widget {\n flex: 1;\n min-height: 0;\n }\n .editor-placeholder {\n flex: 1;\n min-height: 0;\n }\n .result-tabs {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n }\n .result-tabs::part(body) {\n flex: 1;\n min-height: 0;\n overflow: auto;\n }\n .result-tabs .tab-close {\n margin-left: -0.25rem;\n padding: 0.2rem;\n }\n .results-empty {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--wa-color-neutral-500, #6b7280);\n font-size: 0.875rem;\n }\n .result-table-wrap {\n overflow: auto;\n padding: 0.75rem;\n }\n .result-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 0.8125rem;\n }\n .result-table th,\n .result-table td {\n padding: 0.35rem 0.75rem;\n text-align: left;\n border-bottom: 1px solid var(--wa-color-neutral-200, #e5e7eb);\n }\n .result-table th {\n font-weight: 600;\n background: var(--wa-color-neutral-100, #f3f4f6);\n }\n .result-table tbody tr:hover {\n background: var(--wa-color-neutral-50, #f9fafb);\n }\n .result-error {\n padding: 0.75rem;\n color: var(--wa-color-red-60, #dc2626);\n font-family: ui-monospace, monospace;\n font-size: 0.8125rem;\n }\n .result-error pre {\n margin: 0;\n white-space: pre-wrap;\n }\n .result-empty {\n padding: 0.75rem;\n color: var(--wa-color-neutral-500, #6b7280);\n font-size: 0.875rem;\n }\n `;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"lyra-duckdb-editor\": LyraDuckDBEditor;\n }\n}\n","import { rootContext, editorRegistry, File, type EditorInput } from '@eclipse-lyra/core';\nimport { html } from 'lit';\nimport { duckdbService } from './duckdb-service';\nimport './duckdb-editor';\nimport './duckdb-extension-manager';\n\nexport default function () {\n rootContext.put('duckdbService', duckdbService);\n\n editorRegistry.registerEditorInputHandler({\n editorId: 'system.duckdb-editor',\n label: 'DuckDB',\n icon: 'database',\n canHandle: (input: unknown) =>\n input instanceof File && input.getName().toLowerCase().endsWith('.sql'),\n ranking: 1000,\n handle: async (input: File) => {\n const editorInput: EditorInput = {\n title: input.getName(),\n data: input,\n key: input.getName(),\n icon: 'database',\n noOverflow: false,\n state: {},\n component: () => null as any,\n };\n editorInput.component = () =>\n html`<lyra-duckdb-editor .input=${editorInput}></lyra-duckdb-editor>`;\n return editorInput;\n },\n });\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"duckdb-extension-C_6Yn0IO.js","sources":["../src/duckdb-editor.ts","../src/duckdb-extension.ts"],"sourcesContent":["import { customElement, property, state } from \"lit/decorators.js\";\nimport { LyraPart } from \"@eclipse-lyra/core\";\nimport { css, html } from \"lit\";\nimport { createRef, ref } from \"lit/directives/ref.js\";\nimport { styleMap } from \"lit/directives/style-map.js\";\nimport { EditorInput, EditorContentProvider, toastError, toastInfo, promptDialog, confirmDialog, activePartSignal } from \"@eclipse-lyra/core\";\nimport { LyraMonacoWidget } from \"@eclipse-lyra/extension-monaco-editor\";\nimport { duckdbService, duckdbExtensionManagerService, type DuckDBDatabase, type DuckDBQueryResult } from \"./api\";\n\nconst MAX_TAB_LABEL = 28;\nconst DB_NAME_REGEX = /^[a-zA-Z0-9_.-]+$/;\n\ninterface ResultTab {\n id: string;\n label: string;\n sql: string;\n result: DuckDBQueryResult | { error: string };\n}\n\nfunction truncateLabel(sql: string): string {\n const oneLine = sql.replace(/\\s+/g, \" \").trim();\n if (oneLine.length <= MAX_TAB_LABEL) return oneLine;\n return oneLine.slice(0, MAX_TAB_LABEL) + \"…\";\n}\n\n@customElement(\"lyra-duckdb-editor\")\nexport class LyraDuckDBEditor extends LyraPart implements EditorContentProvider {\n @property({ attribute: false })\n public input?: EditorInput;\n\n @property({ type: Boolean })\n public readOnly = false;\n\n @state()\n private initialContent: string | undefined = undefined;\n\n @state()\n private initialUri: string | undefined = undefined;\n\n @state()\n private resultTabs: ResultTab[] = [];\n\n @state()\n private activeResultId: string | null = null;\n\n @state()\n private running = false;\n\n @state()\n private availableDatabases: string[] = [];\n\n @state()\n private selectedDbName: string | null = null;\n\n private widgetRef = createRef<LyraMonacoWidget>();\n private tabGroupRef = createRef<HTMLElement & { active: string }>();\n private tabIdCounter = 0;\n private db: DuckDBDatabase | null = null;\n\n protected async doInitUI() {\n const file = this.input!.data;\n const textContents = await file.getContents();\n this.initialContent = textContents;\n this.initialUri = file.getName();\n this.watch(activePartSignal, () => {\n if (activePartSignal.get() === this) this.refreshDatabaseList();\n });\n await this.refreshDatabaseList();\n this.requestUpdate();\n }\n\n private async refreshDatabaseList(): Promise<void> {\n try {\n this.availableDatabases = await duckdbService.listDatabases();\n } catch {\n this.availableDatabases = [];\n }\n this.requestUpdate();\n this.updateToolbar();\n }\n\n private _onContentChange = () => {\n this.markDirty(true);\n };\n\n save(): void {\n const value = this.widgetRef.value?.getContent() ?? \"\";\n this.input?.data.saveContents(value);\n this.markDirty(false);\n }\n\n protected doClose() {\n this.widgetRef.value?.dispose();\n if (this.db) {\n void this.db.close();\n this.db = null;\n }\n }\n\n public getLanguage(): string | null {\n return \"sql\";\n }\n\n public isLanguage(lang: string): boolean {\n return lang.toLowerCase() === \"sql\";\n }\n\n public getContent(): string | null {\n return this.widgetRef.value?.getContent() ?? null;\n }\n\n public getSelection(): string | null {\n return this.widgetRef.value?.getSelection() ?? null;\n }\n\n public getSnippet(lines: number = 5): { snippet: string; cursorLine: number } | null {\n return this.widgetRef.value?.getSnippet(lines) ?? null;\n }\n\n public getFilePath(): string | null {\n return this.input?.data?.getWorkspacePath() ?? null;\n }\n\n private async runQuery(useSelectionOnly = false): Promise<void> {\n const sql = useSelectionOnly\n ? this.getSelection()?.trim()\n : (this.getSelection()?.trim() || this.getContent()?.trim());\n if (!sql) {\n toastError(useSelectionOnly ? \"No selection to run\" : \"No SQL to run\");\n return;\n }\n if (this.running) return;\n\n this.running = true;\n const id = `result-${++this.tabIdCounter}`;\n const label = truncateLabel(sql);\n this.resultTabs = [...this.resultTabs, { id, label, sql, result: { columns: [], rows: [] } }];\n this.activeResultId = id;\n this.requestUpdate();\n this.updateToolbar();\n\n const timeoutMs = 60_000;\n const timeoutId = window.setTimeout(() => this.clearRunningState(), timeoutMs);\n\n try {\n const dbName = this.selectedDbName ?? undefined;\n if (!this.db || this.db.name !== (dbName ?? null)) {\n if (this.db) {\n void this.db.close();\n this.db = null;\n }\n this.db = await duckdbService.open(dbName);\n }\n const result = await this.db.runQuery(sql);\n this.resultTabs = this.resultTabs.map((t) =>\n t.id === id ? { ...t, result } : t\n );\n } catch (err) {\n const error = err instanceof Error ? err.message : String(err);\n this.resultTabs = this.resultTabs.map((t) =>\n t.id === id ? { ...t, result: { error } } : t\n );\n } finally {\n window.clearTimeout(timeoutId);\n this.running = false;\n this.activeResultId = id;\n this.requestUpdate();\n this.updateToolbar();\n }\n }\n\n private clearRunningState(): void {\n if (this.running) {\n this.running = false;\n this.requestUpdate();\n this.updateToolbar();\n }\n }\n\n private closeTab(id: string): void {\n const idx = this.resultTabs.findIndex((t) => t.id === id);\n if (idx < 0) return;\n const next = this.resultTabs.filter((t) => t.id !== id);\n this.resultTabs = next;\n if (this.activeResultId === id) {\n const prevIdx = Math.min(idx, next.length - 1);\n this.activeResultId = next[prevIdx]?.id ?? null;\n }\n this.requestUpdate();\n this.updateToolbar();\n }\n\n private renderResultPanel(tab: ResultTab) {\n if (\"error\" in tab.result) {\n return html`\n <div class=\"result-error\">\n <pre>${tab.result.error}</pre>\n </div>\n `;\n }\n const { columns, rows } = tab.result;\n if (columns.length === 0 && rows.length === 0) {\n return html`<div class=\"result-empty\">Query returned no rows.</div>`;\n }\n return html`\n <div class=\"result-table-wrap\">\n <table class=\"result-table\">\n <thead>\n <tr>\n ${columns.map((col) => html`<th>${col}</th>`)}\n </tr>\n </thead>\n <tbody>\n ${rows.map(\n (row) => html`\n <tr>\n ${row.map((cell) => html`<td>${String(cell ?? \"\")}</td>`)}\n </tr>\n `\n )}\n </tbody>\n </table>\n </div>\n `;\n }\n\n private onDatabaseChange(e: Event) {\n const select = e.target as { value?: string };\n const value = select?.value ?? \"\";\n const next = value === \"\" ? null : value;\n if (this.selectedDbName === next) return;\n this.selectedDbName = next;\n if (this.db) {\n void this.db.close();\n this.db = null;\n }\n this.requestUpdate();\n }\n\n private async addNewDatabase(): Promise<void> {\n const raw = await promptDialog(\"New database name\", \"\");\n if (raw == null) return;\n const name = raw.trim();\n if (!name) {\n toastError(\"Name cannot be empty\");\n return;\n }\n if (!DB_NAME_REGEX.test(name)) {\n toastError(\"Name may only contain letters, numbers, and . _ -\");\n return;\n }\n if (this.availableDatabases.includes(name)) {\n toastError(`Database \"${name}\" already exists`);\n return;\n }\n try {\n const newDb = await duckdbService.open(name);\n await newDb.close();\n this.selectedDbName = name;\n if (this.db) {\n void this.db.close();\n this.db = null;\n }\n await this.refreshDatabaseList();\n toastInfo(`Database \"${name}\" created`);\n } catch (err) {\n toastError(err instanceof Error ? err.message : String(err));\n }\n }\n\n private async deleteSelectedDatabase(): Promise<void> {\n const name = this.selectedDbName;\n const label = name === null ? \"In-memory\" : name;\n const ok = await confirmDialog(`Delete database \"${label}\"?`);\n if (!ok) return;\n if (name === null) {\n if (this.db) {\n void this.db.close();\n this.db = null;\n }\n } else {\n try {\n await duckdbService.delete(name);\n if (this.db?.name === name) this.db = null;\n this.selectedDbName = null;\n await this.refreshDatabaseList();\n } catch (err) {\n toastError(err instanceof Error ? err.message : String(err));\n return;\n }\n }\n this.requestUpdate();\n this.updateToolbar();\n }\n\n protected renderToolbar() {\n const dbValue = this.selectedDbName ?? \"\";\n return html`\n <wa-select\n class=\"db-select\"\n size=\"small\"\n value=${dbValue}\n title=\"Database (OPFS)\"\n @change=${(e: Event) => this.onDatabaseChange(e)}\n >\n <wa-option value=\"\">In-memory</wa-option>\n ${this.availableDatabases.map(\n (name) => html`<wa-option value=${name}>${name}</wa-option>`\n )}\n </wa-select>\n <wa-button\n size=\"small\"\n appearance=\"plain\"\n title=\"New database\"\n @click=${() => this.addNewDatabase()}\n >\n <wa-icon name=\"plus\" label=\"New\"></wa-icon>\n </wa-button>\n <wa-button\n size=\"small\"\n appearance=\"plain\"\n title=${this.selectedDbName === null ? \"Clear in-memory database\" : `Delete database \"${this.selectedDbName}\"`}\n @click=${() => this.deleteSelectedDatabase()}\n >\n <wa-icon name=\"trash\" label=\"Delete\"></wa-icon>\n </wa-button>\n <wa-button\n size=\"small\"\n appearance=\"plain\"\n title=\"Manage DuckDB extensions\"\n @click=${() =>\n duckdbExtensionManagerService.showExtensionManager({\n db: this.db,\n databaseLabel: this.selectedDbName === null ? \"In-memory\" : this.selectedDbName,\n })}\n >\n <wa-icon name=\"puzzle-piece\" label=\"Extensions\"></wa-icon>\n Extensions\n </wa-button>\n <wa-button\n size=\"small\"\n appearance=\"plain\"\n ?disabled=${this.running}\n @click=${() => this.runQuery(true)}\n title=\"Run selection only\"\n >\n <wa-icon name=\"i-cursor\" label=\"Run selection\"></wa-icon>\n ${this.running ? \"Running…\" : \"Run selection\"}\n </wa-button>\n <wa-button\n size=\"small\"\n appearance=\"plain\"\n ?disabled=${this.running}\n @click=${() => this.runQuery(false)}\n title=\"Run all SQL\"\n >\n <wa-icon name=\"play\" label=\"Run\"></wa-icon>\n ${this.running ? \"Running…\" : \"Run all\"}\n </wa-button>\n `;\n }\n\n protected updated(changedProperties: Map<string, unknown>) {\n super.updated(changedProperties);\n if (changedProperties.has(\"resultTabs\") || changedProperties.has(\"running\")) {\n this.updateToolbar();\n }\n const activeId = this.activeResultId ?? this.resultTabs[0]?.id ?? \"\";\n if (activeId && this.tabGroupRef.value && this.tabGroupRef.value.active !== activeId) {\n this.tabGroupRef.value.active = activeId;\n }\n }\n\n render() {\n if (this.initialContent === undefined) {\n return html`<div class=\"editor-placeholder\"></div>`;\n }\n\n const hasResults = this.resultTabs.length > 0;\n const activeId = this.activeResultId ?? this.resultTabs[0]?.id ?? \"\";\n\n return html`\n <wa-split-panel\n class=\"editor-split\"\n orientation=\"vertical\"\n position=\"60\"\n >\n <div slot=\"start\" class=\"editor-area\">\n <lyra-monaco-widget\n .value=${this.initialContent}\n .uri=${this.initialUri}\n .language=${\"sql\"}\n .readOnly=${this.readOnly}\n @content-change=${this._onContentChange}\n ${ref(this.widgetRef)}\n ></lyra-monaco-widget>\n </div>\n <div slot=\"end\" class=\"results-area\">\n ${hasResults\n ? html`\n <wa-tab-group\n class=\"result-tabs\"\n .active=${activeId}\n ${ref(this.tabGroupRef)}\n @wa-tab-show=${(e: CustomEvent<{ name: string }>) => {\n this.activeResultId = e.detail?.name ?? null;\n }}\n >\n ${this.resultTabs.flatMap((tab) => [\n html`<wa-tab panel=\"${tab.id}\">${tab.label}</wa-tab>`,\n html`<wa-button\n slot=\"nav\"\n tabindex=\"-1\"\n appearance=\"plain\"\n size=\"small\"\n class=\"tab-close\"\n title=\"Close tab\"\n @click=${() => this.closeTab(tab.id)}\n >\n <wa-icon name=\"xmark\" label=\"Close\"></wa-icon>\n </wa-button>`,\n html`<wa-tab-panel name=\"${tab.id}\">${this.renderResultPanel(tab)}</wa-tab-panel>`,\n ])}\n </wa-tab-group>\n `\n : html`\n <div class=\"results-empty\">\n Run a query to see results in a new tab.\n </div>\n `}\n </div>\n </wa-split-panel>\n `;\n }\n\n static styles = css`\n :host {\n display: flex;\n flex-direction: column;\n position: relative;\n width: 100%;\n height: 100%;\n }\n .db-select {\n max-width: 10rem;\n }\n .editor-split {\n flex: 1;\n min-height: 0;\n height: 100%;\n }\n .editor-area,\n .results-area {\n height: 100%;\n min-height: 0;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n .editor-area monaco-widget {\n flex: 1;\n min-height: 0;\n }\n .editor-placeholder {\n flex: 1;\n min-height: 0;\n }\n .result-tabs {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n }\n .result-tabs::part(body) {\n flex: 1;\n min-height: 0;\n overflow: auto;\n }\n .result-tabs .tab-close {\n margin-left: -0.25rem;\n padding: 0.2rem;\n }\n .results-empty {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--wa-color-neutral-500, #6b7280);\n font-size: 0.875rem;\n }\n .result-table-wrap {\n overflow: auto;\n padding: 0.75rem;\n }\n .result-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 0.8125rem;\n }\n .result-table th,\n .result-table td {\n padding: 0.35rem 0.75rem;\n text-align: left;\n border-bottom: 1px solid var(--wa-color-neutral-200, #e5e7eb);\n }\n .result-table th {\n font-weight: 600;\n background: var(--wa-color-neutral-100, #f3f4f6);\n }\n .result-table tbody tr:hover {\n background: var(--wa-color-neutral-50, #f9fafb);\n }\n .result-error {\n padding: 0.75rem;\n color: var(--wa-color-red-60, #dc2626);\n font-family: ui-monospace, monospace;\n font-size: 0.8125rem;\n }\n .result-error pre {\n margin: 0;\n white-space: pre-wrap;\n }\n .result-empty {\n padding: 0.75rem;\n color: var(--wa-color-neutral-500, #6b7280);\n font-size: 0.875rem;\n }\n `;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"lyra-duckdb-editor\": LyraDuckDBEditor;\n }\n}\n","import { rootContext, editorRegistry, File, type EditorInput } from '@eclipse-lyra/core';\nimport { html } from 'lit';\nimport { duckdbService } from './duckdb-service';\nimport './duckdb-editor';\nimport './duckdb-extension-manager';\n\nexport default function () {\n rootContext.put('duckdbService', duckdbService);\n\n editorRegistry.registerEditorInputHandler({\n editorId: 'system.duckdb-editor',\n label: 'DuckDB',\n icon: 'database',\n canHandle: (input: unknown) =>\n input instanceof File && input.getName().toLowerCase().endsWith('.sql'),\n ranking: 1000,\n handle: async (input: File) => {\n const editorInput: EditorInput = {\n title: input.getName(),\n data: input,\n key: input.getName(),\n icon: 'database',\n noOverflow: false,\n state: {},\n component: () => null as any,\n };\n editorInput.component = () =>\n html`<lyra-duckdb-editor .input=${editorInput}></lyra-duckdb-editor>`;\n return editorInput;\n },\n });\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { createLogger, rootContext } from "@eclipse-lyra/core";
|
|
2
|
-
import * as duckdb from "
|
|
2
|
+
import * as duckdb from "@duckdb/duckdb-wasm";
|
|
3
|
+
import duckdb_wasm from "@duckdb/duckdb-wasm/dist/duckdb-mvp.wasm?url";
|
|
4
|
+
import mvp_worker from "@duckdb/duckdb-wasm/dist/duckdb-browser-mvp.worker.js?url";
|
|
5
|
+
import duckdb_wasm_eh from "@duckdb/duckdb-wasm/dist/duckdb-eh.wasm?url";
|
|
6
|
+
import eh_worker from "@duckdb/duckdb-wasm/dist/duckdb-browser-eh.worker.js?url";
|
|
3
7
|
import { css, LitElement, html } from "lit";
|
|
4
8
|
import { property, state, customElement } from "lit/decorators.js";
|
|
5
9
|
import { repeat } from "lit/directives/repeat.js";
|
|
6
10
|
const logger = createLogger("DuckDBService");
|
|
7
|
-
const
|
|
11
|
+
const MANUAL_BUNDLES = {
|
|
12
|
+
mvp: { mainModule: duckdb_wasm, mainWorker: mvp_worker },
|
|
13
|
+
eh: { mainModule: duckdb_wasm_eh, mainWorker: eh_worker }
|
|
14
|
+
};
|
|
8
15
|
const IN_MEMORY_KEY = "__memory__";
|
|
9
16
|
const OPFS_DB_DIR = "duckdb-databases";
|
|
10
17
|
const EXTENSION_NAME_REGEX = /^[a-zA-Z][a-zA-Z0-9_]*$/;
|
|
@@ -34,12 +41,8 @@ async function ensureOPFSDatabaseDir() {
|
|
|
34
41
|
await root.getDirectoryHandle(OPFS_DB_DIR, { create: true });
|
|
35
42
|
}
|
|
36
43
|
async function createConnection(path) {
|
|
37
|
-
const bundle = await duckdb.selectBundle(
|
|
38
|
-
const
|
|
39
|
-
new Blob([`importScripts("${bundle.mainWorker}");`], { type: "text/javascript" })
|
|
40
|
-
);
|
|
41
|
-
const worker = new Worker(workerUrl);
|
|
42
|
-
URL.revokeObjectURL(workerUrl);
|
|
44
|
+
const bundle = await duckdb.selectBundle(MANUAL_BUNDLES);
|
|
45
|
+
const worker = new Worker(bundle.mainWorker);
|
|
43
46
|
const log = new duckdb.ConsoleLogger();
|
|
44
47
|
const db = new duckdb.AsyncDuckDB(log, worker);
|
|
45
48
|
await db.instantiate(bundle.mainModule, bundle.pthreadWorker);
|
|
@@ -430,4 +433,4 @@ export {
|
|
|
430
433
|
duckdbService as c,
|
|
431
434
|
duckdbExtensionManagerService as d
|
|
432
435
|
};
|
|
433
|
-
//# sourceMappingURL=duckdb-extension-manager-
|
|
436
|
+
//# sourceMappingURL=duckdb-extension-manager-6cjh-2v9.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"duckdb-extension-manager-6cjh-2v9.js","sources":["../src/duckdb-service.ts","../src/duckdb-extension-manager.ts"],"sourcesContent":["import { createLogger } from '@eclipse-lyra/core';\nimport * as duckdb from '@duckdb/duckdb-wasm';\nimport duckdb_wasm from '@duckdb/duckdb-wasm/dist/duckdb-mvp.wasm?url';\nimport mvp_worker from '@duckdb/duckdb-wasm/dist/duckdb-browser-mvp.worker.js?url';\nimport duckdb_wasm_eh from '@duckdb/duckdb-wasm/dist/duckdb-eh.wasm?url';\nimport eh_worker from '@duckdb/duckdb-wasm/dist/duckdb-browser-eh.worker.js?url';\n\nconst logger = createLogger('DuckDBService');\n\nconst MANUAL_BUNDLES: duckdb.DuckDBBundles = {\n mvp: { mainModule: duckdb_wasm, mainWorker: mvp_worker },\n eh: { mainModule: duckdb_wasm_eh, mainWorker: eh_worker },\n};\n\nconst IN_MEMORY_KEY = '__memory__';\nconst OPFS_DB_DIR = 'duckdb-databases';\nconst EXTENSION_NAME_REGEX = /^[a-zA-Z][a-zA-Z0-9_]*$/;\nconst DB_NAME_REGEX = /^[a-zA-Z0-9_.-]+$/;\n\nfunction pathFor(name: string): string {\n return `opfs://${OPFS_DB_DIR}/${name}.duckdb`;\n}\n\ntype AsyncDuckDB = duckdb.AsyncDuckDB;\ntype AsyncDuckDBConnection = Awaited<ReturnType<AsyncDuckDB['connect']>>;\n\n/** Plain JS result: columns in order, rows as array of value arrays. */\nexport interface DuckDBQueryResult {\n columns: string[];\n rows: unknown[][];\n}\n\nfunction toPlainValue(v: unknown): unknown {\n if (v === null || v === undefined) return v;\n if (typeof v === 'bigint') return Number(v);\n if (v instanceof Date) return v.toISOString();\n if (typeof v === 'object' && v !== null && typeof (v as { toJSON: unknown }).toJSON === 'function') {\n return (v as { toJSON: () => unknown }).toJSON();\n }\n return v;\n}\n\nfunction tableToPlainArrays(table: { toArray?: () => unknown[] }): { columns: string[]; rows: unknown[][] } {\n const raw = table.toArray?.();\n const rowObjects = Array.isArray(raw) ? (raw as Record<string, unknown>[]) : [];\n if (rowObjects.length === 0) return { columns: [], rows: [] };\n const columns = Object.keys(rowObjects[0]);\n const rows = rowObjects.map((obj) => columns.map((col) => toPlainValue(obj[col])));\n return { columns, rows };\n}\n\nasync function ensureOPFSDatabaseDir(): Promise<void> {\n const root = await navigator.storage.getDirectory();\n await root.getDirectoryHandle(OPFS_DB_DIR, { create: true });\n}\n\nasync function createConnection(path: string | null): Promise<{\n db: AsyncDuckDB;\n conn: AsyncDuckDBConnection;\n worker: Worker;\n}> {\n const bundle = await duckdb.selectBundle(MANUAL_BUNDLES);\n const worker = new Worker(bundle.mainWorker!);\n const log = new duckdb.ConsoleLogger();\n const db = new duckdb.AsyncDuckDB(log, worker);\n await db.instantiate(bundle.mainModule, bundle.pthreadWorker);\n if (path) {\n await ensureOPFSDatabaseDir();\n await db.open({\n path,\n accessMode: duckdb.DuckDBAccessMode.READ_WRITE,\n });\n logger.info(`DuckDB-WASM opened: ${path} (read-write)`);\n }\n const conn = await db.connect();\n logger.info('DuckDB-WASM initialized');\n return { db, conn, worker };\n}\n\n/**\n * Abstraction over a single DuckDB database. Use runQuery, enableExtension, close, or delete.\n */\nexport class DuckDBDatabase {\n private readonly key: string;\n\n constructor(\n readonly name: string | null,\n private db: AsyncDuckDB,\n private conn: AsyncDuckDBConnection,\n private worker: Worker,\n private onClose: (key: string) => void,\n private onDeleteFromOPFS?: (name: string) => Promise<void>,\n ) {\n this.key = name ?? IN_MEMORY_KEY;\n }\n\n async runQuery(sql: string): Promise<DuckDBQueryResult> {\n const trimmed = sql.trim();\n if (!trimmed) return { rows: [], columns: [] };\n\n try {\n const table = await this.conn.query(trimmed);\n return tableToPlainArrays(table);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.error(`Query failed: ${msg}`);\n throw new Error(`Query failed: ${msg}`);\n }\n }\n\n async enableExtension(extensionName: string): Promise<void> {\n if (!EXTENSION_NAME_REGEX.test(extensionName)) {\n throw new Error(`Invalid extension name: ${extensionName}`);\n }\n const installSql = `INSTALL ${extensionName}`;\n const loadSql = `LOAD ${extensionName}`;\n try {\n await this.conn.query(installSql);\n await this.conn.query(loadSql);\n logger.info(`DuckDB extension enabled: ${extensionName}`);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.error(`Failed to enable extension ${extensionName}: ${msg}`);\n throw new Error(`Failed to enable extension ${extensionName}: ${msg}`);\n }\n }\n\n async close(): Promise<void> {\n try {\n await this.conn.close();\n } catch (e) {\n logger.warn('Error closing DuckDB connection: ' + (e instanceof Error ? e.message : String(e)));\n }\n try {\n this.db.terminate();\n } catch (e) {\n logger.warn('Error terminating DuckDB: ' + (e instanceof Error ? e.message : String(e)));\n }\n this.onClose(this.key);\n }\n}\n\nexport class DuckDBService {\n private databases = new Map<string, DuckDBDatabase>();\n\n private keyFor(name: string | undefined): string {\n return name === undefined || name === '' ? IN_MEMORY_KEY : name;\n }\n\n /**\n * Open a database by name. Stored in OPFS as `duckdb-databases/<name>.duckdb`. Omit name for in-memory.\n * Returns the same abstraction if that database is already open.\n */\n async open(name?: string): Promise<DuckDBDatabase> {\n const key = this.keyFor(name);\n const existing = this.databases.get(key);\n if (existing) return existing;\n\n if (key !== IN_MEMORY_KEY && !DB_NAME_REGEX.test(name!)) {\n throw new Error(`Invalid database name: ${name}`);\n }\n\n const nameOrNull = name === undefined || name === '' ? null : name;\n const path = nameOrNull ? pathFor(nameOrNull) : null;\n const { db, conn, worker } = await createConnection(path);\n\n const dbObj = new DuckDBDatabase(\n nameOrNull,\n db,\n conn,\n worker,\n (k) => this.databases.delete(k),\n nameOrNull ? (n) => this.removeOPFSDatabase(n) : undefined,\n );\n this.databases.set(key, dbObj);\n return dbObj;\n }\n\n /**\n * List persisted database names (files in OPFS under duckdb-databases/, without .duckdb extension).\n */\n async listDatabases(): Promise<string[]> {\n try {\n const root = await navigator.storage.getDirectory();\n const dir = await root.getDirectoryHandle(OPFS_DB_DIR, { create: false });\n const names: string[] = [];\n for await (const [entryName, handle] of (dir as unknown as AsyncIterable<[string, FileSystemHandle]>)) {\n if (handle.kind === 'file' && entryName.endsWith('.duckdb')) {\n names.push(entryName.slice(0, -'.duckdb'.length));\n }\n }\n return names.sort();\n } catch (err: unknown) {\n if (err instanceof Error && err.name === 'NotFoundError') return [];\n const msg = err instanceof Error ? err.message : String(err);\n logger.error(`listDatabases failed: ${msg}`);\n return [];\n }\n }\n\n /**\n * Close the database if open and remove its file from OPFS. Name is the simple database name (e.g. `appspace`).\n */\n async delete(name: string): Promise<void> {\n if (!DB_NAME_REGEX.test(name)) {\n throw new Error(`Invalid database name: ${name}`);\n }\n const existing = this.databases.get(name);\n if (existing) await existing.close();\n await this.removeOPFSDatabase(name);\n }\n\n private async removeOPFSDatabase(name: string): Promise<void> {\n try {\n const root = await navigator.storage.getDirectory();\n const dir = await root.getDirectoryHandle(OPFS_DB_DIR, { create: false });\n await dir.removeEntry(`${name}.duckdb`);\n logger.info(`DuckDB removed: ${name}`);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.error(`Failed to delete database ${name}: ${msg}`);\n throw new Error(`Failed to delete database: ${msg}`);\n }\n }\n}\n\nexport const duckdbService = new DuckDBService();\n","import { css, html, LitElement } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { repeat } from \"lit/directives/repeat.js\";\nimport { rootContext } from \"@eclipse-lyra/core\";\nimport type { DuckDBDatabase } from \"./duckdb-service\";\n\nexport const DUCKDB_AVAILABLE_EXTENSIONS: { name: string; description: string }[] = [\n { name: \"json\", description: \"JSON file and functions\" },\n { name: \"parquet\", description: \"Parquet file support\" },\n { name: \"csv\", description: \"CSV file support\" },\n { name: \"httpfs\", description: \"HTTP(S) and S3 access\" },\n { name: \"fts\", description: \"Full-text search\" },\n { name: \"inet\", description: \"IP address types\" },\n { name: \"jemalloc\", description: \"Memory allocator\" },\n { name: \"substrait\", description: \"Substrait integration\" },\n];\n\nexport interface DuckDBExtensionManagerOptions {\n db: DuckDBDatabase | null;\n databaseLabel: string;\n}\n\n@customElement(\"lyra-duckdb-extension-manager\")\nexport class LyraDuckDBExtensionManager extends LitElement {\n @property({ type: Boolean })\n open = false;\n\n @property({ attribute: false })\n db: DuckDBDatabase | null = null;\n\n @property()\n databaseLabel = \"In-memory\";\n\n @state()\n private selectedExtensions = new Set<string>();\n\n @state()\n private installing = false;\n\n @state()\n private installError: string | null = null;\n\n public configure(options: DuckDBExtensionManagerOptions) {\n this.db = options.db;\n this.databaseLabel = options.databaseLabel;\n this.selectedExtensions = new Set();\n this.installError = null;\n }\n\n public show() {\n this.open = true;\n }\n\n public hide() {\n this.open = false;\n }\n\n private toggleExtension(name: string) {\n const next = new Set(this.selectedExtensions);\n if (next.has(name)) next.delete(name);\n else next.add(name);\n this.selectedExtensions = next;\n this.installError = null;\n }\n\n private async installSelected() {\n if (!this.db || this.selectedExtensions.size === 0) return;\n this.installing = true;\n this.installError = null;\n const toInstall = [...this.selectedExtensions];\n try {\n for (const name of toInstall) {\n await this.db.enableExtension(name);\n }\n this.selectedExtensions = new Set();\n } catch (err) {\n this.installError = err instanceof Error ? err.message : String(err);\n } finally {\n this.installing = false;\n }\n }\n\n render() {\n const dbReady = this.db !== null;\n const canInstall = dbReady && this.selectedExtensions.size > 0 && !this.installing;\n\n return html`\n <wa-dialog\n label=\"DuckDB extensions\"\n ?open=${this.open}\n @wa-after-hide=${() => {\n this.open = false;\n this.dispatchEvent(new CustomEvent(\"hide\", { bubbles: true, composed: true }));\n }}\n >\n <div class=\"extension-manager\">\n <p class=\"extension-manager-description\">\n Database: <strong>${this.databaseLabel}</strong>. Select extensions to install.\n </p>\n\n ${!dbReady\n ? html`\n <wa-alert variant=\"warning\" open>\n <wa-icon slot=\"icon\" name=\"triangle-exclamation\"></wa-icon>\n Open or create a database and run a query first so a connection exists.\n </wa-alert>\n `\n : \"\"}\n\n ${this.installError\n ? html`\n <wa-alert variant=\"danger\" open closable @wa-after-hide=${() => (this.installError = null)}>\n <wa-icon slot=\"icon\" name=\"circle-exclamation\"></wa-icon>\n ${this.installError}\n </wa-alert>\n `\n : \"\"}\n\n <div class=\"extension-list\">\n <div class=\"extension-list-header\">\n <strong>Available extensions</strong>\n </div>\n ${repeat(\n DUCKDB_AVAILABLE_EXTENSIONS,\n (ext) => ext.name,\n (ext) => html`\n <div class=\"extension-item\">\n <wa-checkbox\n ?checked=${this.selectedExtensions.has(ext.name)}\n ?disabled=${!dbReady}\n @wa-change=${() => this.toggleExtension(ext.name)}\n >\n <span class=\"extension-name\">${ext.name}</span>\n <span class=\"extension-desc\">${ext.description}</span>\n </wa-checkbox>\n </div>\n `\n )}\n </div>\n </div>\n <div slot=\"footer\" class=\"extension-manager-footer\">\n <wa-button\n variant=\"primary\"\n ?disabled=${!canInstall}\n @click=${() => this.installSelected()}\n >\n ${this.installing ? \"Installing…\" : `Install selected (${this.selectedExtensions.size})`}\n </wa-button>\n <wa-button variant=\"default\" @click=${() => this.hide()}>\n Done\n </wa-button>\n </div>\n </wa-dialog>\n `;\n }\n\n static styles = css`\n :host {\n display: contents;\n }\n\n .extension-manager {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n padding: 1rem;\n }\n\n .extension-manager-description {\n margin: 0;\n font-size: 0.95rem;\n opacity: 0.9;\n }\n\n .extension-list {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n max-height: 360px;\n overflow-y: auto;\n }\n\n .extension-list-header {\n padding: 0.5rem 0;\n border-bottom: 1px solid var(--wa-color-neutral-200, #e5e7eb);\n margin-bottom: 0.25rem;\n }\n\n .extension-item {\n display: flex;\n align-items: center;\n padding: 0.5rem 0;\n }\n\n .extension-item wa-checkbox {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex: 1;\n }\n\n .extension-name {\n font-family: ui-monospace, monospace;\n font-size: 0.95rem;\n min-width: 6rem;\n }\n\n .extension-desc {\n font-size: 0.875rem;\n opacity: 0.8;\n }\n\n .extension-manager-footer {\n display: flex;\n gap: 0.5rem;\n justify-content: flex-end;\n padding-top: 1rem;\n border-top: 1px solid var(--wa-color-neutral-200, #e5e7eb);\n }\n `;\n}\n\nclass DuckDBExtensionManagerService {\n private managerInstance: LyraDuckDBExtensionManager | null = null;\n\n public showExtensionManager(options: DuckDBExtensionManagerOptions): LyraDuckDBExtensionManager {\n if (!this.managerInstance) {\n this.managerInstance = document.createElement(\"lyra-duckdb-extension-manager\") as LyraDuckDBExtensionManager;\n document.body.appendChild(this.managerInstance);\n }\n this.managerInstance.configure(options);\n this.managerInstance.show();\n return this.managerInstance;\n }\n\n public getManager(): LyraDuckDBExtensionManager | null {\n return this.managerInstance;\n }\n}\n\nexport const duckdbExtensionManagerService = new DuckDBExtensionManagerService();\nrootContext.put(\"duckdbExtensionManagerService\", duckdbExtensionManagerService);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"lyra-duckdb-extension-manager\": LyraDuckDBExtensionManager;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"duckdb-service.d.ts","sourceRoot":"","sources":["../src/duckdb-service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"duckdb-service.d.ts","sourceRoot":"","sources":["../src/duckdb-service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,MAAM,qBAAqB,CAAC;AAsB9C,KAAK,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;AACtC,KAAK,qBAAqB,GAAG,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAEzE,wEAAwE;AACxE,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC;CACnB;AAiDD;;GAEG;AACH,qBAAa,cAAc;IAIvB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAC5B,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,gBAAgB,CAAC;IAR3B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;gBAGlB,IAAI,EAAE,MAAM,GAAG,IAAI,EACpB,EAAE,EAAE,WAAW,EACf,IAAI,EAAE,qBAAqB,EAC3B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,EAC9B,gBAAgB,CAAC,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,aAAA;IAKtD,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAcjD,eAAe,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBrD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAa7B;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,SAAS,CAAqC;IAEtD,OAAO,CAAC,MAAM;IAId;;;OAGG;IACG,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAyBlD;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAmBxC;;OAEG;IACG,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAS3B,kBAAkB;CAYjC;AAED,eAAO,MAAM,aAAa,eAAsB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { contributionRegistry, SYSTEM_LANGUAGE_BUNDLES, i18nLazy, extensionRegistry } from "@eclipse-lyra/core";
|
|
2
|
-
import pkg from "
|
|
2
|
+
import pkg from "./home/runner/work/core/core/packages/extension-duckdb/package.json";
|
|
3
3
|
const namespace = "extensions";
|
|
4
4
|
const en = { "EXT_DUCKDB_NAME": "DuckDB", "EXT_DUCKDB_DESC": "In-browser SQL engine (DuckDB-WASM) for advanced queries, analytics, and Parquet/CSV/JSON." };
|
|
5
5
|
const de = { "EXT_DUCKDB_NAME": "DuckDB", "EXT_DUCKDB_DESC": "SQL-Engine im Browser (DuckDB-WASM) für erweiterte Abfragen, Analysen und Parquet/CSV/JSON." };
|
|
@@ -14,7 +14,7 @@ extensionRegistry.registerExtension({
|
|
|
14
14
|
id: pkg.name,
|
|
15
15
|
name: t("EXT_DUCKDB_NAME"),
|
|
16
16
|
description: t("EXT_DUCKDB_DESC"),
|
|
17
|
-
loader: () => import("./duckdb-extension-
|
|
17
|
+
loader: () => import("./duckdb-extension-C_6Yn0IO.js"),
|
|
18
18
|
icon: "database",
|
|
19
19
|
dependencies: ["@eclipse-lyra/extension-monaco-editor"]
|
|
20
20
|
});
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"duckdb-extension-manager-hie2HG1j.js","sources":["../src/duckdb-service.ts","../src/duckdb-extension-manager.ts"],"sourcesContent":["import { createLogger } from '@eclipse-lyra/core';\nimport * as duckdb from '@duckdb/duckdb-wasm';\n\nconst logger = createLogger('DuckDBService');\n\nconst JSDELIVR_BUNDLES = duckdb.getJsDelivrBundles();\n\nconst IN_MEMORY_KEY = '__memory__';\nconst OPFS_DB_DIR = 'duckdb-databases';\nconst EXTENSION_NAME_REGEX = /^[a-zA-Z][a-zA-Z0-9_]*$/;\nconst DB_NAME_REGEX = /^[a-zA-Z0-9_.-]+$/;\n\nfunction pathFor(name: string): string {\n return `opfs://${OPFS_DB_DIR}/${name}.duckdb`;\n}\n\ntype AsyncDuckDB = duckdb.AsyncDuckDB;\ntype AsyncDuckDBConnection = Awaited<ReturnType<AsyncDuckDB['connect']>>;\n\n/** Plain JS result: columns in order, rows as array of value arrays. */\nexport interface DuckDBQueryResult {\n columns: string[];\n rows: unknown[][];\n}\n\nfunction toPlainValue(v: unknown): unknown {\n if (v === null || v === undefined) return v;\n if (typeof v === 'bigint') return Number(v);\n if (v instanceof Date) return v.toISOString();\n if (typeof v === 'object' && v !== null && typeof (v as { toJSON: unknown }).toJSON === 'function') {\n return (v as { toJSON: () => unknown }).toJSON();\n }\n return v;\n}\n\nfunction tableToPlainArrays(table: { toArray?: () => unknown[] }): { columns: string[]; rows: unknown[][] } {\n const raw = table.toArray?.();\n const rowObjects = Array.isArray(raw) ? (raw as Record<string, unknown>[]) : [];\n if (rowObjects.length === 0) return { columns: [], rows: [] };\n const columns = Object.keys(rowObjects[0]);\n const rows = rowObjects.map((obj) => columns.map((col) => toPlainValue(obj[col])));\n return { columns, rows };\n}\n\nasync function ensureOPFSDatabaseDir(): Promise<void> {\n const root = await navigator.storage.getDirectory();\n await root.getDirectoryHandle(OPFS_DB_DIR, { create: true });\n}\n\nasync function createConnection(path: string | null): Promise<{\n db: AsyncDuckDB;\n conn: AsyncDuckDBConnection;\n worker: Worker;\n}> {\n const bundle = await duckdb.selectBundle(JSDELIVR_BUNDLES);\n const workerUrl = URL.createObjectURL(\n new Blob([`importScripts(\"${bundle.mainWorker}\");`], { type: 'text/javascript' }),\n );\n const worker = new Worker(workerUrl);\n URL.revokeObjectURL(workerUrl);\n const log = new duckdb.ConsoleLogger();\n const db = new duckdb.AsyncDuckDB(log, worker);\n await db.instantiate(bundle.mainModule, bundle.pthreadWorker);\n if (path) {\n await ensureOPFSDatabaseDir();\n await db.open({\n path,\n accessMode: duckdb.DuckDBAccessMode.READ_WRITE,\n });\n logger.info(`DuckDB-WASM opened: ${path} (read-write)`);\n }\n const conn = await db.connect();\n logger.info('DuckDB-WASM initialized');\n return { db, conn, worker };\n}\n\n/**\n * Abstraction over a single DuckDB database. Use runQuery, enableExtension, close, or delete.\n */\nexport class DuckDBDatabase {\n private readonly key: string;\n\n constructor(\n readonly name: string | null,\n private db: AsyncDuckDB,\n private conn: AsyncDuckDBConnection,\n private worker: Worker,\n private onClose: (key: string) => void,\n private onDeleteFromOPFS?: (name: string) => Promise<void>,\n ) {\n this.key = name ?? IN_MEMORY_KEY;\n }\n\n async runQuery(sql: string): Promise<DuckDBQueryResult> {\n const trimmed = sql.trim();\n if (!trimmed) return { rows: [], columns: [] };\n\n try {\n const table = await this.conn.query(trimmed);\n return tableToPlainArrays(table);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.error(`Query failed: ${msg}`);\n throw new Error(`Query failed: ${msg}`);\n }\n }\n\n async enableExtension(extensionName: string): Promise<void> {\n if (!EXTENSION_NAME_REGEX.test(extensionName)) {\n throw new Error(`Invalid extension name: ${extensionName}`);\n }\n const installSql = `INSTALL ${extensionName}`;\n const loadSql = `LOAD ${extensionName}`;\n try {\n await this.conn.query(installSql);\n await this.conn.query(loadSql);\n logger.info(`DuckDB extension enabled: ${extensionName}`);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.error(`Failed to enable extension ${extensionName}: ${msg}`);\n throw new Error(`Failed to enable extension ${extensionName}: ${msg}`);\n }\n }\n\n async close(): Promise<void> {\n try {\n await this.conn.close();\n } catch (e) {\n logger.warn('Error closing DuckDB connection: ' + (e instanceof Error ? e.message : String(e)));\n }\n try {\n this.db.terminate();\n } catch (e) {\n logger.warn('Error terminating DuckDB: ' + (e instanceof Error ? e.message : String(e)));\n }\n this.onClose(this.key);\n }\n}\n\nexport class DuckDBService {\n private databases = new Map<string, DuckDBDatabase>();\n\n private keyFor(name: string | undefined): string {\n return name === undefined || name === '' ? IN_MEMORY_KEY : name;\n }\n\n /**\n * Open a database by name. Stored in OPFS as `duckdb-databases/<name>.duckdb`. Omit name for in-memory.\n * Returns the same abstraction if that database is already open.\n */\n async open(name?: string): Promise<DuckDBDatabase> {\n const key = this.keyFor(name);\n const existing = this.databases.get(key);\n if (existing) return existing;\n\n if (key !== IN_MEMORY_KEY && !DB_NAME_REGEX.test(name!)) {\n throw new Error(`Invalid database name: ${name}`);\n }\n\n const nameOrNull = name === undefined || name === '' ? null : name;\n const path = nameOrNull ? pathFor(nameOrNull) : null;\n const { db, conn, worker } = await createConnection(path);\n\n const dbObj = new DuckDBDatabase(\n nameOrNull,\n db,\n conn,\n worker,\n (k) => this.databases.delete(k),\n nameOrNull ? (n) => this.removeOPFSDatabase(n) : undefined,\n );\n this.databases.set(key, dbObj);\n return dbObj;\n }\n\n /**\n * List persisted database names (files in OPFS under duckdb-databases/, without .duckdb extension).\n */\n async listDatabases(): Promise<string[]> {\n try {\n const root = await navigator.storage.getDirectory();\n const dir = await root.getDirectoryHandle(OPFS_DB_DIR, { create: false });\n const names: string[] = [];\n for await (const [entryName, handle] of (dir as unknown as AsyncIterable<[string, FileSystemHandle]>)) {\n if (handle.kind === 'file' && entryName.endsWith('.duckdb')) {\n names.push(entryName.slice(0, -'.duckdb'.length));\n }\n }\n return names.sort();\n } catch (err: unknown) {\n if (err instanceof Error && err.name === 'NotFoundError') return [];\n const msg = err instanceof Error ? err.message : String(err);\n logger.error(`listDatabases failed: ${msg}`);\n return [];\n }\n }\n\n /**\n * Close the database if open and remove its file from OPFS. Name is the simple database name (e.g. `appspace`).\n */\n async delete(name: string): Promise<void> {\n if (!DB_NAME_REGEX.test(name)) {\n throw new Error(`Invalid database name: ${name}`);\n }\n const existing = this.databases.get(name);\n if (existing) await existing.close();\n await this.removeOPFSDatabase(name);\n }\n\n private async removeOPFSDatabase(name: string): Promise<void> {\n try {\n const root = await navigator.storage.getDirectory();\n const dir = await root.getDirectoryHandle(OPFS_DB_DIR, { create: false });\n await dir.removeEntry(`${name}.duckdb`);\n logger.info(`DuckDB removed: ${name}`);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n logger.error(`Failed to delete database ${name}: ${msg}`);\n throw new Error(`Failed to delete database: ${msg}`);\n }\n }\n}\n\nexport const duckdbService = new DuckDBService();\n","import { css, html, LitElement } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { repeat } from \"lit/directives/repeat.js\";\nimport { rootContext } from \"@eclipse-lyra/core\";\nimport type { DuckDBDatabase } from \"./duckdb-service\";\n\nexport const DUCKDB_AVAILABLE_EXTENSIONS: { name: string; description: string }[] = [\n { name: \"json\", description: \"JSON file and functions\" },\n { name: \"parquet\", description: \"Parquet file support\" },\n { name: \"csv\", description: \"CSV file support\" },\n { name: \"httpfs\", description: \"HTTP(S) and S3 access\" },\n { name: \"fts\", description: \"Full-text search\" },\n { name: \"inet\", description: \"IP address types\" },\n { name: \"jemalloc\", description: \"Memory allocator\" },\n { name: \"substrait\", description: \"Substrait integration\" },\n];\n\nexport interface DuckDBExtensionManagerOptions {\n db: DuckDBDatabase | null;\n databaseLabel: string;\n}\n\n@customElement(\"lyra-duckdb-extension-manager\")\nexport class LyraDuckDBExtensionManager extends LitElement {\n @property({ type: Boolean })\n open = false;\n\n @property({ attribute: false })\n db: DuckDBDatabase | null = null;\n\n @property()\n databaseLabel = \"In-memory\";\n\n @state()\n private selectedExtensions = new Set<string>();\n\n @state()\n private installing = false;\n\n @state()\n private installError: string | null = null;\n\n public configure(options: DuckDBExtensionManagerOptions) {\n this.db = options.db;\n this.databaseLabel = options.databaseLabel;\n this.selectedExtensions = new Set();\n this.installError = null;\n }\n\n public show() {\n this.open = true;\n }\n\n public hide() {\n this.open = false;\n }\n\n private toggleExtension(name: string) {\n const next = new Set(this.selectedExtensions);\n if (next.has(name)) next.delete(name);\n else next.add(name);\n this.selectedExtensions = next;\n this.installError = null;\n }\n\n private async installSelected() {\n if (!this.db || this.selectedExtensions.size === 0) return;\n this.installing = true;\n this.installError = null;\n const toInstall = [...this.selectedExtensions];\n try {\n for (const name of toInstall) {\n await this.db.enableExtension(name);\n }\n this.selectedExtensions = new Set();\n } catch (err) {\n this.installError = err instanceof Error ? err.message : String(err);\n } finally {\n this.installing = false;\n }\n }\n\n render() {\n const dbReady = this.db !== null;\n const canInstall = dbReady && this.selectedExtensions.size > 0 && !this.installing;\n\n return html`\n <wa-dialog\n label=\"DuckDB extensions\"\n ?open=${this.open}\n @wa-after-hide=${() => {\n this.open = false;\n this.dispatchEvent(new CustomEvent(\"hide\", { bubbles: true, composed: true }));\n }}\n >\n <div class=\"extension-manager\">\n <p class=\"extension-manager-description\">\n Database: <strong>${this.databaseLabel}</strong>. Select extensions to install.\n </p>\n\n ${!dbReady\n ? html`\n <wa-alert variant=\"warning\" open>\n <wa-icon slot=\"icon\" name=\"triangle-exclamation\"></wa-icon>\n Open or create a database and run a query first so a connection exists.\n </wa-alert>\n `\n : \"\"}\n\n ${this.installError\n ? html`\n <wa-alert variant=\"danger\" open closable @wa-after-hide=${() => (this.installError = null)}>\n <wa-icon slot=\"icon\" name=\"circle-exclamation\"></wa-icon>\n ${this.installError}\n </wa-alert>\n `\n : \"\"}\n\n <div class=\"extension-list\">\n <div class=\"extension-list-header\">\n <strong>Available extensions</strong>\n </div>\n ${repeat(\n DUCKDB_AVAILABLE_EXTENSIONS,\n (ext) => ext.name,\n (ext) => html`\n <div class=\"extension-item\">\n <wa-checkbox\n ?checked=${this.selectedExtensions.has(ext.name)}\n ?disabled=${!dbReady}\n @wa-change=${() => this.toggleExtension(ext.name)}\n >\n <span class=\"extension-name\">${ext.name}</span>\n <span class=\"extension-desc\">${ext.description}</span>\n </wa-checkbox>\n </div>\n `\n )}\n </div>\n </div>\n <div slot=\"footer\" class=\"extension-manager-footer\">\n <wa-button\n variant=\"primary\"\n ?disabled=${!canInstall}\n @click=${() => this.installSelected()}\n >\n ${this.installing ? \"Installing…\" : `Install selected (${this.selectedExtensions.size})`}\n </wa-button>\n <wa-button variant=\"default\" @click=${() => this.hide()}>\n Done\n </wa-button>\n </div>\n </wa-dialog>\n `;\n }\n\n static styles = css`\n :host {\n display: contents;\n }\n\n .extension-manager {\n display: flex;\n flex-direction: column;\n gap: 1rem;\n padding: 1rem;\n }\n\n .extension-manager-description {\n margin: 0;\n font-size: 0.95rem;\n opacity: 0.9;\n }\n\n .extension-list {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n max-height: 360px;\n overflow-y: auto;\n }\n\n .extension-list-header {\n padding: 0.5rem 0;\n border-bottom: 1px solid var(--wa-color-neutral-200, #e5e7eb);\n margin-bottom: 0.25rem;\n }\n\n .extension-item {\n display: flex;\n align-items: center;\n padding: 0.5rem 0;\n }\n\n .extension-item wa-checkbox {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex: 1;\n }\n\n .extension-name {\n font-family: ui-monospace, monospace;\n font-size: 0.95rem;\n min-width: 6rem;\n }\n\n .extension-desc {\n font-size: 0.875rem;\n opacity: 0.8;\n }\n\n .extension-manager-footer {\n display: flex;\n gap: 0.5rem;\n justify-content: flex-end;\n padding-top: 1rem;\n border-top: 1px solid var(--wa-color-neutral-200, #e5e7eb);\n }\n `;\n}\n\nclass DuckDBExtensionManagerService {\n private managerInstance: LyraDuckDBExtensionManager | null = null;\n\n public showExtensionManager(options: DuckDBExtensionManagerOptions): LyraDuckDBExtensionManager {\n if (!this.managerInstance) {\n this.managerInstance = document.createElement(\"lyra-duckdb-extension-manager\") as LyraDuckDBExtensionManager;\n document.body.appendChild(this.managerInstance);\n }\n this.managerInstance.configure(options);\n this.managerInstance.show();\n return this.managerInstance;\n }\n\n public getManager(): LyraDuckDBExtensionManager | null {\n return this.managerInstance;\n }\n}\n\nexport const duckdbExtensionManagerService = new DuckDBExtensionManagerService();\nrootContext.put(\"duckdbExtensionManagerService\", duckdbExtensionManagerService);\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"lyra-duckdb-extension-manager\": LyraDuckDBExtensionManager;\n }\n}\n"],"names":[],"mappings":";;;;;AAGA,MAAM,SAAS,aAAa,eAAe;AAE3C,MAAM,mBAAmB,OAAO,mBAAA;AAEhC,MAAM,gBAAgB;AACtB,MAAM,cAAc;AACpB,MAAM,uBAAuB;AAC7B,MAAM,gBAAgB;AAEtB,SAAS,QAAQ,MAAsB;AACrC,SAAO,UAAU,WAAW,IAAI,IAAI;AACtC;AAWA,SAAS,aAAa,GAAqB;AACzC,MAAI,MAAM,QAAQ,MAAM,OAAW,QAAO;AAC1C,MAAI,OAAO,MAAM,SAAU,QAAO,OAAO,CAAC;AAC1C,MAAI,aAAa,KAAM,QAAO,EAAE,YAAA;AAChC,MAAI,OAAO,MAAM,YAAY,MAAM,QAAQ,OAAQ,EAA0B,WAAW,YAAY;AAClG,WAAQ,EAAgC,OAAA;AAAA,EAC1C;AACA,SAAO;AACT;AAEA,SAAS,mBAAmB,OAAgF;AAC1G,QAAM,MAAM,MAAM,UAAA;AAClB,QAAM,aAAa,MAAM,QAAQ,GAAG,IAAK,MAAoC,CAAA;AAC7E,MAAI,WAAW,WAAW,EAAG,QAAO,EAAE,SAAS,CAAA,GAAI,MAAM,GAAC;AAC1D,QAAM,UAAU,OAAO,KAAK,WAAW,CAAC,CAAC;AACzC,QAAM,OAAO,WAAW,IAAI,CAAC,QAAQ,QAAQ,IAAI,CAAC,QAAQ,aAAa,IAAI,GAAG,CAAC,CAAC,CAAC;AACjF,SAAO,EAAE,SAAS,KAAA;AACpB;AAEA,eAAe,wBAAuC;AACpD,QAAM,OAAO,MAAM,UAAU,QAAQ,aAAA;AACrC,QAAM,KAAK,mBAAmB,aAAa,EAAE,QAAQ,MAAM;AAC7D;AAEA,eAAe,iBAAiB,MAI7B;AACD,QAAM,SAAS,MAAM,OAAO,aAAa,gBAAgB;AACzD,QAAM,YAAY,IAAI;AAAA,IACpB,IAAI,KAAK,CAAC,kBAAkB,OAAO,UAAU,KAAK,GAAG,EAAE,MAAM,kBAAA,CAAmB;AAAA,EAAA;AAElF,QAAM,SAAS,IAAI,OAAO,SAAS;AACnC,MAAI,gBAAgB,SAAS;AAC7B,QAAM,MAAM,IAAI,OAAO,cAAA;AACvB,QAAM,KAAK,IAAI,OAAO,YAAY,KAAK,MAAM;AAC7C,QAAM,GAAG,YAAY,OAAO,YAAY,OAAO,aAAa;AAC5D,MAAI,MAAM;AACR,UAAM,sBAAA;AACN,UAAM,GAAG,KAAK;AAAA,MACZ;AAAA,MACA,YAAY,OAAO,iBAAiB;AAAA,IAAA,CACrC;AACD,WAAO,KAAK,uBAAuB,IAAI,eAAe;AAAA,EACxD;AACA,QAAM,OAAO,MAAM,GAAG,QAAA;AACtB,SAAO,KAAK,yBAAyB;AACrC,SAAO,EAAE,IAAI,MAAM,OAAA;AACrB;AAKO,MAAM,eAAe;AAAA,EAG1B,YACW,MACD,IACA,MACA,QACA,SACA,kBACR;AANS,SAAA,OAAA;AACD,SAAA,KAAA;AACA,SAAA,OAAA;AACA,SAAA,SAAA;AACA,SAAA,UAAA;AACA,SAAA,mBAAA;AAER,SAAK,MAAM,QAAQ;AAAA,EACrB;AAAA,EAEA,MAAM,SAAS,KAAyC;AACtD,UAAM,UAAU,IAAI,KAAA;AACpB,QAAI,CAAC,QAAS,QAAO,EAAE,MAAM,CAAA,GAAI,SAAS,GAAC;AAE3C,QAAI;AACF,YAAM,QAAQ,MAAM,KAAK,KAAK,MAAM,OAAO;AAC3C,aAAO,mBAAmB,KAAK;AAAA,IACjC,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,aAAO,MAAM,iBAAiB,GAAG,EAAE;AACnC,YAAM,IAAI,MAAM,iBAAiB,GAAG,EAAE;AAAA,IACxC;AAAA,EACF;AAAA,EAEA,MAAM,gBAAgB,eAAsC;AAC1D,QAAI,CAAC,qBAAqB,KAAK,aAAa,GAAG;AAC7C,YAAM,IAAI,MAAM,2BAA2B,aAAa,EAAE;AAAA,IAC5D;AACA,UAAM,aAAa,WAAW,aAAa;AAC3C,UAAM,UAAU,QAAQ,aAAa;AACrC,QAAI;AACF,YAAM,KAAK,KAAK,MAAM,UAAU;AAChC,YAAM,KAAK,KAAK,MAAM,OAAO;AAC7B,aAAO,KAAK,6BAA6B,aAAa,EAAE;AAAA,IAC1D,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,aAAO,MAAM,8BAA8B,aAAa,KAAK,GAAG,EAAE;AAClE,YAAM,IAAI,MAAM,8BAA8B,aAAa,KAAK,GAAG,EAAE;AAAA,IACvE;AAAA,EACF;AAAA,EAEA,MAAM,QAAuB;AAC3B,QAAI;AACF,YAAM,KAAK,KAAK,MAAA;AAAA,IAClB,SAAS,GAAG;AACV,aAAO,KAAK,uCAAuC,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,EAAE;AAAA,IAChG;AACA,QAAI;AACF,WAAK,GAAG,UAAA;AAAA,IACV,SAAS,GAAG;AACV,aAAO,KAAK,gCAAgC,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,EAAE;AAAA,IACzF;AACA,SAAK,QAAQ,KAAK,GAAG;AAAA,EACvB;AACF;AAEO,MAAM,cAAc;AAAA,EAApB,cAAA;AACL,SAAQ,gCAAgB,IAAA;AAAA,EAA4B;AAAA,EAE5C,OAAO,MAAkC;AAC/C,WAAO,SAAS,UAAa,SAAS,KAAK,gBAAgB;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,KAAK,MAAwC;AACjD,UAAM,MAAM,KAAK,OAAO,IAAI;AAC5B,UAAM,WAAW,KAAK,UAAU,IAAI,GAAG;AACvC,QAAI,SAAU,QAAO;AAErB,QAAI,QAAQ,iBAAiB,CAAC,cAAc,KAAK,IAAK,GAAG;AACvD,YAAM,IAAI,MAAM,0BAA0B,IAAI,EAAE;AAAA,IAClD;AAEA,UAAM,aAAa,SAAS,UAAa,SAAS,KAAK,OAAO;AAC9D,UAAM,OAAO,aAAa,QAAQ,UAAU,IAAI;AAChD,UAAM,EAAE,IAAI,MAAM,WAAW,MAAM,iBAAiB,IAAI;AAExD,UAAM,QAAQ,IAAI;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,CAAC,MAAM,KAAK,UAAU,OAAO,CAAC;AAAA,MAC9B,aAAa,CAAC,MAAM,KAAK,mBAAmB,CAAC,IAAI;AAAA,IAAA;AAEnD,SAAK,UAAU,IAAI,KAAK,KAAK;AAC7B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,gBAAmC;AACvC,QAAI;AACF,YAAM,OAAO,MAAM,UAAU,QAAQ,aAAA;AACrC,YAAM,MAAM,MAAM,KAAK,mBAAmB,aAAa,EAAE,QAAQ,OAAO;AACxE,YAAM,QAAkB,CAAA;AACxB,uBAAiB,CAAC,WAAW,MAAM,KAAM,KAA8D;AACrG,YAAI,OAAO,SAAS,UAAU,UAAU,SAAS,SAAS,GAAG;AAC3D,gBAAM,KAAK,UAAU,MAAM,GAAG,CAAC,UAAU,MAAM,CAAC;AAAA,QAClD;AAAA,MACF;AACA,aAAO,MAAM,KAAA;AAAA,IACf,SAAS,KAAc;AACrB,UAAI,eAAe,SAAS,IAAI,SAAS,wBAAwB,CAAA;AACjE,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,aAAO,MAAM,yBAAyB,GAAG,EAAE;AAC3C,aAAO,CAAA;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,MAA6B;AACxC,QAAI,CAAC,cAAc,KAAK,IAAI,GAAG;AAC7B,YAAM,IAAI,MAAM,0BAA0B,IAAI,EAAE;AAAA,IAClD;AACA,UAAM,WAAW,KAAK,UAAU,IAAI,IAAI;AACxC,QAAI,SAAU,OAAM,SAAS,MAAA;AAC7B,UAAM,KAAK,mBAAmB,IAAI;AAAA,EACpC;AAAA,EAEA,MAAc,mBAAmB,MAA6B;AAC5D,QAAI;AACF,YAAM,OAAO,MAAM,UAAU,QAAQ,aAAA;AACrC,YAAM,MAAM,MAAM,KAAK,mBAAmB,aAAa,EAAE,QAAQ,OAAO;AACxE,YAAM,IAAI,YAAY,GAAG,IAAI,SAAS;AACtC,aAAO,KAAK,mBAAmB,IAAI,EAAE;AAAA,IACvC,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,aAAO,MAAM,6BAA6B,IAAI,KAAK,GAAG,EAAE;AACxD,YAAM,IAAI,MAAM,8BAA8B,GAAG,EAAE;AAAA,IACrD;AAAA,EACF;AACF;AAEO,MAAM,gBAAgB,IAAI,cAAA;;;;;;;;;;;ACzN1B,MAAM,8BAAuE;AAAA,EAClF,EAAE,MAAM,QAAQ,aAAa,0BAAA;AAAA,EAC7B,EAAE,MAAM,WAAW,aAAa,uBAAA;AAAA,EAChC,EAAE,MAAM,OAAO,aAAa,mBAAA;AAAA,EAC5B,EAAE,MAAM,UAAU,aAAa,wBAAA;AAAA,EAC/B,EAAE,MAAM,OAAO,aAAa,mBAAA;AAAA,EAC5B,EAAE,MAAM,QAAQ,aAAa,mBAAA;AAAA,EAC7B,EAAE,MAAM,YAAY,aAAa,mBAAA;AAAA,EACjC,EAAE,MAAM,aAAa,aAAa,wBAAA;AACpC;AAQO,IAAM,6BAAN,cAAyC,WAAW;AAAA,EAApD,cAAA;AAAA,UAAA,GAAA,SAAA;AAEL,SAAA,OAAO;AAGP,SAAA,KAA4B;AAG5B,SAAA,gBAAgB;AAGhB,SAAQ,yCAAyB,IAAA;AAGjC,SAAQ,aAAa;AAGrB,SAAQ,eAA8B;AAAA,EAAA;AAAA,EAE/B,UAAU,SAAwC;AACvD,SAAK,KAAK,QAAQ;AAClB,SAAK,gBAAgB,QAAQ;AAC7B,SAAK,yCAAyB,IAAA;AAC9B,SAAK,eAAe;AAAA,EACtB;AAAA,EAEO,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AAAA,EAEO,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AAAA,EAEQ,gBAAgB,MAAc;AACpC,UAAM,OAAO,IAAI,IAAI,KAAK,kBAAkB;AAC5C,QAAI,KAAK,IAAI,IAAI,EAAG,MAAK,OAAO,IAAI;AAAA,QAC/B,MAAK,IAAI,IAAI;AAClB,SAAK,qBAAqB;AAC1B,SAAK,eAAe;AAAA,EACtB;AAAA,EAEA,MAAc,kBAAkB;AAC9B,QAAI,CAAC,KAAK,MAAM,KAAK,mBAAmB,SAAS,EAAG;AACpD,SAAK,aAAa;AAClB,SAAK,eAAe;AACpB,UAAM,YAAY,CAAC,GAAG,KAAK,kBAAkB;AAC7C,QAAI;AACF,iBAAW,QAAQ,WAAW;AAC5B,cAAM,KAAK,GAAG,gBAAgB,IAAI;AAAA,MACpC;AACA,WAAK,yCAAyB,IAAA;AAAA,IAChC,SAAS,KAAK;AACZ,WAAK,eAAe,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,IACrE,UAAA;AACE,WAAK,aAAa;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,SAAS;AACP,UAAM,UAAU,KAAK,OAAO;AAC5B,UAAM,aAAa,WAAW,KAAK,mBAAmB,OAAO,KAAK,CAAC,KAAK;AAExE,WAAO;AAAA;AAAA;AAAA,gBAGK,KAAK,IAAI;AAAA,yBACA,MAAM;AACrB,WAAK,OAAO;AACZ,WAAK,cAAc,IAAI,YAAY,QAAQ,EAAE,SAAS,MAAM,UAAU,KAAA,CAAM,CAAC;AAAA,IAC/E,CAAC;AAAA;AAAA;AAAA;AAAA,gCAIuB,KAAK,aAAa;AAAA;AAAA;AAAA,YAGtC,CAAC,UACC;AAAA;AAAA;AAAA;AAAA;AAAA,kBAMA,EAAE;AAAA;AAAA,YAEJ,KAAK,eACH;AAAA,0EAC4D,MAAO,KAAK,eAAe,IAAK;AAAA;AAAA,oBAEtF,KAAK,YAAY;AAAA;AAAA,kBAGvB,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAMF;AAAA,MACA;AAAA,MACA,CAAC,QAAQ,IAAI;AAAA,MACb,CAAC,QAAQ;AAAA;AAAA;AAAA,+BAGQ,KAAK,mBAAmB,IAAI,IAAI,IAAI,CAAC;AAAA,gCACpC,CAAC,OAAO;AAAA,iCACP,MAAM,KAAK,gBAAgB,IAAI,IAAI,CAAC;AAAA;AAAA,mDAElB,IAAI,IAAI;AAAA,mDACR,IAAI,WAAW;AAAA;AAAA;AAAA;AAAA,IAAA,CAIrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAMW,CAAC,UAAU;AAAA,qBACd,MAAM,KAAK,gBAAA,CAAiB;AAAA;AAAA,cAEnC,KAAK,aAAa,gBAAgB,qBAAqB,KAAK,mBAAmB,IAAI,GAAG;AAAA;AAAA,gDAEpD,MAAM,KAAK,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM/D;AAkEF;AArMa,2BAqIJ,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAnIhB,gBAAA;AAAA,EADC,SAAS,EAAE,MAAM,QAAA,CAAS;AAAA,GADhB,2BAEX,WAAA,QAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAS,EAAE,WAAW,MAAA,CAAO;AAAA,GAJnB,2BAKX,WAAA,MAAA,CAAA;AAGA,gBAAA;AAAA,EADC,SAAA;AAAS,GAPC,2BAQX,WAAA,iBAAA,CAAA;AAGQ,gBAAA;AAAA,EADP,MAAA;AAAM,GAVI,2BAWH,WAAA,sBAAA,CAAA;AAGA,gBAAA;AAAA,EADP,MAAA;AAAM,GAbI,2BAcH,WAAA,cAAA,CAAA;AAGA,gBAAA;AAAA,EADP,MAAA;AAAM,GAhBI,2BAiBH,WAAA,gBAAA,CAAA;AAjBG,6BAAN,gBAAA;AAAA,EADN,cAAc,+BAA+B;AAAA,GACjC,0BAAA;AAuMb,MAAM,8BAA8B;AAAA,EAApC,cAAA;AACE,SAAQ,kBAAqD;AAAA,EAAA;AAAA,EAEtD,qBAAqB,SAAoE;AAC9F,QAAI,CAAC,KAAK,iBAAiB;AACzB,WAAK,kBAAkB,SAAS,cAAc,+BAA+B;AAC7E,eAAS,KAAK,YAAY,KAAK,eAAe;AAAA,IAChD;AACA,SAAK,gBAAgB,UAAU,OAAO;AACtC,SAAK,gBAAgB,KAAA;AACrB,WAAO,KAAK;AAAA,EACd;AAAA,EAEO,aAAgD;AACrD,WAAO,KAAK;AAAA,EACd;AACF;AAEO,MAAM,gCAAgC,IAAI,8BAAA;AACjD,YAAY,IAAI,iCAAiC,6BAA6B;"}
|