@libredb/studio 0.9.7 → 0.9.12
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/chunk-34YQUUCM.mjs +319 -0
- package/dist/chunk-34YQUUCM.mjs.map +1 -0
- package/dist/chunk-4LVB3K53.mjs +37 -0
- package/dist/chunk-4LVB3K53.mjs.map +1 -0
- package/dist/chunk-6DRZXXNT.mjs +100 -0
- package/dist/chunk-6DRZXXNT.mjs.map +1 -0
- package/dist/chunk-CZVV3JJB.mjs +160 -0
- package/dist/chunk-CZVV3JJB.mjs.map +1 -0
- package/dist/chunk-D4WVWWWF.js +332 -0
- package/dist/chunk-D4WVWWWF.js.map +1 -0
- package/dist/chunk-DY3KXE44.mjs +3 -0
- package/dist/chunk-DY3KXE44.mjs.map +1 -0
- package/dist/chunk-DZ2UB3C6.mjs +6679 -0
- package/dist/chunk-DZ2UB3C6.mjs.map +1 -0
- package/dist/chunk-FYSE52VB.js +242 -0
- package/dist/chunk-FYSE52VB.js.map +1 -0
- package/dist/chunk-G4WYE6TI.js +4 -0
- package/dist/chunk-G4WYE6TI.js.map +1 -0
- package/dist/chunk-JOGLIOFO.js +1310 -0
- package/dist/chunk-JOGLIOFO.js.map +1 -0
- package/dist/chunk-JZO5KRZN.js +165 -0
- package/dist/chunk-JZO5KRZN.js.map +1 -0
- package/dist/chunk-KV356UXJ.js +253 -0
- package/dist/chunk-KV356UXJ.js.map +1 -0
- package/dist/chunk-PPODO6HX.mjs +237 -0
- package/dist/chunk-PPODO6HX.mjs.map +1 -0
- package/dist/chunk-PTIRB2JO.js +258 -0
- package/dist/chunk-PTIRB2JO.js.map +1 -0
- package/dist/chunk-Q6LRDBK7.js +42 -0
- package/dist/chunk-Q6LRDBK7.js.map +1 -0
- package/dist/chunk-QJP5FZRY.mjs +255 -0
- package/dist/chunk-QJP5FZRY.mjs.map +1 -0
- package/dist/chunk-R3POCJK6.mjs +248 -0
- package/dist/chunk-R3POCJK6.mjs.map +1 -0
- package/dist/chunk-RBVDMLFV.js +6747 -0
- package/dist/chunk-RBVDMLFV.js.map +1 -0
- package/dist/chunk-RCQB4FCE.js +186 -0
- package/dist/chunk-RCQB4FCE.js.map +1 -0
- package/dist/chunk-SR5DRGBX.mjs +174 -0
- package/dist/chunk-SR5DRGBX.mjs.map +1 -0
- package/dist/chunk-VLCRUZX7.js +102 -0
- package/dist/chunk-VLCRUZX7.js.map +1 -0
- package/dist/chunk-VWVRUCQO.mjs +1289 -0
- package/dist/chunk-VWVRUCQO.mjs.map +1 -0
- package/dist/components.d.mts +273 -0
- package/dist/components.d.ts +273 -0
- package/dist/components.js +59 -0
- package/dist/components.js.map +1 -0
- package/dist/components.mjs +6 -0
- package/dist/components.mjs.map +1 -0
- package/dist/custom-BNDOYC5P.js +134 -0
- package/dist/custom-BNDOYC5P.js.map +1 -0
- package/dist/custom-S2EKFMP3.mjs +132 -0
- package/dist/custom-S2EKFMP3.mjs.map +1 -0
- package/dist/gemini-4ASHNK4H.js +81 -0
- package/dist/gemini-4ASHNK4H.js.map +1 -0
- package/dist/gemini-C5RBLQEJ.mjs +79 -0
- package/dist/gemini-C5RBLQEJ.mjs.map +1 -0
- package/dist/index.d.mts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +95 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +10 -0
- package/dist/index.mjs.map +1 -0
- package/dist/mongodb-XMZEZA4A.mjs +748 -0
- package/dist/mongodb-XMZEZA4A.mjs.map +1 -0
- package/dist/mongodb-YQJJTLX3.js +750 -0
- package/dist/mongodb-YQJJTLX3.js.map +1 -0
- package/dist/mssql-PMOU4D36.js +916 -0
- package/dist/mssql-PMOU4D36.js.map +1 -0
- package/{src/lib/db/providers/sql/mssql.ts → dist/mssql-ZH5VP2C5.mjs} +268 -423
- package/dist/mssql-ZH5VP2C5.mjs.map +1 -0
- package/{src/lib/db/providers/sql/mysql.ts → dist/mysql-I3WJQXN2.mjs} +277 -428
- package/dist/mysql-I3WJQXN2.mjs.map +1 -0
- package/dist/mysql-Y3MSA5QY.js +833 -0
- package/dist/mysql-Y3MSA5QY.js.map +1 -0
- package/dist/ollama-26BYLVEV.mjs +115 -0
- package/dist/ollama-26BYLVEV.mjs.map +1 -0
- package/dist/ollama-HVWAGKQC.js +117 -0
- package/dist/ollama-HVWAGKQC.js.map +1 -0
- package/dist/openai-4U56KPG7.mjs +111 -0
- package/dist/openai-4U56KPG7.mjs.map +1 -0
- package/dist/openai-AK3R37BS.js +113 -0
- package/dist/openai-AK3R37BS.js.map +1 -0
- package/dist/oracle-L6VEAVXO.js +917 -0
- package/dist/oracle-L6VEAVXO.js.map +1 -0
- package/{src/lib/db/providers/sql/oracle.ts → dist/oracle-P2G7T4P4.mjs} +321 -454
- package/dist/oracle-P2G7T4P4.mjs.map +1 -0
- package/{src/lib/db/providers/sql/postgres.ts → dist/postgres-O5KOQUVP.mjs} +261 -471
- package/dist/postgres-O5KOQUVP.mjs.map +1 -0
- package/dist/postgres-RLCWNFFX.js +971 -0
- package/dist/postgres-RLCWNFFX.js.map +1 -0
- package/dist/providers.d.mts +149 -0
- package/dist/providers.d.ts +149 -0
- package/dist/providers.js +44 -0
- package/dist/providers.js.map +1 -0
- package/dist/providers.mjs +7 -0
- package/dist/providers.mjs.map +1 -0
- package/dist/redis-4WMQOVLX.mjs +435 -0
- package/dist/redis-4WMQOVLX.mjs.map +1 -0
- package/dist/redis-QVQ6YU62.js +441 -0
- package/dist/redis-QVQ6YU62.js.map +1 -0
- package/dist/sqlite-4I2P2OGQ.js +554 -0
- package/dist/sqlite-4I2P2OGQ.js.map +1 -0
- package/dist/sqlite-OA4YJX5S.mjs +531 -0
- package/dist/sqlite-OA4YJX5S.mjs.map +1 -0
- package/dist/types-BJvJfxSY.d.mts +141 -0
- package/dist/types-BJvJfxSY.d.ts +141 -0
- package/dist/types-ClAg_v5k.d.mts +343 -0
- package/dist/types-Der_X8E8.d.ts +343 -0
- package/dist/types.d.mts +2 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/types.mjs +3 -0
- package/dist/types.mjs.map +1 -0
- package/dist/workspace.d.mts +80 -0
- package/dist/workspace.d.ts +80 -0
- package/dist/workspace.js +4182 -0
- package/dist/workspace.js.map +1 -0
- package/dist/workspace.mjs +4155 -0
- package/dist/workspace.mjs.map +1 -0
- package/package.json +60 -5
- package/.claude/settings.local.json +0 -127
- package/.cursorrules +0 -426
- package/.devin/wiki.json +0 -143
- package/.dockerignore +0 -80
- package/.env.example +0 -159
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -49
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -29
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -57
- package/.github/workflows/ci.yml +0 -185
- package/.github/workflows/codeql.yml +0 -57
- package/.github/workflows/docker-build-push.yml +0 -118
- package/.github/workflows/helm-release.yml +0 -113
- package/CLAUDE.md +0 -265
- package/CODE_OF_CONDUCT.md +0 -124
- package/CONTRIBUTING.md +0 -154
- package/Dockerfile +0 -73
- package/SECURITY.md +0 -107
- package/artifacthub-repo.yml +0 -4
- package/bun.lock +0 -1714
- package/bunfig.toml +0 -3
- package/charts/libredb-studio/.helmignore +0 -11
- package/charts/libredb-studio/Chart.lock +0 -6
- package/charts/libredb-studio/Chart.yaml +0 -50
- package/charts/libredb-studio/README.md +0 -206
- package/charts/libredb-studio/templates/NOTES.txt +0 -59
- package/charts/libredb-studio/templates/_helpers.tpl +0 -135
- package/charts/libredb-studio/templates/configmap.yaml +0 -37
- package/charts/libredb-studio/templates/deployment.yaml +0 -184
- package/charts/libredb-studio/templates/hpa.yaml +0 -32
- package/charts/libredb-studio/templates/ingress.yaml +0 -41
- package/charts/libredb-studio/templates/networkpolicy.yaml +0 -50
- package/charts/libredb-studio/templates/pdb.yaml +0 -18
- package/charts/libredb-studio/templates/pvc.yaml +0 -23
- package/charts/libredb-studio/templates/secret.yaml +0 -30
- package/charts/libredb-studio/templates/seed-configmap.yaml +0 -11
- package/charts/libredb-studio/templates/service.yaml +0 -22
- package/charts/libredb-studio/templates/serviceaccount.yaml +0 -13
- package/charts/libredb-studio/values.schema.json +0 -246
- package/charts/libredb-studio/values.yaml +0 -286
- package/components.json +0 -22
- package/conductor/code_styleguides/typescript.md +0 -43
- package/conductor/product-guidelines.md +0 -43
- package/conductor/product.md +0 -3
- package/conductor/setup_state.json +0 -1
- package/conductor/tech-stack.md +0 -39
- package/conductor/tracks/enhance_postgres_monitoring_20251227/metadata.json +0 -8
- package/conductor/tracks/enhance_postgres_monitoring_20251227/plan.md +0 -44
- package/conductor/tracks/enhance_postgres_monitoring_20251227/spec.md +0 -31
- package/conductor/tracks.md +0 -8
- package/conductor/workflow.md +0 -333
- package/database-compose.yml +0 -55
- package/docker/postgres-init/01-extensions.sql +0 -10
- package/docker/postgres-init/02-sample-data.sql +0 -585
- package/docker/postgres.yml +0 -68
- package/docker-compose.yml +0 -38
- package/docs/AI_PLAN.md +0 -74
- package/docs/API_DOCS.md +0 -875
- package/docs/ARCHITECTURE.md +0 -218
- package/docs/DATABASE_PROVIDERS.md +0 -358
- package/docs/FEATURES.md +0 -116
- package/docs/HELM_CHART.md +0 -252
- package/docs/LOGIN_PAGE.md +0 -178
- package/docs/MONACO_EDITOR_PERFORMANCE.md +0 -315
- package/docs/OIDC_ARCH.md +0 -681
- package/docs/OIDC_SETUP.md +0 -322
- package/docs/POSTGRES_METRICS.md +0 -516
- package/docs/QUERY_OPTIMIZATION.md +0 -370
- package/docs/SEED_CONNECTIONS.md +0 -468
- package/docs/SQL_ALIAS_COMPLETION.md +0 -190
- package/docs/STORAGE_ARCHITECTURE.md +0 -565
- package/docs/STORAGE_QUICK_SETUP.md +0 -419
- package/docs/TECHNICAL_PLAN.md +0 -36
- package/docs/THEMING.md +0 -345
- package/docs/adding-a-new-database-provider.md +0 -642
- package/docs/backlogs/000-PLATFORM_DATA_SYNC_DATABASE.md +0 -360
- package/docs/backlogs/001-INLINE_DATA_EDITING.md +0 -118
- package/docs/backlogs/002-DATA_IMPORT.md +0 -215
- package/docs/backlogs/003-QUERY_TIME_MACHINE.md +0 -183
- package/docs/backlogs/004-AI_DATA_STORYTELLER.md +0 -292
- package/docs/backlogs/005-QUERY_PLAYGROUND.md +0 -352
- package/docs/backlogs/006-DATA_MASKING.md +0 -418
- package/docs/enterprise-features.md +0 -718
- package/docs/kubernetes-helm-chart-artifacthub-plan.md +0 -803
- package/docs/medium-koyeb-article-en.md +0 -215
- package/docs/plans/test-plans.md +0 -445
- package/docs/releases/RELEASE.V0.3.0.md +0 -22
- package/docs/releases/RELEASE.V0.4.0.md +0 -154
- package/docs/releases/RELEASE.V0.5.0.md +0 -252
- package/docs/releases/RELEASE_v0.5.6.md +0 -145
- package/docs/releases/RELEASE_v0.6.1.md +0 -303
- package/docs/releases/RELEASE_v0.6.7.md +0 -292
- package/docs/releases/RELEASE_v0.7.0.md +0 -332
- package/docs/releases/RELEASE_v0.8.0.md +0 -521
- package/docs/sampledb/titanic.sql +0 -1379
- package/docs/superpowers/plans/2026-03-25-seed-connections.md +0 -1362
- package/docs/superpowers/specs/2026-03-25-seed-connections-design.md +0 -590
- package/e2e/admin-dashboard.spec.ts +0 -64
- package/e2e/connection-management.spec.ts +0 -58
- package/e2e/export.spec.ts +0 -34
- package/e2e/login.spec.ts +0 -85
- package/e2e/query-execution.spec.ts +0 -35
- package/e2e/tab-management.spec.ts +0 -64
- package/eslint.config.mjs +0 -28
- package/fly.toml +0 -43
- package/next.config.ts +0 -32
- package/playwright.config.ts +0 -34
- package/postcss.config.mjs +0 -7
- package/public/favicon-32x32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/file.svg +0 -1
- package/public/globe.svg +0 -1
- package/public/logo.svg +0 -32
- package/public/next.svg +0 -1
- package/public/screenshots/code-generator.png +0 -0
- package/public/screenshots/connection-modal.png +0 -0
- package/public/screenshots/data-profiler.png +0 -0
- package/public/screenshots/erd-diagram.png +0 -0
- package/public/screenshots/hero-editor.png +0 -0
- package/public/screenshots/nl2sql.png +0 -0
- package/public/vercel.svg +0 -1
- package/public/window.svg +0 -1
- package/render.yaml +0 -58
- package/scripts/merge-lcov.mjs +0 -239
- package/sonar-project.properties +0 -16
- package/src/app/admin/error.tsx +0 -46
- package/src/app/admin/page.tsx +0 -10
- package/src/app/api/admin/audit/route.ts +0 -52
- package/src/app/api/admin/fleet-health/route.ts +0 -81
- package/src/app/api/ai/autopilot/route.ts +0 -105
- package/src/app/api/ai/chat/route.ts +0 -132
- package/src/app/api/ai/describe-schema/route.ts +0 -52
- package/src/app/api/ai/explain/route.ts +0 -86
- package/src/app/api/ai/impact/route.ts +0 -97
- package/src/app/api/ai/index-advisor/route.ts +0 -98
- package/src/app/api/ai/nl2sql/route.ts +0 -87
- package/src/app/api/ai/query-safety/route.ts +0 -87
- package/src/app/api/auth/login/route.ts +0 -62
- package/src/app/api/auth/logout/route.ts +0 -25
- package/src/app/api/auth/me/route.ts +0 -10
- package/src/app/api/auth/oidc/callback/route.ts +0 -82
- package/src/app/api/auth/oidc/login/route.ts +0 -43
- package/src/app/api/connections/managed/route.ts +0 -35
- package/src/app/api/db/cancel/route.ts +0 -42
- package/src/app/api/db/disconnect/route.ts +0 -28
- package/src/app/api/db/health/route.ts +0 -49
- package/src/app/api/db/maintenance/route.ts +0 -72
- package/src/app/api/db/monitoring/route.ts +0 -62
- package/src/app/api/db/multi-query/route.ts +0 -116
- package/src/app/api/db/pool-stats/route.ts +0 -37
- package/src/app/api/db/profile/route.ts +0 -144
- package/src/app/api/db/provider-meta/route.ts +0 -49
- package/src/app/api/db/query/route.ts +0 -50
- package/src/app/api/db/schema/route.ts +0 -47
- package/src/app/api/db/schema-snapshot/route.ts +0 -42
- package/src/app/api/db/test-connection/route.ts +0 -55
- package/src/app/api/db/transaction/route.ts +0 -111
- package/src/app/api/storage/[collection]/route.ts +0 -67
- package/src/app/api/storage/config/route.ts +0 -17
- package/src/app/api/storage/migrate/route.ts +0 -45
- package/src/app/api/storage/route.ts +0 -32
- package/src/app/error.tsx +0 -49
- package/src/app/global-error.tsx +0 -55
- package/src/app/globals.css +0 -146
- package/src/app/icon.svg +0 -42
- package/src/app/layout.tsx +0 -34
- package/src/app/login/login-form.tsx +0 -301
- package/src/app/login/page.tsx +0 -11
- package/src/app/monitoring/page.tsx +0 -8
- package/src/app/not-found.tsx +0 -29
- package/src/app/page.tsx +0 -5
- package/src/components/AIAutopilotPanel.tsx +0 -238
- package/src/components/CodeGenerator.tsx +0 -271
- package/src/components/CommandPalette.tsx +0 -227
- package/src/components/ConnectionModal.tsx +0 -759
- package/src/components/CreateTableModal.tsx +0 -281
- package/src/components/DataCharts.tsx +0 -962
- package/src/components/DataImportModal.tsx +0 -582
- package/src/components/DataProfiler.tsx +0 -335
- package/src/components/DatabaseDocs.tsx +0 -251
- package/src/components/MaskingSettings.tsx +0 -414
- package/src/components/MobileNav.tsx +0 -50
- package/src/components/NL2SQLPanel.tsx +0 -281
- package/src/components/PivotTable.tsx +0 -257
- package/src/components/QueryEditor.tsx +0 -760
- package/src/components/QueryHistory.tsx +0 -344
- package/src/components/QuerySafetyDialog.tsx +0 -290
- package/src/components/ResultsGrid.tsx +0 -644
- package/src/components/SaveQueryModal.tsx +0 -104
- package/src/components/SavedQueries.tsx +0 -128
- package/src/components/SchemaDiagram.tsx +0 -473
- package/src/components/SchemaDiff.tsx +0 -473
- package/src/components/SnapshotTimeline.tsx +0 -116
- package/src/components/Studio.tsx +0 -639
- package/src/components/TestDataGenerator.tsx +0 -261
- package/src/components/VisualExplain.tsx +0 -820
- package/src/components/admin/AdminDashboard.tsx +0 -163
- package/src/components/admin/tabs/AuditTab.tsx +0 -531
- package/src/components/admin/tabs/MonitoringEmbed.tsx +0 -11
- package/src/components/admin/tabs/OperationsTab.tsx +0 -646
- package/src/components/admin/tabs/OverviewTab.tsx +0 -1328
- package/src/components/admin/tabs/SecurityTab.tsx +0 -284
- package/src/components/community-section.tsx +0 -92
- package/src/components/icons/db-icons.tsx +0 -84
- package/src/components/libredb-logo.tsx +0 -61
- package/src/components/monitoring/MonitoringDashboard.tsx +0 -345
- package/src/components/monitoring/tabs/MetricChart.tsx +0 -82
- package/src/components/monitoring/tabs/OverviewTab.tsx +0 -263
- package/src/components/monitoring/tabs/PerformanceTab.tsx +0 -254
- package/src/components/monitoring/tabs/PoolTab.tsx +0 -174
- package/src/components/monitoring/tabs/QueriesTab.tsx +0 -287
- package/src/components/monitoring/tabs/SessionsTab.tsx +0 -316
- package/src/components/monitoring/tabs/StorageTab.tsx +0 -335
- package/src/components/monitoring/tabs/TablesTab.tsx +0 -300
- package/src/components/results-grid/ResultCard.tsx +0 -111
- package/src/components/results-grid/RowDetailSheet.tsx +0 -178
- package/src/components/results-grid/StatsBar.tsx +0 -201
- package/src/components/results-grid/index.ts +0 -1
- package/src/components/results-grid/utils.ts +0 -23
- package/src/components/schema-explorer/ColumnList.tsx +0 -53
- package/src/components/schema-explorer/SchemaExplorer.tsx +0 -182
- package/src/components/schema-explorer/TableItem.tsx +0 -210
- package/src/components/schema-explorer/index.ts +0 -1
- package/src/components/sidebar/ConnectionItem.tsx +0 -105
- package/src/components/sidebar/ConnectionsList.tsx +0 -62
- package/src/components/sidebar/Sidebar.tsx +0 -130
- package/src/components/sidebar/index.ts +0 -2
- package/src/components/studio/BottomPanel.tsx +0 -286
- package/src/components/studio/QueryToolbar.tsx +0 -180
- package/src/components/studio/StudioDesktopHeader.tsx +0 -114
- package/src/components/studio/StudioMobileHeader.tsx +0 -340
- package/src/components/studio/StudioTabBar.tsx +0 -82
- package/src/components/studio/index.ts +0 -5
- package/src/components/ui/accordion.tsx +0 -66
- package/src/components/ui/alert-dialog.tsx +0 -157
- package/src/components/ui/alert.tsx +0 -66
- package/src/components/ui/aspect-ratio.tsx +0 -11
- package/src/components/ui/avatar.tsx +0 -53
- package/src/components/ui/badge.tsx +0 -46
- package/src/components/ui/breadcrumb.tsx +0 -109
- package/src/components/ui/button-group.tsx +0 -83
- package/src/components/ui/button.tsx +0 -60
- package/src/components/ui/calendar.tsx +0 -216
- package/src/components/ui/card.tsx +0 -92
- package/src/components/ui/carousel.tsx +0 -241
- package/src/components/ui/chart.tsx +0 -357
- package/src/components/ui/checkbox.tsx +0 -32
- package/src/components/ui/collapsible.tsx +0 -33
- package/src/components/ui/command.tsx +0 -184
- package/src/components/ui/context-menu.tsx +0 -252
- package/src/components/ui/dialog.tsx +0 -143
- package/src/components/ui/drawer.tsx +0 -135
- package/src/components/ui/dropdown-menu.tsx +0 -257
- package/src/components/ui/empty.tsx +0 -104
- package/src/components/ui/field.tsx +0 -248
- package/src/components/ui/form.tsx +0 -167
- package/src/components/ui/hover-card.tsx +0 -44
- package/src/components/ui/input-group.tsx +0 -170
- package/src/components/ui/input-otp.tsx +0 -77
- package/src/components/ui/input.tsx +0 -21
- package/src/components/ui/item.tsx +0 -193
- package/src/components/ui/kbd.tsx +0 -28
- package/src/components/ui/label.tsx +0 -24
- package/src/components/ui/menubar.tsx +0 -276
- package/src/components/ui/navigation-menu.tsx +0 -168
- package/src/components/ui/pagination.tsx +0 -127
- package/src/components/ui/popover.tsx +0 -48
- package/src/components/ui/progress.tsx +0 -31
- package/src/components/ui/radio-group.tsx +0 -45
- package/src/components/ui/resizable.tsx +0 -56
- package/src/components/ui/scroll-area.tsx +0 -58
- package/src/components/ui/select.tsx +0 -187
- package/src/components/ui/separator.tsx +0 -28
- package/src/components/ui/sheet.tsx +0 -139
- package/src/components/ui/sidebar.tsx +0 -726
- package/src/components/ui/skeleton.tsx +0 -13
- package/src/components/ui/slider.tsx +0 -63
- package/src/components/ui/sonner.tsx +0 -40
- package/src/components/ui/spinner.tsx +0 -16
- package/src/components/ui/switch.tsx +0 -31
- package/src/components/ui/table.tsx +0 -116
- package/src/components/ui/tabs.tsx +0 -66
- package/src/components/ui/textarea.tsx +0 -18
- package/src/components/ui/toggle-group.tsx +0 -83
- package/src/components/ui/toggle.tsx +0 -47
- package/src/components/ui/tooltip.tsx +0 -61
- package/src/exports/components.ts +0 -15
- package/src/exports/index.ts +0 -4
- package/src/exports/providers.ts +0 -4
- package/src/exports/types.ts +0 -26
- package/src/hooks/use-ai-chat.ts +0 -182
- package/src/hooks/use-all-connections.ts +0 -66
- package/src/hooks/use-api-call.ts +0 -71
- package/src/hooks/use-auth.ts +0 -51
- package/src/hooks/use-connection-form.ts +0 -349
- package/src/hooks/use-connection-manager.ts +0 -169
- package/src/hooks/use-connection-payload.ts +0 -15
- package/src/hooks/use-inline-editing.ts +0 -109
- package/src/hooks/use-mobile.ts +0 -20
- package/src/hooks/use-monitoring-data.ts +0 -270
- package/src/hooks/use-provider-metadata.ts +0 -62
- package/src/hooks/use-query-execution.ts +0 -478
- package/src/hooks/use-storage-sync.ts +0 -259
- package/src/hooks/use-tab-manager.ts +0 -231
- package/src/hooks/use-toast.ts +0 -20
- package/src/hooks/use-transaction-control.ts +0 -64
- package/src/lib/api/error-codes.ts +0 -30
- package/src/lib/api/errors.ts +0 -236
- package/src/lib/api/with-error-handler.ts +0 -41
- package/src/lib/audit.ts +0 -105
- package/src/lib/auth.ts +0 -87
- package/src/lib/connection-string-parser.ts +0 -172
- package/src/lib/data-masking.ts +0 -385
- package/src/lib/db/base-provider.ts +0 -325
- package/src/lib/db/errors.ts +0 -317
- package/src/lib/db/factory.ts +0 -324
- package/src/lib/db/index.ts +0 -123
- package/src/lib/db/providers/document/index.ts +0 -6
- package/src/lib/db/providers/document/mongodb.ts +0 -992
- package/src/lib/db/providers/keyvalue/redis.ts +0 -554
- package/src/lib/db/providers/sql/index.ts +0 -11
- package/src/lib/db/providers/sql/sql-base.ts +0 -174
- package/src/lib/db/providers/sql/sqlite.ts +0 -721
- package/src/lib/db/types.ts +0 -437
- package/src/lib/db/utils/pool-manager.ts +0 -287
- package/src/lib/db/utils/query-limiter.ts +0 -239
- package/src/lib/db-ui-config.ts +0 -86
- package/src/lib/editor/mongodb-completions.ts +0 -172
- package/src/lib/editor/sql-completions.ts +0 -280
- package/src/lib/llm/base-provider.ts +0 -117
- package/src/lib/llm/factory.ts +0 -102
- package/src/lib/llm/index.ts +0 -90
- package/src/lib/llm/providers/custom.ts +0 -181
- package/src/lib/llm/providers/gemini.ts +0 -126
- package/src/lib/llm/providers/ollama.ts +0 -154
- package/src/lib/llm/providers/openai.ts +0 -146
- package/src/lib/llm/types.ts +0 -173
- package/src/lib/llm/utils/config.ts +0 -187
- package/src/lib/llm/utils/retry.ts +0 -119
- package/src/lib/llm/utils/streaming.ts +0 -202
- package/src/lib/logger.ts +0 -127
- package/src/lib/monitoring-thresholds.ts +0 -44
- package/src/lib/oidc.ts +0 -262
- package/src/lib/query-generators.ts +0 -61
- package/src/lib/schema-diff/diff-engine.ts +0 -273
- package/src/lib/schema-diff/migration-generator.ts +0 -208
- package/src/lib/schema-diff/types.ts +0 -55
- package/src/lib/seed/config-loader.ts +0 -79
- package/src/lib/seed/connection-filter.ts +0 -49
- package/src/lib/seed/credential-resolver.ts +0 -62
- package/src/lib/seed/index.ts +0 -40
- package/src/lib/seed/resolve-connection.ts +0 -57
- package/src/lib/seed/types.ts +0 -69
- package/src/lib/sql/alias-extractor.ts +0 -267
- package/src/lib/sql/index.ts +0 -8
- package/src/lib/sql/statement-splitter.ts +0 -167
- package/src/lib/sql/types.ts +0 -40
- package/src/lib/ssh/tunnel.ts +0 -142
- package/src/lib/storage/factory.ts +0 -84
- package/src/lib/storage/index.ts +0 -14
- package/src/lib/storage/local-storage.ts +0 -99
- package/src/lib/storage/providers/postgres.ts +0 -225
- package/src/lib/storage/providers/sqlite.ts +0 -153
- package/src/lib/storage/storage-facade.ts +0 -272
- package/src/lib/storage/types.ts +0 -75
- package/src/lib/time-series-buffer.ts +0 -58
- package/src/lib/types.ts +0 -173
- package/src/lib/utils.ts +0 -6
- package/src/proxy.ts +0 -104
- package/src/types/db-drivers.d.ts +0 -23
- package/src/types/html2canvas.d.ts +0 -9
- package/tests/api/admin/audit.test.ts +0 -178
- package/tests/api/admin/fleet-health.test.ts +0 -183
- package/tests/api/ai/autopilot.test.ts +0 -174
- package/tests/api/ai/chat.test.ts +0 -250
- package/tests/api/ai/describe-schema.test.ts +0 -266
- package/tests/api/ai/explain.test.ts +0 -199
- package/tests/api/ai/impact.test.ts +0 -168
- package/tests/api/ai/index-advisor.test.ts +0 -171
- package/tests/api/ai/nl2sql.test.ts +0 -202
- package/tests/api/ai/query-safety.test.ts +0 -196
- package/tests/api/auth/login.test.ts +0 -170
- package/tests/api/auth/logout.test.ts +0 -140
- package/tests/api/auth/me.test.ts +0 -73
- package/tests/api/auth/oidc-callback.test.ts +0 -215
- package/tests/api/auth/oidc-login.test.ts +0 -127
- package/tests/api/db/cancel.test.ts +0 -198
- package/tests/api/db/disconnect.test.ts +0 -124
- package/tests/api/db/health.test.ts +0 -222
- package/tests/api/db/maintenance.test.ts +0 -263
- package/tests/api/db/monitoring.test.ts +0 -221
- package/tests/api/db/multi-query.test.ts +0 -316
- package/tests/api/db/pool-stats.test.ts +0 -135
- package/tests/api/db/profile.test.ts +0 -330
- package/tests/api/db/provider-meta.test.ts +0 -193
- package/tests/api/db/query.test.ts +0 -314
- package/tests/api/db/schema-snapshot.test.ts +0 -170
- package/tests/api/db/schema.test.ts +0 -191
- package/tests/api/db/test-connection.test.ts +0 -185
- package/tests/api/db/transaction.test.ts +0 -314
- package/tests/api/proxy.test.ts +0 -191
- package/tests/api/seed/managed-route.test.ts +0 -113
- package/tests/api/storage/config.test.ts +0 -42
- package/tests/api/storage/storage-routes.test.ts +0 -309
- package/tests/components/AIAutopilotPanel.test.tsx +0 -756
- package/tests/components/AdminPage.test.tsx +0 -33
- package/tests/components/CodeGenerator.test.tsx +0 -182
- package/tests/components/CommandPalette.test.tsx +0 -428
- package/tests/components/CommunitySection.test.tsx +0 -91
- package/tests/components/ConnectionModal.mobile.test.tsx +0 -284
- package/tests/components/ConnectionModal.test.tsx +0 -570
- package/tests/components/CreateTableModal.test.tsx +0 -383
- package/tests/components/DataCharts.test.tsx +0 -739
- package/tests/components/DataImportModal.test.tsx +0 -751
- package/tests/components/DataProfiler.test.tsx +0 -589
- package/tests/components/DatabaseDocs.test.tsx +0 -353
- package/tests/components/LoginPage.test.tsx +0 -163
- package/tests/components/LoginPageOIDC.test.tsx +0 -92
- package/tests/components/MaskingSettings.test.tsx +0 -498
- package/tests/components/MobileNav.test.tsx +0 -30
- package/tests/components/MonitoringPage.test.tsx +0 -32
- package/tests/components/NL2SQLPanel.test.tsx +0 -621
- package/tests/components/Page.test.tsx +0 -33
- package/tests/components/PivotTable.test.tsx +0 -350
- package/tests/components/QueryEditor.test.tsx +0 -1730
- package/tests/components/QueryHistory.test.tsx +0 -572
- package/tests/components/QuerySafetyDialog.test.tsx +0 -586
- package/tests/components/ResultsGrid.test.tsx +0 -804
- package/tests/components/RootLayout.test.tsx +0 -83
- package/tests/components/SaveQueryModal.test.tsx +0 -25
- package/tests/components/SavedQueries.test.tsx +0 -43
- package/tests/components/SchemaDiagram.test.tsx +0 -1034
- package/tests/components/SchemaDiff.test.tsx +0 -906
- package/tests/components/SnapshotTimeline.test.tsx +0 -174
- package/tests/components/Studio.test.tsx +0 -1030
- package/tests/components/TestDataGenerator.test.tsx +0 -291
- package/tests/components/VisualExplain.test.tsx +0 -704
- package/tests/components/admin/AdminDashboard.test.tsx +0 -205
- package/tests/components/admin/AuditTab.test.tsx +0 -220
- package/tests/components/admin/MonitoringEmbed.test.tsx +0 -58
- package/tests/components/admin/OperationsTab.test.tsx +0 -975
- package/tests/components/admin/OverviewTab.test.tsx +0 -254
- package/tests/components/admin/SecurityTab.test.tsx +0 -467
- package/tests/components/monitoring/MetricChart.test.tsx +0 -111
- package/tests/components/monitoring/MonitoringDashboard.test.tsx +0 -259
- package/tests/components/monitoring/OverviewTab.test.tsx +0 -78
- package/tests/components/monitoring/PerformanceTab.test.tsx +0 -87
- package/tests/components/monitoring/PoolTab.test.tsx +0 -42
- package/tests/components/monitoring/QueriesTab.test.tsx +0 -80
- package/tests/components/monitoring/SessionsTab.test.tsx +0 -154
- package/tests/components/monitoring/StorageTab.test.tsx +0 -127
- package/tests/components/monitoring/TablesTab.test.tsx +0 -153
- package/tests/components/results-grid/ResultCard.test.tsx +0 -105
- package/tests/components/results-grid/RowDetailSheet.test.tsx +0 -308
- package/tests/components/results-grid/StatsBar.test.tsx +0 -162
- package/tests/components/schema-explorer/ColumnList.test.tsx +0 -151
- package/tests/components/schema-explorer/SchemaExplorer.test.tsx +0 -461
- package/tests/components/schema-explorer/TableItem.test.tsx +0 -415
- package/tests/components/sidebar/ConnectionItem.test.tsx +0 -201
- package/tests/components/sidebar/ConnectionsList.test.tsx +0 -176
- package/tests/components/sidebar/Sidebar.test.tsx +0 -187
- package/tests/components/studio/BottomPanel.test.tsx +0 -383
- package/tests/components/studio/QueryToolbar.test.tsx +0 -321
- package/tests/components/studio/StudioDesktopHeader.test.tsx +0 -377
- package/tests/components/studio/StudioMobileHeader.test.tsx +0 -198
- package/tests/components/studio/StudioTabBar.test.tsx +0 -331
- package/tests/fixtures/connections.ts +0 -96
- package/tests/fixtures/masking-configs.ts +0 -86
- package/tests/fixtures/query-results.ts +0 -71
- package/tests/fixtures/schemas.ts +0 -64
- package/tests/fixtures/seed-connections/invalid-config.yaml +0 -7
- package/tests/fixtures/seed-connections/minimal-config.yaml +0 -8
- package/tests/fixtures/seed-connections/mixed-credentials.yaml +0 -23
- package/tests/fixtures/seed-connections/multi-role-config.yaml +0 -30
- package/tests/fixtures/seed-connections/valid-config.json +0 -15
- package/tests/fixtures/seed-connections/valid-config.yaml +0 -51
- package/tests/helpers/mock-fetch.ts +0 -59
- package/tests/helpers/mock-monaco.ts +0 -112
- package/tests/helpers/mock-navigation.ts +0 -28
- package/tests/helpers/mock-next.ts +0 -80
- package/tests/helpers/mock-provider.ts +0 -133
- package/tests/helpers/mock-sonner.ts +0 -29
- package/tests/helpers/render-with-providers.tsx +0 -19
- package/tests/hooks/use-ai-chat.test.ts +0 -600
- package/tests/hooks/use-auth.test.ts +0 -371
- package/tests/hooks/use-connection-form.test.ts +0 -743
- package/tests/hooks/use-connection-manager.test.ts +0 -466
- package/tests/hooks/use-inline-editing.test.ts +0 -321
- package/tests/hooks/use-mobile.test.ts +0 -177
- package/tests/hooks/use-monitoring-data.test.ts +0 -819
- package/tests/hooks/use-provider-metadata.test.ts +0 -228
- package/tests/hooks/use-query-execution.test.ts +0 -1212
- package/tests/hooks/use-tab-manager.test.ts +0 -756
- package/tests/hooks/use-toast.test.ts +0 -74
- package/tests/hooks/use-transaction-control.test.ts +0 -211
- package/tests/integration/db/mongodb-provider.test.ts +0 -698
- package/tests/integration/db/mssql-provider.test.ts +0 -840
- package/tests/integration/db/mysql-provider.test.ts +0 -872
- package/tests/integration/db/oracle-provider.test.ts +0 -843
- package/tests/integration/db/postgres-provider.test.ts +0 -1382
- package/tests/integration/db/redis-provider.test.ts +0 -526
- package/tests/integration/db/sqlite-provider.test.ts +0 -480
- package/tests/integration/seed/seed-pipeline.test.ts +0 -102
- package/tests/isolated/factory-singleton.test.ts +0 -150
- package/tests/isolated/use-storage-sync.test.ts +0 -389
- package/tests/run-components.sh +0 -196
- package/tests/setup-dom.ts +0 -58
- package/tests/setup.ts +0 -40
- package/tests/unit/api-errors.test.ts +0 -210
- package/tests/unit/code-generator-functions.test.ts +0 -271
- package/tests/unit/components/column-list.test.tsx +0 -190
- package/tests/unit/components/data-import-modal.test.tsx +0 -441
- package/tests/unit/components/studio-mobile-header.test.tsx +0 -327
- package/tests/unit/data-charts-functions.test.ts +0 -496
- package/tests/unit/data-import-functions.test.ts +0 -320
- package/tests/unit/data-import-utils.test.ts +0 -125
- package/tests/unit/db/base-provider.test.ts +0 -517
- package/tests/unit/db/errors.test.ts +0 -403
- package/tests/unit/db/factory.test.ts +0 -436
- package/tests/unit/db/pool-manager.test.ts +0 -440
- package/tests/unit/db/query-limiter.test.ts +0 -387
- package/tests/unit/db/sql-base.test.ts +0 -438
- package/tests/unit/lib/api/error-codes.test.ts +0 -39
- package/tests/unit/lib/audit.test.ts +0 -326
- package/tests/unit/lib/auth.test.ts +0 -146
- package/tests/unit/lib/connection-string-parser.test.ts +0 -424
- package/tests/unit/lib/data-masking.test.ts +0 -583
- package/tests/unit/lib/db-icons.test.tsx +0 -41
- package/tests/unit/lib/monitoring-thresholds.test.ts +0 -133
- package/tests/unit/lib/oidc.test.ts +0 -509
- package/tests/unit/lib/query-generators.test.ts +0 -127
- package/tests/unit/lib/storage/factory.test.ts +0 -71
- package/tests/unit/lib/storage/local-storage.test.ts +0 -114
- package/tests/unit/lib/storage/providers/postgres.test.ts +0 -312
- package/tests/unit/lib/storage/providers/sqlite.test.ts +0 -232
- package/tests/unit/lib/storage/storage-facade-extended.test.ts +0 -331
- package/tests/unit/lib/storage/storage-facade.test.ts +0 -184
- package/tests/unit/lib/storage.test.ts +0 -317
- package/tests/unit/lib/time-series-buffer.test.ts +0 -212
- package/tests/unit/lib/utils.test.ts +0 -24
- package/tests/unit/llm/base-provider.test.ts +0 -238
- package/tests/unit/llm/config.test.ts +0 -262
- package/tests/unit/llm/custom-provider.test.ts +0 -281
- package/tests/unit/llm/gemini-provider.test.ts +0 -248
- package/tests/unit/llm/llm-factory.test.ts +0 -155
- package/tests/unit/llm/ollama-provider.test.ts +0 -288
- package/tests/unit/llm/openai-provider.test.ts +0 -324
- package/tests/unit/llm/retry.test.ts +0 -180
- package/tests/unit/llm/streaming.test.ts +0 -355
- package/tests/unit/logger.test.ts +0 -198
- package/tests/unit/mongodb-completions.test.ts +0 -516
- package/tests/unit/pivot-table-functions.test.ts +0 -76
- package/tests/unit/query-cancelled-error.test.ts +0 -81
- package/tests/unit/schema-diff/diff-engine.test.ts +0 -367
- package/tests/unit/schema-diff/migration-generator.test.ts +0 -513
- package/tests/unit/seed/config-loader.test.ts +0 -73
- package/tests/unit/seed/connection-filter.test.ts +0 -91
- package/tests/unit/seed/credential-resolver.test.ts +0 -85
- package/tests/unit/seed/index.test.ts +0 -72
- package/tests/unit/seed/resolve-connection.test.ts +0 -74
- package/tests/unit/seed/types.test.ts +0 -129
- package/tests/unit/sql/alias-extractor.test.ts +0 -444
- package/tests/unit/sql/statement-splitter.test.ts +0 -348
- package/tests/unit/sql-completions.test.ts +0 -463
- package/tests/unit/ssh-tunnel.test.ts +0 -465
- package/tsconfig.json +0 -42
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkPTIRB2JO_js = require('./chunk-PTIRB2JO.js');
|
|
4
|
+
|
|
5
|
+
// src/lib/db/utils/query-limiter.ts
|
|
6
|
+
var DEFAULT_QUERY_LIMIT = 500;
|
|
7
|
+
var MAX_UNLIMITED_ROWS = 1e5;
|
|
8
|
+
function stripTrailingSemicolon(s) {
|
|
9
|
+
let end = s.length;
|
|
10
|
+
while (end > 0 && (s[end - 1] === " " || s[end - 1] === " " || s[end - 1] === "\n" || s[end - 1] === "\r")) end--;
|
|
11
|
+
while (end > 0 && s[end - 1] === ";") end--;
|
|
12
|
+
while (end > 0 && (s[end - 1] === " " || s[end - 1] === " " || s[end - 1] === "\n" || s[end - 1] === "\r")) end--;
|
|
13
|
+
return s.slice(0, end);
|
|
14
|
+
}
|
|
15
|
+
function analyzeQuery(sql) {
|
|
16
|
+
const trimmed = stripTrailingSemicolon(sql.trim());
|
|
17
|
+
const normalized = trimmed.replace(/\s+/g, " ").toUpperCase();
|
|
18
|
+
let type = "OTHER";
|
|
19
|
+
if (/^\s*SELECT\b/i.test(trimmed)) type = "SELECT";
|
|
20
|
+
else if (/^\s*INSERT\b/i.test(trimmed)) type = "INSERT";
|
|
21
|
+
else if (/^\s*UPDATE\b/i.test(trimmed)) type = "UPDATE";
|
|
22
|
+
else if (/^\s*DELETE\b/i.test(trimmed)) type = "DELETE";
|
|
23
|
+
else if (/^\s*(CREATE|ALTER|DROP|TRUNCATE)\b/i.test(trimmed)) type = "DDL";
|
|
24
|
+
else if (/^\s*WITH\b/i.test(trimmed) && /\bSELECT\b/i.test(trimmed)) {
|
|
25
|
+
type = "SELECT";
|
|
26
|
+
}
|
|
27
|
+
const limitMatch = trimmed.match(
|
|
28
|
+
/\bLIMIT\s+(\d+)(?:\s*,\s*(\d+)|\s+OFFSET\s+(\d+))?\s*$/i
|
|
29
|
+
);
|
|
30
|
+
let hasLimit = false;
|
|
31
|
+
let existingLimit;
|
|
32
|
+
let existingOffset;
|
|
33
|
+
if (limitMatch) {
|
|
34
|
+
hasLimit = true;
|
|
35
|
+
if (limitMatch[2] !== void 0) {
|
|
36
|
+
existingOffset = parseInt(limitMatch[1]);
|
|
37
|
+
existingLimit = parseInt(limitMatch[2]);
|
|
38
|
+
} else {
|
|
39
|
+
existingLimit = parseInt(limitMatch[1]);
|
|
40
|
+
existingOffset = limitMatch[3] ? parseInt(limitMatch[3]) : void 0;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (!hasLimit) {
|
|
44
|
+
const fetchMatch = trimmed.match(/\bFETCH\s+(?:FIRST|NEXT)\s+(\d+)\s+ROWS?\s+ONLY\s*$/i);
|
|
45
|
+
if (fetchMatch) {
|
|
46
|
+
hasLimit = true;
|
|
47
|
+
existingLimit = parseInt(fetchMatch[1]);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (!hasLimit) {
|
|
51
|
+
const topMatch = trimmed.match(/^\s*SELECT\s+TOP\s+(\d+)\b/i);
|
|
52
|
+
if (topMatch) {
|
|
53
|
+
hasLimit = true;
|
|
54
|
+
existingLimit = parseInt(topMatch[1]);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (!hasLimit && /\bROWNUM\s*<=?\s*\d+/i.test(normalized)) {
|
|
58
|
+
hasLimit = true;
|
|
59
|
+
}
|
|
60
|
+
const offsetOnlyMatch = !hasLimit && trimmed.match(/\bOFFSET\s+(\d+)\s*$/i);
|
|
61
|
+
const hasOffset = hasLimit ? existingOffset !== void 0 : !!offsetOnlyMatch;
|
|
62
|
+
if (offsetOnlyMatch && !hasLimit) {
|
|
63
|
+
existingOffset = parseInt(offsetOnlyMatch[1]);
|
|
64
|
+
}
|
|
65
|
+
const isUnion = /\bUNION\b/i.test(normalized);
|
|
66
|
+
const hasCTE = /^\s*WITH\b/i.test(trimmed);
|
|
67
|
+
const selectCount = (normalized.match(/\bSELECT\b/g) || []).length;
|
|
68
|
+
const hasSubquery = selectCount > 1;
|
|
69
|
+
return {
|
|
70
|
+
type,
|
|
71
|
+
hasLimit,
|
|
72
|
+
existingLimit,
|
|
73
|
+
hasOffset,
|
|
74
|
+
existingOffset,
|
|
75
|
+
isUnion,
|
|
76
|
+
hasCTE,
|
|
77
|
+
hasSubquery
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function applyQueryLimit(sql, limit, offset = 0, options = {}) {
|
|
81
|
+
const { forceLimit = false } = options;
|
|
82
|
+
const info = analyzeQuery(sql);
|
|
83
|
+
if (info.type !== "SELECT") {
|
|
84
|
+
return {
|
|
85
|
+
sql,
|
|
86
|
+
wasLimited: false,
|
|
87
|
+
appliedLimit: 0,
|
|
88
|
+
appliedOffset: 0
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
if (info.hasLimit && !forceLimit) {
|
|
92
|
+
return {
|
|
93
|
+
sql,
|
|
94
|
+
wasLimited: false,
|
|
95
|
+
originalLimit: info.existingLimit,
|
|
96
|
+
appliedLimit: info.existingLimit || 0,
|
|
97
|
+
appliedOffset: info.existingOffset || 0
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
const trimmedInput = sql.trim();
|
|
101
|
+
let modifiedSql = stripTrailingSemicolon(trimmedInput);
|
|
102
|
+
const hasSemicolon = modifiedSql.length < trimmedInput.length && trimmedInput.includes(";");
|
|
103
|
+
if (info.hasLimit && forceLimit) {
|
|
104
|
+
modifiedSql = modifiedSql.replace(/\bLIMIT\s+\d+\s*,\s*\d+\s*$/i, "").trim();
|
|
105
|
+
modifiedSql = modifiedSql.replace(/\bLIMIT\s+\d+(?:\s+OFFSET\s+\d+)?\s*$/i, "").trim();
|
|
106
|
+
}
|
|
107
|
+
const limitClause = offset > 0 ? `LIMIT ${limit} OFFSET ${offset}` : `LIMIT ${limit}`;
|
|
108
|
+
modifiedSql = `${modifiedSql} ${limitClause}`;
|
|
109
|
+
if (hasSemicolon) {
|
|
110
|
+
modifiedSql += ";";
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
sql: modifiedSql,
|
|
114
|
+
wasLimited: true,
|
|
115
|
+
originalLimit: info.existingLimit,
|
|
116
|
+
appliedLimit: limit,
|
|
117
|
+
appliedOffset: offset
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// src/lib/db/providers/sql/sql-base.ts
|
|
122
|
+
var SQLBaseProvider = class extends chunkPTIRB2JO_js.BaseDatabaseProvider {
|
|
123
|
+
constructor(config, options = {}) {
|
|
124
|
+
super(config, options);
|
|
125
|
+
}
|
|
126
|
+
// ============================================================================
|
|
127
|
+
// SQL-Specific Utilities
|
|
128
|
+
// ============================================================================
|
|
129
|
+
/**
|
|
130
|
+
* Escape identifier based on SQL dialect
|
|
131
|
+
* PostgreSQL/SQLite: "identifier"
|
|
132
|
+
* MySQL: `identifier`
|
|
133
|
+
*/
|
|
134
|
+
escapeIdentifier(identifier) {
|
|
135
|
+
if (this.type === "mssql") {
|
|
136
|
+
const escaped2 = identifier.replace(/\]/g, "]]");
|
|
137
|
+
return `[${escaped2}]`;
|
|
138
|
+
}
|
|
139
|
+
const quoteChar = this.type === "mysql" ? "`" : '"';
|
|
140
|
+
const escaped = identifier.replace(
|
|
141
|
+
new RegExp(quoteChar, "g"),
|
|
142
|
+
quoteChar + quoteChar
|
|
143
|
+
);
|
|
144
|
+
return `${quoteChar}${escaped}${quoteChar}`;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Escape string value for SQL
|
|
148
|
+
*/
|
|
149
|
+
escapeString(value) {
|
|
150
|
+
return value.replace(/'/g, "''");
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Build LIMIT clause based on dialect
|
|
154
|
+
*/
|
|
155
|
+
buildLimitClause(limit, offset) {
|
|
156
|
+
if (offset !== void 0 && offset > 0) {
|
|
157
|
+
return `LIMIT ${limit} OFFSET ${offset}`;
|
|
158
|
+
}
|
|
159
|
+
return `LIMIT ${limit}`;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Get placeholder style for parameterized queries
|
|
163
|
+
* PostgreSQL: $1, $2, $3
|
|
164
|
+
* MySQL/SQLite: ?, ?, ?
|
|
165
|
+
*/
|
|
166
|
+
getPlaceholder(index) {
|
|
167
|
+
if (this.type === "postgres") return `$${index}`;
|
|
168
|
+
if (this.type === "oracle") return `:${index}`;
|
|
169
|
+
if (this.type === "mssql") return `@p${index}`;
|
|
170
|
+
return "?";
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Determine if SSL should be enabled based on host
|
|
174
|
+
*/
|
|
175
|
+
shouldEnableSSL() {
|
|
176
|
+
var _a;
|
|
177
|
+
const host = ((_a = this.config.host) == null ? void 0 : _a.toLowerCase()) || "";
|
|
178
|
+
const cloudProviders = [
|
|
179
|
+
"supabase",
|
|
180
|
+
"render",
|
|
181
|
+
"neon",
|
|
182
|
+
"planetscale",
|
|
183
|
+
"aws",
|
|
184
|
+
"azure",
|
|
185
|
+
"gcp",
|
|
186
|
+
"cloud"
|
|
187
|
+
];
|
|
188
|
+
return this.options.ssl === true || cloudProviders.some((provider) => host.includes(provider));
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Get information schema name based on dialect
|
|
192
|
+
*/
|
|
193
|
+
getInformationSchemaName() {
|
|
194
|
+
return "information_schema";
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Get default schema/database name for queries
|
|
198
|
+
*/
|
|
199
|
+
getDefaultSchema() {
|
|
200
|
+
var _a;
|
|
201
|
+
switch (this.type) {
|
|
202
|
+
case "postgres":
|
|
203
|
+
return "public";
|
|
204
|
+
case "mysql":
|
|
205
|
+
return this.config.database || "";
|
|
206
|
+
case "oracle":
|
|
207
|
+
return ((_a = this.config.user) == null ? void 0 : _a.toUpperCase()) || "";
|
|
208
|
+
case "mssql":
|
|
209
|
+
return "dbo";
|
|
210
|
+
default:
|
|
211
|
+
return "";
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Check if query is read-only (SELECT, SHOW, DESCRIBE, EXPLAIN)
|
|
216
|
+
*/
|
|
217
|
+
isReadOnlyQuery(sql) {
|
|
218
|
+
const trimmed = sql.trim().toLowerCase();
|
|
219
|
+
return trimmed.startsWith("select") || trimmed.startsWith("show") || trimmed.startsWith("describe") || trimmed.startsWith("explain") || trimmed.startsWith("pragma");
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Check if query modifies schema (CREATE, DROP, ALTER, TRUNCATE)
|
|
223
|
+
*/
|
|
224
|
+
isSchemaModifyingQuery(sql) {
|
|
225
|
+
const trimmed = sql.trim().toLowerCase();
|
|
226
|
+
return trimmed.startsWith("create") || trimmed.startsWith("drop") || trimmed.startsWith("alter") || trimmed.startsWith("truncate");
|
|
227
|
+
}
|
|
228
|
+
// ============================================================================
|
|
229
|
+
// Query Preparation (applies LIMIT for SELECT queries)
|
|
230
|
+
// ============================================================================
|
|
231
|
+
prepareQuery(query, options = {}) {
|
|
232
|
+
const { limit = DEFAULT_QUERY_LIMIT, offset = 0, unlimited = false } = options;
|
|
233
|
+
const effectiveLimit = unlimited ? MAX_UNLIMITED_ROWS : limit;
|
|
234
|
+
const queryInfo = analyzeQuery(query);
|
|
235
|
+
if (queryInfo.type === "SELECT") {
|
|
236
|
+
const limitResult = applyQueryLimit(query, effectiveLimit, offset);
|
|
237
|
+
return {
|
|
238
|
+
query: limitResult.sql,
|
|
239
|
+
wasLimited: limitResult.wasLimited,
|
|
240
|
+
limit: effectiveLimit,
|
|
241
|
+
offset
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
return { query, wasLimited: false, limit: effectiveLimit, offset };
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
exports.DEFAULT_QUERY_LIMIT = DEFAULT_QUERY_LIMIT;
|
|
249
|
+
exports.MAX_UNLIMITED_ROWS = MAX_UNLIMITED_ROWS;
|
|
250
|
+
exports.SQLBaseProvider = SQLBaseProvider;
|
|
251
|
+
exports.analyzeQuery = analyzeQuery;
|
|
252
|
+
//# sourceMappingURL=chunk-KV356UXJ.js.map
|
|
253
|
+
//# sourceMappingURL=chunk-KV356UXJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/db/utils/query-limiter.ts","../src/lib/db/providers/sql/sql-base.ts"],"names":["BaseDatabaseProvider","escaped"],"mappings":";;;;;AAUO,IAAM,mBAAA,GAAsB;AAC5B,IAAM,kBAAA,GAAqB;AAuClC,SAAS,uBAAuB,CAAA,EAAmB;AACjD,EAAA,IAAI,MAAM,CAAA,CAAE,MAAA;AACZ,EAAA,OAAO,GAAA,GAAM,MAAM,CAAA,CAAE,GAAA,GAAM,CAAC,CAAA,KAAM,GAAA,IAAO,EAAE,GAAA,GAAM,CAAC,MAAM,GAAA,IAAQ,CAAA,CAAE,MAAM,CAAC,CAAA,KAAM,QAAQ,CAAA,CAAE,GAAA,GAAM,CAAC,CAAA,KAAM,IAAA,CAAA,EAAO,GAAA,EAAA;AAC7G,EAAA,OAAO,MAAM,CAAA,IAAK,CAAA,CAAE,GAAA,GAAM,CAAC,MAAM,GAAA,EAAK,GAAA,EAAA;AACtC,EAAA,OAAO,GAAA,GAAM,MAAM,CAAA,CAAE,GAAA,GAAM,CAAC,CAAA,KAAM,GAAA,IAAO,EAAE,GAAA,GAAM,CAAC,MAAM,GAAA,IAAQ,CAAA,CAAE,MAAM,CAAC,CAAA,KAAM,QAAQ,CAAA,CAAE,GAAA,GAAM,CAAC,CAAA,KAAM,IAAA,CAAA,EAAO,GAAA,EAAA;AAC7G,EAAA,OAAO,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,GAAG,CAAA;AACvB;AAEO,SAAS,aAAa,GAAA,EAA8B;AAEzD,EAAA,MAAM,OAAA,GAAU,sBAAA,CAAuB,GAAA,CAAI,IAAA,EAAM,CAAA;AACjD,EAAA,MAAM,aAAa,OAAA,CAAQ,OAAA,CAAQ,MAAA,EAAQ,GAAG,EAAE,WAAA,EAAY;AAG5D,EAAA,IAAI,IAAA,GAAgC,OAAA;AACpC,EAAA,IAAI,eAAA,CAAgB,IAAA,CAAK,OAAO,CAAA,EAAG,IAAA,GAAO,QAAA;AAAA,OAAA,IACjC,eAAA,CAAgB,IAAA,CAAK,OAAO,CAAA,EAAG,IAAA,GAAO,QAAA;AAAA,OAAA,IACtC,eAAA,CAAgB,IAAA,CAAK,OAAO,CAAA,EAAG,IAAA,GAAO,QAAA;AAAA,OAAA,IACtC,eAAA,CAAgB,IAAA,CAAK,OAAO,CAAA,EAAG,IAAA,GAAO,QAAA;AAAA,OAAA,IACtC,qCAAA,CAAsC,IAAA,CAAK,OAAO,CAAA,EAAG,IAAA,GAAO,KAAA;AAAA,OAAA,IAE5D,cAAc,IAAA,CAAK,OAAO,KAAK,aAAA,CAAc,IAAA,CAAK,OAAO,CAAA,EAAG;AACnE,IAAA,IAAA,GAAO,QAAA;AAAA,EACT;AAIA,EAAA,MAAM,aAAa,OAAA,CAAQ,KAAA;AAAA,IACzB;AAAA,GACF;AAEA,EAAA,IAAI,QAAA,GAAW,KAAA;AACf,EAAA,IAAI,aAAA;AACJ,EAAA,IAAI,cAAA;AAEJ,EAAA,IAAI,UAAA,EAAY;AACd,IAAA,QAAA,GAAW,IAAA;AAEX,IAAA,IAAI,UAAA,CAAW,CAAC,CAAA,KAAM,MAAA,EAAW;AAE/B,MAAA,cAAA,GAAiB,QAAA,CAAS,UAAA,CAAW,CAAC,CAAC,CAAA;AACvC,MAAA,aAAA,GAAgB,QAAA,CAAS,UAAA,CAAW,CAAC,CAAC,CAAA;AAAA,IACxC,CAAA,MAAO;AACL,MAAA,aAAA,GAAgB,QAAA,CAAS,UAAA,CAAW,CAAC,CAAC,CAAA;AACtC,MAAA,cAAA,GAAiB,WAAW,CAAC,CAAA,GAAI,SAAS,UAAA,CAAW,CAAC,CAAC,CAAA,GAAI,MAAA;AAAA,IAC7D;AAAA,EACF;AAGA,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,KAAA,CAAM,sDAAsD,CAAA;AACvF,IAAA,IAAI,UAAA,EAAY;AACd,MAAA,QAAA,GAAW,IAAA;AACX,MAAA,aAAA,GAAgB,QAAA,CAAS,UAAA,CAAW,CAAC,CAAC,CAAA;AAAA,IACxC;AAAA,EACF;AAGA,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,KAAA,CAAM,6BAA6B,CAAA;AAC5D,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,QAAA,GAAW,IAAA;AACX,MAAA,aAAA,GAAgB,QAAA,CAAS,QAAA,CAAS,CAAC,CAAC,CAAA;AAAA,IACtC;AAAA,EACF;AAGA,EAAA,IAAI,CAAC,QAAA,IAAY,uBAAA,CAAwB,IAAA,CAAK,UAAU,CAAA,EAAG;AACzD,IAAA,QAAA,GAAW,IAAA;AAAA,EACb;AAGA,EAAA,MAAM,eAAA,GAAkB,CAAC,QAAA,IAAY,OAAA,CAAQ,MAAM,uBAAuB,CAAA;AAC1E,EAAA,MAAM,SAAA,GAAY,QAAA,GAAW,cAAA,KAAmB,MAAA,GAAY,CAAC,CAAC,eAAA;AAE9D,EAAA,IAAI,eAAA,IAAmB,CAAC,QAAA,EAAU;AAChC,IAAA,cAAA,GAAiB,QAAA,CAAS,eAAA,CAAgB,CAAC,CAAC,CAAA;AAAA,EAC9C;AAGA,EAAA,MAAM,OAAA,GAAU,YAAA,CAAa,IAAA,CAAK,UAAU,CAAA;AAG5C,EAAA,MAAM,MAAA,GAAS,aAAA,CAAc,IAAA,CAAK,OAAO,CAAA;AAGzC,EAAA,MAAM,eAAe,UAAA,CAAW,KAAA,CAAM,aAAa,CAAA,IAAK,EAAC,EAAG,MAAA;AAC5D,EAAA,MAAM,cAAc,WAAA,GAAc,CAAA;AAElC,EAAA,OAAO;AAAA,IACL,IAAA;AAAA,IACA,QAAA;AAAA,IACA,aAAA;AAAA,IACA,SAAA;AAAA,IACA,cAAA;AAAA,IACA,OAAA;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GACF;AACF;AASO,SAAS,gBACd,GAAA,EACA,KAAA,EACA,SAAiB,CAAA,EACjB,OAAA,GAAsC,EAAC,EACnB;AACpB,EAAA,MAAM,EAAE,UAAA,GAAa,KAAA,EAAM,GAAI,OAAA;AAC/B,EAAA,MAAM,IAAA,GAAO,aAAa,GAAG,CAAA;AAG7B,EAAA,IAAI,IAAA,CAAK,SAAS,QAAA,EAAU;AAC1B,IAAA,OAAO;AAAA,MACL,GAAA;AAAA,MACA,UAAA,EAAY,KAAA;AAAA,MACZ,YAAA,EAAc,CAAA;AAAA,MACd,aAAA,EAAe;AAAA,KACjB;AAAA,EACF;AAGA,EAAA,IAAI,IAAA,CAAK,QAAA,IAAY,CAAC,UAAA,EAAY;AAChC,IAAA,OAAO;AAAA,MACL,GAAA;AAAA,MACA,UAAA,EAAY,KAAA;AAAA,MACZ,eAAe,IAAA,CAAK,aAAA;AAAA,MACpB,YAAA,EAAc,KAAK,aAAA,IAAiB,CAAA;AAAA,MACpC,aAAA,EAAe,KAAK,cAAA,IAAkB;AAAA,KACxC;AAAA,EACF;AAGA,EAAA,MAAM,YAAA,GAAe,IAAI,IAAA,EAAK;AAC9B,EAAA,IAAI,WAAA,GAAc,uBAAuB,YAAY,CAAA;AACrD,EAAA,MAAM,eAAe,WAAA,CAAY,MAAA,GAAS,aAAa,MAAA,IAAU,YAAA,CAAa,SAAS,GAAG,CAAA;AAG1F,EAAA,IAAI,IAAA,CAAK,YAAY,UAAA,EAAY;AAE/B,IAAA,WAAA,GAAc,WAAA,CACX,OAAA,CAAQ,8BAAA,EAAgC,EAAE,EAC1C,IAAA,EAAK;AAER,IAAA,WAAA,GAAc,WAAA,CACX,OAAA,CAAQ,wCAAA,EAA0C,EAAE,EACpD,IAAA,EAAK;AAAA,EACV;AAGA,EAAA,MAAM,WAAA,GACJ,SAAS,CAAA,GAAI,CAAA,MAAA,EAAS,KAAK,CAAA,QAAA,EAAW,MAAM,CAAA,CAAA,GAAK,CAAA,MAAA,EAAS,KAAK,CAAA,CAAA;AAEjE,EAAA,WAAA,GAAc,CAAA,EAAG,WAAW,CAAA,CAAA,EAAI,WAAW,CAAA,CAAA;AAE3C,EAAA,IAAI,YAAA,EAAc;AAChB,IAAA,WAAA,IAAe,GAAA;AAAA,EACjB;AAEA,EAAA,OAAO;AAAA,IACL,GAAA,EAAK,WAAA;AAAA,IACL,UAAA,EAAY,IAAA;AAAA,IACZ,eAAe,IAAA,CAAK,aAAA;AAAA,IACpB,YAAA,EAAc,KAAA;AAAA,IACd,aAAA,EAAe;AAAA,GACjB;AACF;;;ACvMO,IAAe,eAAA,GAAf,cAAuCA,qCAAA,CAAqB;AAAA,EACjE,WAAA,CAAY,MAAA,EAA4B,OAAA,GAA2B,EAAC,EAAG;AACrE,IAAA,KAAA,CAAM,QAAQ,OAAO,CAAA;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWU,iBAAiB,UAAA,EAA4B;AACrD,IAAA,IAAI,IAAA,CAAK,SAAS,OAAA,EAAS;AACzB,MAAA,MAAMC,QAAAA,GAAU,UAAA,CAAW,OAAA,CAAQ,KAAA,EAAO,IAAI,CAAA;AAC9C,MAAA,OAAO,IAAIA,QAAO,CAAA,CAAA,CAAA;AAAA,IACpB;AACA,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,IAAA,KAAS,OAAA,GAAU,GAAA,GAAM,GAAA;AAChD,IAAA,MAAM,UAAU,UAAA,CAAW,OAAA;AAAA,MACzB,IAAI,MAAA,CAAO,SAAA,EAAW,GAAG,CAAA;AAAA,MACzB,SAAA,GAAY;AAAA,KACd;AACA,IAAA,OAAO,CAAA,EAAG,SAAS,CAAA,EAAG,OAAO,GAAG,SAAS,CAAA,CAAA;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKU,aAAa,KAAA,EAAuB;AAC5C,IAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,IAAA,EAAM,IAAI,CAAA;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKU,gBAAA,CAAiB,OAAe,MAAA,EAAyB;AACjE,IAAA,IAAI,MAAA,KAAW,MAAA,IAAa,MAAA,GAAS,CAAA,EAAG;AACtC,MAAA,OAAO,CAAA,MAAA,EAAS,KAAK,CAAA,QAAA,EAAW,MAAM,CAAA,CAAA;AAAA,IACxC;AACA,IAAA,OAAO,SAAS,KAAK,CAAA,CAAA;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,eAAe,KAAA,EAAuB;AAC9C,IAAA,IAAI,IAAA,CAAK,IAAA,KAAS,UAAA,EAAY,OAAO,IAAI,KAAK,CAAA,CAAA;AAC9C,IAAA,IAAI,IAAA,CAAK,IAAA,KAAS,QAAA,EAAU,OAAO,IAAI,KAAK,CAAA,CAAA;AAC5C,IAAA,IAAI,IAAA,CAAK,IAAA,KAAS,OAAA,EAAS,OAAO,KAAK,KAAK,CAAA,CAAA;AAC5C,IAAA,OAAO,GAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKU,eAAA,GAA2B;AAlFvC,IAAA,IAAA,EAAA;AAmFI,IAAA,MAAM,IAAA,GAAA,CAAA,CAAO,EAAA,GAAA,IAAA,CAAK,MAAA,CAAO,IAAA,KAAZ,mBAAkB,WAAA,EAAA,KAAiB,EAAA;AAChD,IAAA,MAAM,cAAA,GAAiB;AAAA,MACrB,UAAA;AAAA,MACA,QAAA;AAAA,MACA,MAAA;AAAA,MACA,aAAA;AAAA,MACA,KAAA;AAAA,MACA,OAAA;AAAA,MACA,KAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,OACE,IAAA,CAAK,OAAA,CAAQ,GAAA,KAAQ,IAAA,IACrB,cAAA,CAAe,IAAA,CAAK,CAAC,QAAA,KAAa,IAAA,CAAK,QAAA,CAAS,QAAQ,CAAC,CAAA;AAAA,EAE7D;AAAA;AAAA;AAAA;AAAA,EAKU,wBAAA,GAAmC;AAC3C,IAAA,OAAO,oBAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKU,gBAAA,GAA2B;AA9GvC,IAAA,IAAA,EAAA;AA+GI,IAAA,QAAQ,KAAK,IAAA;AAAM,MACjB,KAAK,UAAA;AACH,QAAA,OAAO,QAAA;AAAA,MACT,KAAK,OAAA;AACH,QAAA,OAAO,IAAA,CAAK,OAAO,QAAA,IAAY,EAAA;AAAA,MACjC,KAAK,QAAA;AACH,QAAA,OAAA,CAAA,CAAO,EAAA,GAAA,IAAA,CAAK,MAAA,CAAO,IAAA,KAAZ,IAAA,GAAA,MAAA,GAAA,EAAA,CAAkB,WAAA,EAAA,KAAiB,EAAA;AAAA,MAC5C,KAAK,OAAA;AACH,QAAA,OAAO,KAAA;AAAA,MACT;AACE,QAAA,OAAO,EAAA;AAAA;AACX,EACF;AAAA;AAAA;AAAA;AAAA,EAKU,gBAAgB,GAAA,EAAsB;AAC9C,IAAA,MAAM,OAAA,GAAU,GAAA,CAAI,IAAA,EAAK,CAAE,WAAA,EAAY;AACvC,IAAA,OACE,QAAQ,UAAA,CAAW,QAAQ,KAC3B,OAAA,CAAQ,UAAA,CAAW,MAAM,CAAA,IACzB,OAAA,CAAQ,UAAA,CAAW,UAAU,KAC7B,OAAA,CAAQ,UAAA,CAAW,SAAS,CAAA,IAC5B,OAAA,CAAQ,WAAW,QAAQ,CAAA;AAAA,EAE/B;AAAA;AAAA;AAAA;AAAA,EAKU,uBAAuB,GAAA,EAAsB;AACrD,IAAA,MAAM,OAAA,GAAU,GAAA,CAAI,IAAA,EAAK,CAAE,WAAA,EAAY;AACvC,IAAA,OACE,OAAA,CAAQ,UAAA,CAAW,QAAQ,CAAA,IAC3B,QAAQ,UAAA,CAAW,MAAM,CAAA,IACzB,OAAA,CAAQ,UAAA,CAAW,OAAO,CAAA,IAC1B,OAAA,CAAQ,WAAW,UAAU,CAAA;AAAA,EAEjC;AAAA;AAAA;AAAA;AAAA,EAMgB,YAAA,CAAa,KAAA,EAAe,OAAA,GAA+B,EAAC,EAAkB;AAC5F,IAAA,MAAM,EAAE,KAAA,GAAQ,mBAAA,EAAqB,SAAS,CAAA,EAAG,SAAA,GAAY,OAAM,GAAI,OAAA;AACvE,IAAA,MAAM,cAAA,GAAiB,YAAY,kBAAA,GAAqB,KAAA;AACxD,IAAA,MAAM,SAAA,GAAY,aAAa,KAAK,CAAA;AAEpC,IAAA,IAAI,SAAA,CAAU,SAAS,QAAA,EAAU;AAC/B,MAAA,MAAM,WAAA,GAAc,eAAA,CAAgB,KAAA,EAAO,cAAA,EAAgB,MAAM,CAAA;AACjE,MAAA,OAAO;AAAA,QACL,OAAO,WAAA,CAAY,GAAA;AAAA,QACnB,YAAY,WAAA,CAAY,UAAA;AAAA,QACxB,KAAA,EAAO,cAAA;AAAA,QACP;AAAA,OACF;AAAA,IACF;AAEA,IAAA,OAAO,EAAE,KAAA,EAAO,UAAA,EAAY,KAAA,EAAO,KAAA,EAAO,gBAAgB,MAAA,EAAO;AAAA,EACnE;AACF","file":"chunk-KV356UXJ.js","sourcesContent":["/**\n * Query Limiter Utility\n * SELECT sorgularına otomatik LIMIT ekleyerek büyük result set'lerin\n * sistemi kilitlemesini önler.\n */\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nexport const DEFAULT_QUERY_LIMIT = 500;\nexport const MAX_UNLIMITED_ROWS = 100000;\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface QueryLimitOptions {\n defaultLimit: number;\n maxUnlimited: number;\n forceLimit: boolean;\n}\n\nexport interface ParsedQueryInfo {\n type: 'SELECT' | 'INSERT' | 'UPDATE' | 'DELETE' | 'DDL' | 'OTHER';\n hasLimit: boolean;\n existingLimit?: number;\n hasOffset: boolean;\n existingOffset?: number;\n isUnion: boolean;\n hasCTE: boolean;\n hasSubquery: boolean;\n}\n\nexport interface LimitedQueryResult {\n sql: string;\n wasLimited: boolean;\n originalLimit?: number;\n appliedLimit: number;\n appliedOffset: number;\n}\n\n// ============================================================================\n// Query Analysis\n// ============================================================================\n\n/**\n * SQL sorgusunu analiz eder ve türünü, LIMIT/OFFSET durumunu belirler.\n */\n/** Strip trailing semicolons and whitespace without regex to avoid ReDoS */\nfunction stripTrailingSemicolon(s: string): string {\n let end = s.length;\n while (end > 0 && (s[end - 1] === ' ' || s[end - 1] === '\\t' || s[end - 1] === '\\n' || s[end - 1] === '\\r')) end--;\n while (end > 0 && s[end - 1] === ';') end--;\n while (end > 0 && (s[end - 1] === ' ' || s[end - 1] === '\\t' || s[end - 1] === '\\n' || s[end - 1] === '\\r')) end--;\n return s.slice(0, end);\n}\n\nexport function analyzeQuery(sql: string): ParsedQueryInfo {\n // Strip trailing whitespace and semicolons upfront to avoid ReDoS-prone patterns\n const trimmed = stripTrailingSemicolon(sql.trim());\n const normalized = trimmed.replace(/\\s+/g, ' ').toUpperCase();\n\n // Query type detection\n let type: ParsedQueryInfo['type'] = 'OTHER';\n if (/^\\s*SELECT\\b/i.test(trimmed)) type = 'SELECT';\n else if (/^\\s*INSERT\\b/i.test(trimmed)) type = 'INSERT';\n else if (/^\\s*UPDATE\\b/i.test(trimmed)) type = 'UPDATE';\n else if (/^\\s*DELETE\\b/i.test(trimmed)) type = 'DELETE';\n else if (/^\\s*(CREATE|ALTER|DROP|TRUNCATE)\\b/i.test(trimmed)) type = 'DDL';\n // CTE (WITH clause) that leads to SELECT\n else if (/^\\s*WITH\\b/i.test(trimmed) && /\\bSELECT\\b/i.test(trimmed)) {\n type = 'SELECT';\n }\n\n // LIMIT/OFFSET detection - en dıştaki sorgunun LIMIT'ini bul\n // Regex: Sorgunun sonundaki LIMIT [sayı] [OFFSET sayı] pattern'i\n const limitMatch = trimmed.match(\n /\\bLIMIT\\s+(\\d+)(?:\\s*,\\s*(\\d+)|\\s+OFFSET\\s+(\\d+))?\\s*$/i\n );\n\n let hasLimit = false;\n let existingLimit: number | undefined;\n let existingOffset: number | undefined;\n\n if (limitMatch) {\n hasLimit = true;\n // LIMIT x, y format (MySQL style) veya LIMIT x OFFSET y\n if (limitMatch[2] !== undefined) {\n // LIMIT offset, count (MySQL style)\n existingOffset = parseInt(limitMatch[1]);\n existingLimit = parseInt(limitMatch[2]);\n } else {\n existingLimit = parseInt(limitMatch[1]);\n existingOffset = limitMatch[3] ? parseInt(limitMatch[3]) : undefined;\n }\n }\n\n // Oracle/MSSQL: FETCH FIRST N ROWS ONLY / FETCH NEXT N ROWS ONLY\n if (!hasLimit) {\n const fetchMatch = trimmed.match(/\\bFETCH\\s+(?:FIRST|NEXT)\\s+(\\d+)\\s+ROWS?\\s+ONLY\\s*$/i);\n if (fetchMatch) {\n hasLimit = true;\n existingLimit = parseInt(fetchMatch[1]);\n }\n }\n\n // MSSQL: SELECT TOP N\n if (!hasLimit) {\n const topMatch = trimmed.match(/^\\s*SELECT\\s+TOP\\s+(\\d+)\\b/i);\n if (topMatch) {\n hasLimit = true;\n existingLimit = parseInt(topMatch[1]);\n }\n }\n\n // Oracle legacy: ROWNUM in WHERE clause\n if (!hasLimit && /\\bROWNUM\\s*<=?\\s*\\d+/i.test(normalized)) {\n hasLimit = true;\n }\n\n // OFFSET without LIMIT (rare but possible in PostgreSQL)\n const offsetOnlyMatch = !hasLimit && trimmed.match(/\\bOFFSET\\s+(\\d+)\\s*$/i);\n const hasOffset = hasLimit ? existingOffset !== undefined : !!offsetOnlyMatch;\n\n if (offsetOnlyMatch && !hasLimit) {\n existingOffset = parseInt(offsetOnlyMatch[1]);\n }\n\n // UNION detection\n const isUnion = /\\bUNION\\b/i.test(normalized);\n\n // CTE detection (WITH clause)\n const hasCTE = /^\\s*WITH\\b/i.test(trimmed);\n\n // Subquery detection (nested SELECT - birden fazla SELECT var mı)\n const selectCount = (normalized.match(/\\bSELECT\\b/g) || []).length;\n const hasSubquery = selectCount > 1;\n\n return {\n type,\n hasLimit,\n existingLimit,\n hasOffset,\n existingOffset,\n isUnion,\n hasCTE,\n hasSubquery,\n };\n}\n\n// ============================================================================\n// Query Limiting\n// ============================================================================\n\n/**\n * SELECT sorgusuna LIMIT ekler veya mevcut LIMIT'i günceller.\n */\nexport function applyQueryLimit(\n sql: string,\n limit: number,\n offset: number = 0,\n options: Partial<QueryLimitOptions> = {}\n): LimitedQueryResult {\n const { forceLimit = false } = options;\n const info = analyzeQuery(sql);\n\n // SELECT değilse, limit ekleme\n if (info.type !== 'SELECT') {\n return {\n sql,\n wasLimited: false,\n appliedLimit: 0,\n appliedOffset: 0,\n };\n }\n\n // Mevcut LIMIT varsa ve forceLimit false ise, mevcut limiti koru\n if (info.hasLimit && !forceLimit) {\n return {\n sql,\n wasLimited: false,\n originalLimit: info.existingLimit,\n appliedLimit: info.existingLimit || 0,\n appliedOffset: info.existingOffset || 0,\n };\n }\n\n // Check for trailing semicolon before stripping (string-based to avoid ReDoS)\n const trimmedInput = sql.trim();\n let modifiedSql = stripTrailingSemicolon(trimmedInput);\n const hasSemicolon = modifiedSql.length < trimmedInput.length && trimmedInput.includes(';');\n\n // Mevcut LIMIT/OFFSET'i kaldır (eğer forceLimit true ise)\n if (info.hasLimit && forceLimit) {\n // MySQL style: LIMIT offset, count\n modifiedSql = modifiedSql\n .replace(/\\bLIMIT\\s+\\d+\\s*,\\s*\\d+\\s*$/i, '')\n .trim();\n // Standard style: LIMIT count OFFSET offset\n modifiedSql = modifiedSql\n .replace(/\\bLIMIT\\s+\\d+(?:\\s+OFFSET\\s+\\d+)?\\s*$/i, '')\n .trim();\n }\n\n // LIMIT OFFSET clause'u ekle\n const limitClause =\n offset > 0 ? `LIMIT ${limit} OFFSET ${offset}` : `LIMIT ${limit}`;\n\n modifiedSql = `${modifiedSql} ${limitClause}`;\n\n if (hasSemicolon) {\n modifiedSql += ';';\n }\n\n return {\n sql: modifiedSql,\n wasLimited: true,\n originalLimit: info.existingLimit,\n appliedLimit: limit,\n appliedOffset: offset,\n };\n}\n\n/**\n * Sorgunun LIMIT'li olup olmadığını hızlıca kontrol eder.\n */\nexport function hasQueryLimit(sql: string): boolean {\n const info = analyzeQuery(sql);\n return info.hasLimit;\n}\n\n/**\n * Sorgunun SELECT türünde olup olmadığını kontrol eder.\n */\nexport function isSelectQuery(sql: string): boolean {\n const info = analyzeQuery(sql);\n return info.type === 'SELECT';\n}\n","/**\n * SQL Base Provider\n * Abstract class with shared logic for all SQL-based databases\n */\n\nimport { BaseDatabaseProvider } from '../../base-provider';\nimport {\n type DatabaseConnection,\n type ProviderOptions,\n type PreparedQuery,\n type QueryPrepareOptions,\n} from '../../types';\nimport {\n analyzeQuery,\n applyQueryLimit,\n DEFAULT_QUERY_LIMIT,\n MAX_UNLIMITED_ROWS,\n} from '../../utils/query-limiter';\n\n// ============================================================================\n// SQL Base Provider\n// ============================================================================\n\nexport abstract class SQLBaseProvider extends BaseDatabaseProvider {\n constructor(config: DatabaseConnection, options: ProviderOptions = {}) {\n super(config, options);\n }\n\n // ============================================================================\n // SQL-Specific Utilities\n // ============================================================================\n\n /**\n * Escape identifier based on SQL dialect\n * PostgreSQL/SQLite: \"identifier\"\n * MySQL: `identifier`\n */\n protected escapeIdentifier(identifier: string): string {\n if (this.type === 'mssql') {\n const escaped = identifier.replace(/\\]/g, ']]');\n return `[${escaped}]`;\n }\n const quoteChar = this.type === 'mysql' ? '`' : '\"';\n const escaped = identifier.replace(\n new RegExp(quoteChar, 'g'),\n quoteChar + quoteChar\n );\n return `${quoteChar}${escaped}${quoteChar}`;\n }\n\n /**\n * Escape string value for SQL\n */\n protected escapeString(value: string): string {\n return value.replace(/'/g, \"''\");\n }\n\n /**\n * Build LIMIT clause based on dialect\n */\n protected buildLimitClause(limit: number, offset?: number): string {\n if (offset !== undefined && offset > 0) {\n return `LIMIT ${limit} OFFSET ${offset}`;\n }\n return `LIMIT ${limit}`;\n }\n\n /**\n * Get placeholder style for parameterized queries\n * PostgreSQL: $1, $2, $3\n * MySQL/SQLite: ?, ?, ?\n */\n protected getPlaceholder(index: number): string {\n if (this.type === 'postgres') return `$${index}`;\n if (this.type === 'oracle') return `:${index}`;\n if (this.type === 'mssql') return `@p${index}`;\n return '?';\n }\n\n /**\n * Determine if SSL should be enabled based on host\n */\n protected shouldEnableSSL(): boolean {\n const host = this.config.host?.toLowerCase() || '';\n const cloudProviders = [\n 'supabase',\n 'render',\n 'neon',\n 'planetscale',\n 'aws',\n 'azure',\n 'gcp',\n 'cloud',\n ];\n return (\n this.options.ssl === true ||\n cloudProviders.some((provider) => host.includes(provider))\n );\n }\n\n /**\n * Get information schema name based on dialect\n */\n protected getInformationSchemaName(): string {\n return 'information_schema';\n }\n\n /**\n * Get default schema/database name for queries\n */\n protected getDefaultSchema(): string {\n switch (this.type) {\n case 'postgres':\n return 'public';\n case 'mysql':\n return this.config.database || '';\n case 'oracle':\n return this.config.user?.toUpperCase() || '';\n case 'mssql':\n return 'dbo';\n default:\n return '';\n }\n }\n\n /**\n * Check if query is read-only (SELECT, SHOW, DESCRIBE, EXPLAIN)\n */\n protected isReadOnlyQuery(sql: string): boolean {\n const trimmed = sql.trim().toLowerCase();\n return (\n trimmed.startsWith('select') ||\n trimmed.startsWith('show') ||\n trimmed.startsWith('describe') ||\n trimmed.startsWith('explain') ||\n trimmed.startsWith('pragma')\n );\n }\n\n /**\n * Check if query modifies schema (CREATE, DROP, ALTER, TRUNCATE)\n */\n protected isSchemaModifyingQuery(sql: string): boolean {\n const trimmed = sql.trim().toLowerCase();\n return (\n trimmed.startsWith('create') ||\n trimmed.startsWith('drop') ||\n trimmed.startsWith('alter') ||\n trimmed.startsWith('truncate')\n );\n }\n\n // ============================================================================\n // Query Preparation (applies LIMIT for SELECT queries)\n // ============================================================================\n\n public override prepareQuery(query: string, options: QueryPrepareOptions = {}): PreparedQuery {\n const { limit = DEFAULT_QUERY_LIMIT, offset = 0, unlimited = false } = options;\n const effectiveLimit = unlimited ? MAX_UNLIMITED_ROWS : limit;\n const queryInfo = analyzeQuery(query);\n\n if (queryInfo.type === 'SELECT') {\n const limitResult = applyQueryLimit(query, effectiveLimit, offset);\n return {\n query: limitResult.sql,\n wasLimited: limitResult.wasLimited,\n limit: effectiveLimit,\n offset,\n };\n }\n\n return { query, wasLimited: false, limit: effectiveLimit, offset };\n }\n}\n"]}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { validateConfig, getSafeConfigForLogging, LLMConfigError, LLMStreamError, isRetryableError, LLMError } from './chunk-SR5DRGBX.mjs';
|
|
2
|
+
import { logger } from './chunk-6DRZXXNT.mjs';
|
|
3
|
+
import { __spreadValues, __forAwait } from './chunk-4LVB3K53.mjs';
|
|
4
|
+
|
|
5
|
+
// src/lib/llm/utils/retry.ts
|
|
6
|
+
var DEFAULT_MAX_ATTEMPTS = 3;
|
|
7
|
+
var DEFAULT_INITIAL_DELAY = 1e3;
|
|
8
|
+
var DEFAULT_BACKOFF_MULTIPLIER = 2;
|
|
9
|
+
var DEFAULT_MAX_DELAY = 1e4;
|
|
10
|
+
async function withRetry(fn, options = {}) {
|
|
11
|
+
const {
|
|
12
|
+
maxAttempts = DEFAULT_MAX_ATTEMPTS,
|
|
13
|
+
initialDelay = DEFAULT_INITIAL_DELAY,
|
|
14
|
+
backoffMultiplier = DEFAULT_BACKOFF_MULTIPLIER,
|
|
15
|
+
maxDelay = DEFAULT_MAX_DELAY,
|
|
16
|
+
provider,
|
|
17
|
+
operation = "LLM request"
|
|
18
|
+
} = options;
|
|
19
|
+
let lastError;
|
|
20
|
+
let delay = initialDelay;
|
|
21
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
22
|
+
try {
|
|
23
|
+
return await fn();
|
|
24
|
+
} catch (error) {
|
|
25
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
26
|
+
if (!isRetryableError(error)) {
|
|
27
|
+
throw error;
|
|
28
|
+
}
|
|
29
|
+
if (attempt === maxAttempts) {
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
console.error(
|
|
33
|
+
`[LLM${provider ? `:${provider}` : ""}] ${operation} failed (attempt ${attempt}/${maxAttempts}): ${lastError.message}. Retrying in ${delay}ms...`
|
|
34
|
+
);
|
|
35
|
+
await sleep(delay);
|
|
36
|
+
delay = Math.min(delay * backoffMultiplier, maxDelay);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
console.error(
|
|
40
|
+
`[LLM${provider ? `:${provider}` : ""}] ${operation} failed after ${maxAttempts} attempts: ${lastError == null ? void 0 : lastError.message}`
|
|
41
|
+
);
|
|
42
|
+
throw lastError != null ? lastError : new LLMError("Unknown error during retry", provider);
|
|
43
|
+
}
|
|
44
|
+
function sleep(ms) {
|
|
45
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/lib/llm/base-provider.ts
|
|
49
|
+
var BaseLLMProvider = class {
|
|
50
|
+
constructor(config) {
|
|
51
|
+
this.name = config.provider;
|
|
52
|
+
this.config = config;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Validate provider configuration
|
|
56
|
+
* Can be overridden by subclasses for provider-specific validation
|
|
57
|
+
*/
|
|
58
|
+
validate() {
|
|
59
|
+
validateConfig(this.config);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Execute stream with retry logic
|
|
63
|
+
*/
|
|
64
|
+
async streamWithRetry(streamFn, retryOptions) {
|
|
65
|
+
return withRetry(streamFn, __spreadValues({
|
|
66
|
+
provider: this.name,
|
|
67
|
+
operation: "stream"
|
|
68
|
+
}, retryOptions));
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get the model to use (from options or config)
|
|
72
|
+
*/
|
|
73
|
+
getModel(options) {
|
|
74
|
+
var _a;
|
|
75
|
+
return (_a = options.model) != null ? _a : this.config.model;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Build system message from messages array
|
|
79
|
+
*/
|
|
80
|
+
getSystemMessage(options) {
|
|
81
|
+
const systemMessage = options.messages.find((m) => m.role === "system");
|
|
82
|
+
return systemMessage == null ? void 0 : systemMessage.content;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Build user/assistant messages (excluding system)
|
|
86
|
+
*/
|
|
87
|
+
getNonSystemMessages(options) {
|
|
88
|
+
return options.messages.filter((m) => m.role !== "system").map((m) => ({
|
|
89
|
+
role: m.role,
|
|
90
|
+
content: m.content
|
|
91
|
+
}));
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Log error with safe config
|
|
95
|
+
*/
|
|
96
|
+
logError(operation, error) {
|
|
97
|
+
const safeConfig = getSafeConfigForLogging(this.config);
|
|
98
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
99
|
+
console.error(`[LLM:${this.name}] ${operation} failed:`, errorMessage, safeConfig);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Ensure API key is available
|
|
103
|
+
*/
|
|
104
|
+
ensureApiKey() {
|
|
105
|
+
if (!this.config.apiKey) {
|
|
106
|
+
throw new LLMConfigError(
|
|
107
|
+
`API key is required for ${this.name} provider`,
|
|
108
|
+
this.name
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
return this.config.apiKey;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Ensure API URL is available
|
|
115
|
+
*/
|
|
116
|
+
ensureApiUrl() {
|
|
117
|
+
if (!this.config.apiUrl) {
|
|
118
|
+
throw new LLMConfigError(
|
|
119
|
+
`API URL is required for ${this.name} provider`,
|
|
120
|
+
this.name
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
return this.config.apiUrl;
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// src/lib/llm/utils/streaming.ts
|
|
128
|
+
var textEncoder = new TextEncoder();
|
|
129
|
+
var textDecoder = new TextDecoder();
|
|
130
|
+
function encodeText(text) {
|
|
131
|
+
return textEncoder.encode(text);
|
|
132
|
+
}
|
|
133
|
+
function decodeText(bytes) {
|
|
134
|
+
return textDecoder.decode(bytes);
|
|
135
|
+
}
|
|
136
|
+
function createSSEParser() {
|
|
137
|
+
let buffer = "";
|
|
138
|
+
return new TransformStream({
|
|
139
|
+
transform(chunk, controller) {
|
|
140
|
+
var _a;
|
|
141
|
+
buffer += decodeText(chunk);
|
|
142
|
+
const lines = buffer.split("\n");
|
|
143
|
+
buffer = (_a = lines.pop()) != null ? _a : "";
|
|
144
|
+
for (const line of lines) {
|
|
145
|
+
const trimmed = line.trim();
|
|
146
|
+
if (!trimmed || trimmed.startsWith(":")) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (trimmed.startsWith("data: ")) {
|
|
150
|
+
const data = trimmed.slice(6);
|
|
151
|
+
if (data === "[DONE]") {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
const parsed = JSON.parse(data);
|
|
156
|
+
const content = extractContent(parsed);
|
|
157
|
+
if (content) {
|
|
158
|
+
controller.enqueue(encodeText(content));
|
|
159
|
+
}
|
|
160
|
+
} catch (e) {
|
|
161
|
+
logger.debug("Skipping malformed JSON chunk in SSE stream");
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
flush(controller) {
|
|
167
|
+
if (buffer.trim()) {
|
|
168
|
+
const trimmed = buffer.trim();
|
|
169
|
+
if (trimmed.startsWith("data: ") && trimmed.slice(6) !== "[DONE]") {
|
|
170
|
+
try {
|
|
171
|
+
const parsed = JSON.parse(trimmed.slice(6));
|
|
172
|
+
const content = extractContent(parsed);
|
|
173
|
+
if (content) {
|
|
174
|
+
controller.enqueue(encodeText(content));
|
|
175
|
+
}
|
|
176
|
+
} catch (e) {
|
|
177
|
+
logger.debug("Skipping malformed JSON chunk in SSE stream flush");
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
function extractContent(data) {
|
|
185
|
+
if (!data || typeof data !== "object") {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
const obj = data;
|
|
189
|
+
if (Array.isArray(obj.choices) && obj.choices.length > 0) {
|
|
190
|
+
const choice = obj.choices[0];
|
|
191
|
+
const delta = choice.delta;
|
|
192
|
+
if (delta && typeof delta.content === "string") {
|
|
193
|
+
return delta.content;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
function streamFromAsyncIterable(iterable, transform) {
|
|
199
|
+
return new ReadableStream({
|
|
200
|
+
async start(controller) {
|
|
201
|
+
try {
|
|
202
|
+
try {
|
|
203
|
+
for (var iter = __forAwait(iterable), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
204
|
+
const item = temp.value;
|
|
205
|
+
const chunk = transform(item);
|
|
206
|
+
if (chunk) {
|
|
207
|
+
controller.enqueue(chunk);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
} catch (temp) {
|
|
211
|
+
error = [temp];
|
|
212
|
+
} finally {
|
|
213
|
+
try {
|
|
214
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
215
|
+
} finally {
|
|
216
|
+
if (error)
|
|
217
|
+
throw error[0];
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
controller.close();
|
|
221
|
+
} catch (error2) {
|
|
222
|
+
controller.error(error2);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
function createStreamFromSSEResponse(response, provider) {
|
|
228
|
+
const body = response.body;
|
|
229
|
+
if (!body) {
|
|
230
|
+
throw new LLMStreamError("Response body is empty", provider);
|
|
231
|
+
}
|
|
232
|
+
return body.pipeThrough(createSSEParser());
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export { BaseLLMProvider, createStreamFromSSEResponse, encodeText, streamFromAsyncIterable };
|
|
236
|
+
//# sourceMappingURL=chunk-PPODO6HX.mjs.map
|
|
237
|
+
//# sourceMappingURL=chunk-PPODO6HX.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/llm/utils/retry.ts","../src/lib/llm/base-provider.ts","../src/lib/llm/utils/streaming.ts"],"names":["error"],"mappings":"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","file":"chunk-PPODO6HX.mjs","sourcesContent":["/**\n * Retry Utility with Exponential Backoff\n * Handles transient failures in LLM API calls\n */\n\nimport { isRetryableError, LLMError, type LLMProviderType } from '../types';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface RetryOptions {\n /** Maximum number of retry attempts (default: 3) */\n maxAttempts?: number;\n /** Initial delay in milliseconds (default: 1000) */\n initialDelay?: number;\n /** Backoff multiplier (default: 2) */\n backoffMultiplier?: number;\n /** Maximum delay in milliseconds (default: 10000) */\n maxDelay?: number;\n /** Provider name for logging */\n provider?: LLMProviderType;\n /** Operation name for logging */\n operation?: string;\n}\n\n// ============================================================================\n// Default Configuration\n// ============================================================================\n\nconst DEFAULT_MAX_ATTEMPTS = 3;\nconst DEFAULT_INITIAL_DELAY = 1000;\nconst DEFAULT_BACKOFF_MULTIPLIER = 2;\nconst DEFAULT_MAX_DELAY = 10000;\n\n// ============================================================================\n// Retry Implementation\n// ============================================================================\n\n/**\n * Execute a function with retry logic and exponential backoff\n * @param fn - Async function to execute\n * @param options - Retry configuration\n * @returns Result of the function\n * @throws Last error if all retries fail\n */\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n options: RetryOptions = {}\n): Promise<T> {\n const {\n maxAttempts = DEFAULT_MAX_ATTEMPTS,\n initialDelay = DEFAULT_INITIAL_DELAY,\n backoffMultiplier = DEFAULT_BACKOFF_MULTIPLIER,\n maxDelay = DEFAULT_MAX_DELAY,\n provider,\n operation = 'LLM request',\n } = options;\n\n let lastError: Error | undefined;\n let delay = initialDelay;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n // Check if error is retryable\n if (!isRetryableError(error)) {\n throw error;\n }\n\n // Don't retry on last attempt\n if (attempt === maxAttempts) {\n break;\n }\n\n // Log retry attempt\n console.error(\n `[LLM${provider ? `:${provider}` : ''}] ${operation} failed (attempt ${attempt}/${maxAttempts}): ${lastError.message}. Retrying in ${delay}ms...`\n );\n\n // Wait before retrying\n await sleep(delay);\n\n // Increase delay with exponential backoff\n delay = Math.min(delay * backoffMultiplier, maxDelay);\n }\n }\n\n // All retries exhausted\n console.error(\n `[LLM${provider ? `:${provider}` : ''}] ${operation} failed after ${maxAttempts} attempts: ${lastError?.message}`\n );\n\n throw lastError ?? new LLMError('Unknown error during retry', provider);\n}\n\n/**\n * Sleep for a specified duration\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n// ============================================================================\n// Retry Decorators (for class methods)\n// ============================================================================\n\n/**\n * Create a retryable version of an async function\n */\nexport function makeRetryable<T extends unknown[], R>(\n fn: (...args: T) => Promise<R>,\n options: RetryOptions = {}\n): (...args: T) => Promise<R> {\n return (...args: T) => withRetry(() => fn(...args), options);\n}\n","/**\n * Base LLM Provider\n * Abstract class implementing common provider functionality\n */\n\nimport {\n type LLMConfig,\n type LLMProvider,\n type LLMProviderType,\n type LLMStreamOptions,\n LLMConfigError,\n} from './types';\nimport { validateConfig, getSafeConfigForLogging } from './utils/config';\nimport { withRetry, type RetryOptions } from './utils/retry';\n\n// ============================================================================\n// Base Provider Class\n// ============================================================================\n\nexport abstract class BaseLLMProvider implements LLMProvider {\n public readonly name: LLMProviderType;\n public readonly config: LLMConfig;\n\n protected constructor(config: LLMConfig) {\n this.name = config.provider;\n this.config = config;\n }\n\n /**\n * Validate provider configuration\n * Can be overridden by subclasses for provider-specific validation\n */\n public validate(): void {\n validateConfig(this.config);\n }\n\n /**\n * Stream completion - must be implemented by subclasses\n */\n public abstract stream(options: LLMStreamOptions): Promise<ReadableStream<Uint8Array>>;\n\n /**\n * Execute stream with retry logic\n */\n protected async streamWithRetry(\n streamFn: () => Promise<ReadableStream<Uint8Array>>,\n retryOptions?: RetryOptions\n ): Promise<ReadableStream<Uint8Array>> {\n return withRetry(streamFn, {\n provider: this.name,\n operation: 'stream',\n ...retryOptions,\n });\n }\n\n /**\n * Get the model to use (from options or config)\n */\n protected getModel(options: LLMStreamOptions): string {\n return options.model ?? this.config.model;\n }\n\n /**\n * Build system message from messages array\n */\n protected getSystemMessage(options: LLMStreamOptions): string | undefined {\n const systemMessage = options.messages.find((m) => m.role === 'system');\n return systemMessage?.content;\n }\n\n /**\n * Build user/assistant messages (excluding system)\n */\n protected getNonSystemMessages(options: LLMStreamOptions): Array<{ role: 'user' | 'assistant'; content: string }> {\n return options.messages\n .filter((m) => m.role !== 'system')\n .map((m) => ({\n role: m.role as 'user' | 'assistant',\n content: m.content,\n }));\n }\n\n /**\n * Log error with safe config\n */\n protected logError(operation: string, error: unknown): void {\n const safeConfig = getSafeConfigForLogging(this.config);\n const errorMessage = error instanceof Error ? error.message : String(error);\n console.error(`[LLM:${this.name}] ${operation} failed:`, errorMessage, safeConfig);\n }\n\n /**\n * Ensure API key is available\n */\n protected ensureApiKey(): string {\n if (!this.config.apiKey) {\n throw new LLMConfigError(\n `API key is required for ${this.name} provider`,\n this.name\n );\n }\n return this.config.apiKey;\n }\n\n /**\n * Ensure API URL is available\n */\n protected ensureApiUrl(): string {\n if (!this.config.apiUrl) {\n throw new LLMConfigError(\n `API URL is required for ${this.name} provider`,\n this.name\n );\n }\n return this.config.apiUrl;\n }\n}\n","/**\n * Streaming Utilities for LLM Providers\n * SSE parsing and stream transformation helpers\n */\n\nimport { LLMStreamError, type LLMProviderType } from '../types';\nimport { logger } from '@/lib/logger';\n\n// ============================================================================\n// Text Encoding/Decoding\n// ============================================================================\n\nconst textEncoder = new TextEncoder();\nconst textDecoder = new TextDecoder();\n\nexport function encodeText(text: string): Uint8Array {\n return textEncoder.encode(text);\n}\n\nexport function decodeText(bytes: Uint8Array): string {\n return textDecoder.decode(bytes);\n}\n\n// ============================================================================\n// SSE (Server-Sent Events) Parser\n// ============================================================================\n\nexport interface SSEChunk {\n data: string;\n event?: string;\n id?: string;\n}\n\n/**\n * Parse SSE formatted response for OpenAI-compatible APIs\n * Handles chunked responses and extracts content from delta objects\n */\nexport function createSSEParser(): TransformStream<Uint8Array, Uint8Array> {\n let buffer = '';\n\n return new TransformStream<Uint8Array, Uint8Array>({\n transform(chunk, controller) {\n buffer += decodeText(chunk);\n\n // Process complete lines\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? ''; // Keep incomplete line in buffer\n\n for (const line of lines) {\n const trimmed = line.trim();\n\n // Skip empty lines and comments\n if (!trimmed || trimmed.startsWith(':')) {\n continue;\n }\n\n // Handle data lines\n if (trimmed.startsWith('data: ')) {\n const data = trimmed.slice(6);\n\n // Handle stream end marker\n if (data === '[DONE]') {\n return;\n }\n\n try {\n const parsed = JSON.parse(data);\n const content = extractContent(parsed);\n\n if (content) {\n controller.enqueue(encodeText(content));\n }\n } catch {\n logger.debug('Skipping malformed JSON chunk in SSE stream');\n }\n }\n }\n },\n\n flush(controller) {\n // Process any remaining data in buffer\n if (buffer.trim()) {\n const trimmed = buffer.trim();\n if (trimmed.startsWith('data: ') && trimmed.slice(6) !== '[DONE]') {\n try {\n const parsed = JSON.parse(trimmed.slice(6));\n const content = extractContent(parsed);\n if (content) {\n controller.enqueue(encodeText(content));\n }\n } catch {\n logger.debug('Skipping malformed JSON chunk in SSE stream flush');\n }\n }\n }\n },\n });\n}\n\n/**\n * Extract content from parsed SSE data based on provider format\n */\nfunction extractContent(data: unknown): string | null {\n if (!data || typeof data !== 'object') {\n return null;\n }\n\n const obj = data as Record<string, unknown>;\n\n // OpenAI format: choices[0].delta.content\n if (Array.isArray(obj.choices) && obj.choices.length > 0) {\n const choice = obj.choices[0] as Record<string, unknown>;\n const delta = choice.delta as Record<string, unknown> | undefined;\n\n if (delta && typeof delta.content === 'string') {\n return delta.content;\n }\n }\n\n return null;\n}\n\n// ============================================================================\n// Stream Utilities\n// ============================================================================\n\n/**\n * Create a ReadableStream from an async iterable\n */\nexport function streamFromAsyncIterable<T>(\n iterable: AsyncIterable<T>,\n transform: (item: T) => Uint8Array | null\n): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n async start(controller) {\n try {\n for await (const item of iterable) {\n const chunk = transform(item);\n if (chunk) {\n controller.enqueue(chunk);\n }\n }\n controller.close();\n } catch (error) {\n controller.error(error);\n }\n },\n });\n}\n\n/**\n * Create a ReadableStream from a fetch Response with SSE parsing\n */\nexport function createStreamFromSSEResponse(\n response: Response,\n provider: LLMProviderType\n): ReadableStream<Uint8Array> {\n const body = response.body;\n\n if (!body) {\n throw new LLMStreamError('Response body is empty', provider);\n }\n\n return body.pipeThrough(createSSEParser());\n}\n\n/**\n * Merge multiple streams into one (useful for multi-part responses)\n */\nexport function mergeStreams(\n streams: ReadableStream<Uint8Array>[]\n): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n async start(controller) {\n for (const stream of streams) {\n const reader = stream.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n controller.enqueue(value);\n }\n } finally {\n reader.releaseLock();\n }\n }\n controller.close();\n },\n });\n}\n\n/**\n * Create an error stream that emits a single error message\n */\nexport function createErrorStream(message: string): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n controller.enqueue(encodeText(`Error: ${message}`));\n controller.close();\n },\n });\n}\n"]}
|