drizzle-cube 0.3.13 → 0.3.16
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/adapters/express/index.cjs +1 -1
- package/dist/adapters/express/index.d.ts +8 -1
- package/dist/adapters/express/index.js +162 -99
- package/dist/adapters/fastify/index.cjs +1 -1
- package/dist/adapters/fastify/index.d.ts +8 -1
- package/dist/adapters/fastify/index.js +183 -96
- package/dist/adapters/hono/index.cjs +1 -1
- package/dist/adapters/hono/index.d.ts +8 -1
- package/dist/adapters/hono/index.js +198 -142
- package/dist/adapters/nextjs/index.cjs +1 -1
- package/dist/adapters/nextjs/index.d.ts +29 -1
- package/dist/adapters/nextjs/index.js +251 -132
- package/dist/adapters/utils.d.ts +100 -1
- package/dist/adapters/validation-Bgauxvm6.cjs +214 -0
- package/dist/adapters/{compiler-DTOU8IsK.js → validation-_UkKJ2pC.js} +9582 -5295
- package/dist/client/adapters/index.d.ts +2 -0
- package/dist/client/adapters/retentionModeAdapter.d.ts +3 -0
- package/dist/client/charts.js +12 -12
- package/dist/client/chunks/RetentionCombinedChart-DirfDaZH.js +256 -0
- package/dist/client/chunks/RetentionCombinedChart-DirfDaZH.js.map +1 -0
- package/dist/client/chunks/RetentionCombinedChart.config-C-ILIaEb.js +47 -0
- package/dist/client/chunks/RetentionCombinedChart.config-C-ILIaEb.js.map +1 -0
- package/dist/client/chunks/RetentionHeatmap-Bofadstm.js +178 -0
- package/dist/client/chunks/RetentionHeatmap-Bofadstm.js.map +1 -0
- package/dist/client/chunks/RetentionHeatmap.config-CIvhc-GT.js +28 -0
- package/dist/client/chunks/RetentionHeatmap.config-CIvhc-GT.js.map +1 -0
- package/dist/client/chunks/analysis-builder-APeCxkEH.js +6939 -0
- package/dist/client/chunks/analysis-builder-APeCxkEH.js.map +1 -0
- package/dist/client/chunks/analysis-builder-shared-DEovRjrp.js +2779 -0
- package/dist/client/chunks/analysis-builder-shared-DEovRjrp.js.map +1 -0
- package/dist/client/chunks/{chart-activity-grid-CuPARsr1.js → chart-activity-grid-BnweuBvr.js} +11 -11
- package/dist/client/chunks/{chart-activity-grid-CuPARsr1.js.map → chart-activity-grid-BnweuBvr.js.map} +1 -1
- package/dist/client/chunks/{chart-area-cPrJnhLj.js → chart-area-DLmXFWWy.js} +2 -2
- package/dist/client/chunks/{chart-area-cPrJnhLj.js.map → chart-area-DLmXFWWy.js.map} +1 -1
- package/dist/client/chunks/{chart-bar-D68HFPpa.js → chart-bar-7y0-F27Q.js} +2 -2
- package/dist/client/chunks/{chart-bar-D68HFPpa.js.map → chart-bar-7y0-F27Q.js.map} +1 -1
- package/dist/client/chunks/{chart-bubble-CquyYfNO.js → chart-bubble-3jYKCA2B.js} +2 -2
- package/dist/client/chunks/{chart-bubble-CquyYfNO.js.map → chart-bubble-3jYKCA2B.js.map} +1 -1
- package/dist/client/chunks/{chart-config-activity-grid-Bkvx0F-G.js → chart-config-activity-grid-BBSNCbkb.js} +2 -2
- package/dist/client/chunks/{chart-config-activity-grid-Bkvx0F-G.js.map → chart-config-activity-grid-BBSNCbkb.js.map} +1 -1
- package/dist/client/chunks/{chart-config-area-OApsRaYC.js → chart-config-area-CyyJOO2T.js} +2 -2
- package/dist/client/chunks/{chart-config-area-OApsRaYC.js.map → chart-config-area-CyyJOO2T.js.map} +1 -1
- package/dist/client/chunks/{chart-config-bar-Dy21oaIA.js → chart-config-bar-BJKGnfLt.js} +2 -2
- package/dist/client/chunks/{chart-config-bar-Dy21oaIA.js.map → chart-config-bar-BJKGnfLt.js.map} +1 -1
- package/dist/client/chunks/{chart-config-bubble-Chv0SoFm.js → chart-config-bubble-CuSsCHZ4.js} +2 -2
- package/dist/client/chunks/{chart-config-bubble-Chv0SoFm.js.map → chart-config-bubble-CuSsCHZ4.js.map} +1 -1
- package/dist/client/chunks/{chart-config-data-table-DTIdC35a.js → chart-config-data-table-BhgqwoqT.js} +2 -2
- package/dist/client/chunks/{chart-config-data-table-DTIdC35a.js.map → chart-config-data-table-BhgqwoqT.js.map} +1 -1
- package/dist/client/chunks/{chart-config-funnel-f17Livgr.js → chart-config-funnel-BlSQYng0.js} +4 -4
- package/dist/client/chunks/{chart-config-funnel-f17Livgr.js.map → chart-config-funnel-BlSQYng0.js.map} +1 -1
- package/dist/client/chunks/{chart-config-heat-map-DPhNICha.js → chart-config-heat-map-DHQGFZhX.js} +2 -2
- package/dist/client/chunks/{chart-config-heat-map-DPhNICha.js.map → chart-config-heat-map-DHQGFZhX.js.map} +1 -1
- package/dist/client/chunks/{chart-config-kpi-delta-CCl1d-St.js → chart-config-kpi-delta-yTA5ug_l.js} +2 -2
- package/dist/client/chunks/{chart-config-kpi-delta-CCl1d-St.js.map → chart-config-kpi-delta-yTA5ug_l.js.map} +1 -1
- package/dist/client/chunks/{chart-config-kpi-number-DkE3eSwH.js → chart-config-kpi-number-nVAwDXzq.js} +2 -2
- package/dist/client/chunks/{chart-config-kpi-number-DkE3eSwH.js.map → chart-config-kpi-number-nVAwDXzq.js.map} +1 -1
- package/dist/client/chunks/{chart-config-kpi-text-BMbgdxZm.js → chart-config-kpi-text-DZjqsx-b.js} +2 -2
- package/dist/client/chunks/{chart-config-kpi-text-BMbgdxZm.js.map → chart-config-kpi-text-DZjqsx-b.js.map} +1 -1
- package/dist/client/chunks/{chart-config-line-BnLlRUQE.js → chart-config-line-DR0ThxZy.js} +2 -2
- package/dist/client/chunks/{chart-config-line-BnLlRUQE.js.map → chart-config-line-DR0ThxZy.js.map} +1 -1
- package/dist/client/chunks/{chart-config-markdown-DIaMFC0Z.js → chart-config-markdown-DZxdGNVQ.js} +2 -2
- package/dist/client/chunks/{chart-config-markdown-DIaMFC0Z.js.map → chart-config-markdown-DZxdGNVQ.js.map} +1 -1
- package/dist/client/chunks/{chart-config-pie-O9y_T0BQ.js → chart-config-pie-BM5lgH-w.js} +2 -2
- package/dist/client/chunks/{chart-config-pie-O9y_T0BQ.js.map → chart-config-pie-BM5lgH-w.js.map} +1 -1
- package/dist/client/chunks/{chart-config-radar-CXa0354h.js → chart-config-radar-BBAVIF0S.js} +2 -2
- package/dist/client/chunks/{chart-config-radar-CXa0354h.js.map → chart-config-radar-BBAVIF0S.js.map} +1 -1
- package/dist/client/chunks/{chart-config-radial-bar-BppJU8-Q.js → chart-config-radial-bar-CTwjDRnB.js} +2 -2
- package/dist/client/chunks/{chart-config-radial-bar-BppJU8-Q.js.map → chart-config-radial-bar-CTwjDRnB.js.map} +1 -1
- package/dist/client/chunks/{chart-config-sankey-BfBHgL4x.js → chart-config-sankey-CNAgsMQ4.js} +2 -2
- package/dist/client/chunks/{chart-config-sankey-BfBHgL4x.js.map → chart-config-sankey-CNAgsMQ4.js.map} +1 -1
- package/dist/client/chunks/{chart-config-scatter-BTt8a10R.js → chart-config-scatter-CWvN2E-X.js} +2 -2
- package/dist/client/chunks/{chart-config-scatter-BTt8a10R.js.map → chart-config-scatter-CWvN2E-X.js.map} +1 -1
- package/dist/client/chunks/{chart-config-sunburst-DNmQpIIx.js → chart-config-sunburst-W_SKwaj0.js} +4 -4
- package/dist/client/chunks/{chart-config-sunburst-DNmQpIIx.js.map → chart-config-sunburst-W_SKwaj0.js.map} +1 -1
- package/dist/client/chunks/{chart-config-tree-map-HVgG4oa0.js → chart-config-tree-map-CLmRvvMR.js} +2 -2
- package/dist/client/chunks/{chart-config-tree-map-HVgG4oa0.js.map → chart-config-tree-map-CLmRvvMR.js.map} +1 -1
- package/dist/client/chunks/{chart-data-table-D4WDqbM0.js → chart-data-table-rUFLqysu.js} +4 -4
- package/dist/client/chunks/{chart-data-table-D4WDqbM0.js.map → chart-data-table-rUFLqysu.js.map} +1 -1
- package/dist/client/chunks/{chart-funnel-Csdn4FbN.js → chart-funnel-C7zGBfSw.js} +2 -2
- package/dist/client/chunks/{chart-funnel-Csdn4FbN.js.map → chart-funnel-C7zGBfSw.js.map} +1 -1
- package/dist/client/chunks/{chart-heat-map-v1afxnjq.js → chart-heat-map-B-l8hK8b.js} +2 -2
- package/dist/client/chunks/{chart-heat-map-v1afxnjq.js.map → chart-heat-map-B-l8hK8b.js.map} +1 -1
- package/dist/client/chunks/chart-kpi-delta-sfZEvQZm.js +351 -0
- package/dist/client/chunks/chart-kpi-delta-sfZEvQZm.js.map +1 -0
- package/dist/client/chunks/chart-kpi-number-BxGNOtzI.js +473 -0
- package/dist/client/chunks/chart-kpi-number-BxGNOtzI.js.map +1 -0
- package/dist/client/chunks/{chart-kpi-text-CRp8QWYG.js → chart-kpi-text-BLQ_CWQP.js} +3 -3
- package/dist/client/chunks/{chart-kpi-text-CRp8QWYG.js.map → chart-kpi-text-BLQ_CWQP.js.map} +1 -1
- package/dist/client/chunks/{chart-line-DqqE7ky9.js → chart-line-FSEpBk6Y.js} +5 -5
- package/dist/client/chunks/{chart-line-DqqE7ky9.js.map → chart-line-FSEpBk6Y.js.map} +1 -1
- package/dist/client/chunks/{chart-pie-B5WBzIRH.js → chart-pie-BRQEH9e-.js} +2 -2
- package/dist/client/chunks/{chart-pie-B5WBzIRH.js.map → chart-pie-BRQEH9e-.js.map} +1 -1
- package/dist/client/chunks/{chart-radar-DL_dvhA-.js → chart-radar-DgsFyiIP.js} +2 -2
- package/dist/client/chunks/{chart-radar-DL_dvhA-.js.map → chart-radar-DgsFyiIP.js.map} +1 -1
- package/dist/client/chunks/{chart-radial-bar-DDRo6nz-.js → chart-radial-bar-CUMoXyl9.js} +2 -2
- package/dist/client/chunks/{chart-radial-bar-DDRo6nz-.js.map → chart-radial-bar-CUMoXyl9.js.map} +1 -1
- package/dist/client/chunks/{chart-sankey-C_bgIfg-.js → chart-sankey-IAKDEe7A.js} +2 -2
- package/dist/client/chunks/{chart-sankey-C_bgIfg-.js.map → chart-sankey-IAKDEe7A.js.map} +1 -1
- package/dist/client/chunks/{chart-scatter-DjmJRlK0.js → chart-scatter-D6XwOD2W.js} +15 -15
- package/dist/client/chunks/{chart-scatter-DjmJRlK0.js.map → chart-scatter-D6XwOD2W.js.map} +1 -1
- package/dist/client/chunks/{chart-sunburst-CbMEnaes.js → chart-sunburst-CP_pnj0S.js} +2 -2
- package/dist/client/chunks/{chart-sunburst-CbMEnaes.js.map → chart-sunburst-CP_pnj0S.js.map} +1 -1
- package/dist/client/chunks/{chart-tree-map-DEfJtJVC.js → chart-tree-map-DQMsn47a.js} +30 -30
- package/dist/client/chunks/{chart-tree-map-DEfJtJVC.js.map → chart-tree-map-DQMsn47a.js.map} +1 -1
- package/dist/client/chunks/chartConfigRegistry-BumUIPw4.js +44 -0
- package/dist/client/chunks/{chartConfigRegistry-CiOq-PqX.js.map → chartConfigRegistry-BumUIPw4.js.map} +1 -1
- package/dist/client/chunks/charts-Dk_9XrA7.js +230 -0
- package/dist/client/chunks/charts-Dk_9XrA7.js.map +1 -0
- package/dist/client/chunks/{charts-core-CXrhEEVF.js → charts-core-CjQZBxmv.js} +10 -10
- package/dist/client/chunks/{charts-core-CXrhEEVF.js.map → charts-core-CjQZBxmv.js.map} +1 -1
- package/dist/client/chunks/{charts-loader-BtsnUO4Q.js → charts-loader-ChTUa_-G.js} +30 -28
- package/dist/client/chunks/charts-loader-ChTUa_-G.js.map +1 -0
- package/dist/client/chunks/{components-BDrlf9Er.js → components-BKZ7EAg0.js} +3575 -3208
- package/dist/client/chunks/components-BKZ7EAg0.js.map +1 -0
- package/dist/client/chunks/{core-B8zw0qRf.js → core-BRC075EG.js} +2 -2
- package/dist/client/chunks/{core-B8zw0qRf.js.map → core-BRC075EG.js.map} +1 -1
- package/dist/client/chunks/hooks-D7APQ8uS.js +150 -0
- package/dist/client/chunks/{hooks-B8Zw5PfL.js.map → hooks-D7APQ8uS.js.map} +1 -1
- package/dist/client/chunks/{icons-NzFHtqeM.js → icons-DRreo6m8.js} +128 -112
- package/dist/client/chunks/{icons-NzFHtqeM.js.map → icons-DRreo6m8.js.map} +1 -1
- package/dist/client/chunks/{providers-CqCiJTEj.js → providers-Cj7PQfXn.js} +2 -2
- package/dist/client/chunks/{providers-CqCiJTEj.js.map → providers-Cj7PQfXn.js.map} +1 -1
- package/dist/client/chunks/retention-CzCo8262.js +120 -0
- package/dist/client/chunks/retention-CzCo8262.js.map +1 -0
- package/dist/client/chunks/{useDirtyStateTracking-C_mitVwh.js → useDirtyStateTracking-ZSi3voVl.js} +101 -99
- package/dist/client/chunks/useDirtyStateTracking-ZSi3voVl.js.map +1 -0
- package/dist/client/chunks/{vendor-DzzxS7Ay.js → vendor-cTQhZ_G3.js} +549 -541
- package/dist/client/chunks/vendor-cTQhZ_G3.js.map +1 -0
- package/dist/client/components/AnalysisBuilder/AnalysisTypeSelector.d.ts +3 -1
- package/dist/client/components/AnalysisBuilder/RetentionConfigPanel.d.ts +36 -0
- package/dist/client/components/AnalysisBuilder/RetentionModeContent.d.ts +71 -0
- package/dist/client/components/AnalysisBuilder/types.d.ts +99 -0
- package/dist/client/components/DebugModal.d.ts +2 -1
- package/dist/client/components/charts/RetentionCombinedChart.config.d.ts +2 -0
- package/dist/client/components/charts/RetentionCombinedChart.d.ts +14 -0
- package/dist/client/components/charts/RetentionHeatmap.config.d.ts +2 -0
- package/dist/client/components/charts/RetentionHeatmap.d.ts +7 -0
- package/dist/client/components.js +2 -2
- package/dist/client/hooks/queries/index.d.ts +2 -1
- package/dist/client/hooks/queries/useDryRunQuery.d.ts +26 -0
- package/dist/client/hooks/queries/useExplainQuery.d.ts +3 -1
- package/dist/client/hooks/queries/useFlowQuery.d.ts +5 -0
- package/dist/client/hooks/queries/useRetentionQuery.d.ts +67 -0
- package/dist/client/hooks/useAnalysisBuilderHook.d.ts +61 -0
- package/dist/client/hooks/useAnalysisQueryExecution.d.ts +42 -1
- package/dist/client/hooks.js +3 -3
- package/dist/client/icons/customIcons.d.ts +7 -0
- package/dist/client/icons/types.d.ts +1 -0
- package/dist/client/icons.js +1 -1
- package/dist/client/index.js +11 -11
- package/dist/client/providers.js +1 -1
- package/dist/client/stores/analysisBuilderStore.d.ts +86 -1
- package/dist/client/stores/dashboardStore.d.ts +2 -1
- package/dist/client/stores/slices/index.d.ts +2 -0
- package/dist/client/stores/slices/retentionSlice.d.ts +66 -0
- package/dist/client/styles.css +1 -1
- package/dist/client/types/analysisConfig.d.ts +29 -4
- package/dist/client/types/funnel.d.ts +5 -0
- package/dist/client/types/retention.d.ts +301 -0
- package/dist/client/types.d.ts +6 -3
- package/dist/client-bundle-stats.html +1 -1
- package/dist/server/index.cjs +101 -79
- package/dist/server/index.d.ts +427 -0
- package/dist/server/index.js +9140 -4934
- package/package.json +5 -2
- package/dist/adapters/compiler-CO13DaEb.cjs +0 -192
- package/dist/client/chunks/analysis-builder-Dc9NrG_N.js +0 -6013
- package/dist/client/chunks/analysis-builder-Dc9NrG_N.js.map +0 -1
- package/dist/client/chunks/analysis-builder-shared-B3-UWqQ2.js +0 -2540
- package/dist/client/chunks/analysis-builder-shared-B3-UWqQ2.js.map +0 -1
- package/dist/client/chunks/chart-kpi-delta-Bs5R5xr4.js +0 -435
- package/dist/client/chunks/chart-kpi-delta-Bs5R5xr4.js.map +0 -1
- package/dist/client/chunks/chart-kpi-number-Cf4Pgkm9.js +0 -392
- package/dist/client/chunks/chart-kpi-number-Cf4Pgkm9.js.map +0 -1
- package/dist/client/chunks/chartConfigRegistry-CiOq-PqX.js +0 -44
- package/dist/client/chunks/charts-loader-BtsnUO4Q.js.map +0 -1
- package/dist/client/chunks/charts-xNubY0vm.js +0 -226
- package/dist/client/chunks/charts-xNubY0vm.js.map +0 -1
- package/dist/client/chunks/components-BDrlf9Er.js.map +0 -1
- package/dist/client/chunks/hooks-B8Zw5PfL.js +0 -123
- package/dist/client/chunks/useDirtyStateTracking-C_mitVwh.js.map +0 -1
- package/dist/client/chunks/vendor-DzzxS7Ay.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("express"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("express"),C=require("cors"),a=require("../validation-Bgauxvm6.cjs");function R(f){const{cubes:y,drizzle:j,schema:v,extractSecurityContext:l,engineType:x,cors:b,basePath:d="/cubejs-api/v1",jsonLimit:g="10mb",cache:q,mcp:h={enabled:!0}}=f;if(!y||y.length===0)throw new Error("At least one cube must be provided in the cubes array");const c=p.Router();b&&c.use(C(b)),c.use(p.json({limit:g})),c.use(p.urlencoded({extended:!0,limit:g}));const i=new a.SemanticLayerCompiler({drizzle:j,schema:v,engineType:x,cache:q});if(y.forEach(t=>{i.registerCube(t)}),c.post(`${d}/load`,async(t,r)=>{try{const e=t.body.query||t.body,s=await l(t,r),o=i.validateQuery(e);if(!o.isValid)return r.status(400).json(a.formatErrorResponse(`Query validation failed: ${o.errors.join(", ")}`,400));const n=t.headers["x-cache-control"]==="no-cache",u=await i.executeMultiCubeQuery(e,s,{skipCache:n});r.json(a.formatCubeResponse(e,u,i))}catch(e){console.error("Query execution error:",e),r.status(500).json(a.formatErrorResponse(e instanceof Error?e.message:"Query execution failed",500))}}),c.get(`${d}/load`,async(t,r)=>{try{const e=t.query.query;if(!e)return r.status(400).json(a.formatErrorResponse("Query parameter is required",400));let s;try{s=JSON.parse(e)}catch{return r.status(400).json(a.formatErrorResponse("Invalid JSON in query parameter",400))}const o=await l(t,r),n=i.validateQuery(s);if(!n.isValid)return r.status(400).json(a.formatErrorResponse(`Query validation failed: ${n.errors.join(", ")}`,400));const u=t.headers["x-cache-control"]==="no-cache",m=await i.executeMultiCubeQuery(s,o,{skipCache:u});r.json(a.formatCubeResponse(s,m,i))}catch(e){console.error("Query execution error:",e),r.status(500).json(a.formatErrorResponse(e instanceof Error?e.message:"Query execution failed",500))}}),c.post(`${d}/batch`,async(t,r)=>{try{const{queries:e}=t.body;if(!e||!Array.isArray(e))return r.status(400).json(a.formatErrorResponse('Request body must contain a "queries" array',400));if(e.length===0)return r.status(400).json(a.formatErrorResponse("Queries array cannot be empty",400));const s=await l(t,r),o=t.headers["x-cache-control"]==="no-cache",n=await a.handleBatchRequest(e,s,i,{skipCache:o});r.json(n)}catch(e){console.error("Batch execution error:",e),r.status(500).json(a.formatErrorResponse(e instanceof Error?e.message:"Batch execution failed",500))}}),c.get(`${d}/meta`,(t,r)=>{try{const e=i.getMetadata();r.json(a.formatMetaResponse(e))}catch(e){console.error("Metadata error:",e),r.status(500).json(a.formatErrorResponse(e instanceof Error?e.message:"Failed to fetch metadata",500))}}),c.post(`${d}/sql`,async(t,r)=>{try{const e=t.body,s=await l(t,r),o=i.validateQuery(e);if(!o.isValid)return r.status(400).json(a.formatErrorResponse(`Query validation failed: ${o.errors.join(", ")}`,400));const n=e.measures?.[0]||e.dimensions?.[0];if(!n)return r.status(400).json(a.formatErrorResponse("No measures or dimensions specified",400));const u=n.split(".")[0],m=await i.generateSQL(u,e,s);r.json(a.formatSqlResponse(e,m))}catch(e){console.error("SQL generation error:",e),r.status(500).json(a.formatErrorResponse(e instanceof Error?e.message:"SQL generation failed",500))}}),c.get(`${d}/sql`,async(t,r)=>{try{const e=t.query.query;if(!e)return r.status(400).json(a.formatErrorResponse("Query parameter is required",400));const s=JSON.parse(e),o=await l(t,r),n=i.validateQuery(s);if(!n.isValid)return r.status(400).json(a.formatErrorResponse(`Query validation failed: ${n.errors.join(", ")}`,400));const u=s.measures?.[0]||s.dimensions?.[0];if(!u)return r.status(400).json(a.formatErrorResponse("No measures or dimensions specified",400));const m=u.split(".")[0],Q=await i.generateSQL(m,s,o);r.json(a.formatSqlResponse(s,Q))}catch(e){console.error("SQL generation error:",e),r.status(500).json(a.formatErrorResponse(e instanceof Error?e.message:"SQL generation failed",500))}}),c.post(`${d}/dry-run`,async(t,r)=>{try{const e=t.body.query||t.body,s=await l(t,r),o=await a.handleDryRun(e,s,i);r.json(o)}catch(e){console.error("Dry-run error:",e),r.status(400).json({error:e instanceof Error?e.message:"Dry-run validation failed",valid:!1})}}),c.get(`${d}/dry-run`,async(t,r)=>{try{const e=t.query.query;if(!e)return r.status(400).json({error:"Query parameter is required",valid:!1});const s=JSON.parse(e),o=await l(t,r),n=await a.handleDryRun(s,o,i);r.json(n)}catch(e){console.error("Dry-run error:",e),r.status(400).json({error:e instanceof Error?e.message:"Dry-run validation failed",valid:!1})}}),c.post(`${d}/explain`,async(t,r)=>{try{const e=t.body.query||t.body,s=t.body.options||{},o=await l(t,r),n=i.validateQuery(e);if(!n.isValid)return r.status(400).json({error:`Query validation failed: ${n.errors.join(", ")}`});const u=await i.explainQuery(e,o,s);r.json(u)}catch(e){console.error("Explain error:",e),r.status(500).json({error:e instanceof Error?e.message:"Explain query failed"})}}),h.enabled!==!1){const t=h.tools||["discover","suggest","validate","load"],r=h.basePath??"/mcp";t.includes("discover")&&c.post(`${r}/discover`,async(e,s)=>{try{const o=e.body,n=await a.handleDiscover(i,o);s.json(n)}catch(o){console.error("Discover error:",o),s.status(500).json(a.formatErrorResponse(o instanceof Error?o.message:"Discovery failed",500))}}),t.includes("suggest")&&c.post(`${r}/suggest`,async(e,s)=>{try{const o=e.body;if(!o.naturalLanguage)return s.status(400).json(a.formatErrorResponse("naturalLanguage field is required",400));const n=await a.handleSuggest(i,o);s.json(n)}catch(o){console.error("Suggest error:",o),s.status(500).json(a.formatErrorResponse(o instanceof Error?o.message:"Query suggestion failed",500))}}),t.includes("validate")&&c.post(`${r}/validate`,async(e,s)=>{try{const o=e.body;if(!o.query)return s.status(400).json(a.formatErrorResponse("query field is required",400));const n=await a.handleValidate(i,o);s.json(n)}catch(o){console.error("Validate error:",o),s.status(500).json(a.formatErrorResponse(o instanceof Error?o.message:"Query validation failed",500))}}),t.includes("load")&&c.post(`${r}/load`,async(e,s)=>{try{const o=e.body;if(!o.query)return s.status(400).json(a.formatErrorResponse("query field is required",400));const n=await l(e,s),u=await a.handleLoad(i,n,o);s.json(u)}catch(o){console.error("Load error:",o),s.status(500).json(a.formatErrorResponse(o instanceof Error?o.message:"Query execution failed",500))}})}return c.use((t,r,e,s)=>{console.error("Express adapter error:",t),e.headersSent||e.status(500).json(a.formatErrorResponse(t,500))}),c}function E(f,y){const j=R(y);return f.use("/",j),f}function w(f){const y=p();return E(y,f)}exports.createCubeApp=w;exports.createCubeRouter=R;exports.mountCubeRoutes=E;
|
|
@@ -4,6 +4,7 @@ import { SemanticQuery, SecurityContext, DatabaseExecutor, DrizzleDatabase, Cube
|
|
|
4
4
|
import { PostgresJsDatabase } from 'drizzle-orm/postgres-js';
|
|
5
5
|
import { MySql2Database } from 'drizzle-orm/mysql2';
|
|
6
6
|
import { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';
|
|
7
|
+
import { MCPOptions } from '../utils';
|
|
7
8
|
export interface ExpressAdapterOptions {
|
|
8
9
|
/**
|
|
9
10
|
* Array of cube definitions to register
|
|
@@ -48,7 +49,7 @@ export interface ExpressAdapterOptions {
|
|
|
48
49
|
/**
|
|
49
50
|
* Database engine type (optional - auto-detected if not provided)
|
|
50
51
|
*/
|
|
51
|
-
engineType?: 'postgres' | 'mysql' | 'sqlite';
|
|
52
|
+
engineType?: 'postgres' | 'mysql' | 'sqlite' | 'singlestore' | 'duckdb';
|
|
52
53
|
/**
|
|
53
54
|
* CORS configuration (optional)
|
|
54
55
|
*/
|
|
@@ -66,6 +67,12 @@ export interface ExpressAdapterOptions {
|
|
|
66
67
|
* When provided, query results will be cached using the specified provider
|
|
67
68
|
*/
|
|
68
69
|
cache?: CacheConfig;
|
|
70
|
+
/**
|
|
71
|
+
* MCP (AI-Ready) endpoint configuration
|
|
72
|
+
* Enables AI agents to discover and query your data
|
|
73
|
+
* @default { enabled: true }
|
|
74
|
+
*/
|
|
75
|
+
mcp?: MCPOptions;
|
|
69
76
|
}
|
|
70
77
|
/**
|
|
71
78
|
* Create Express router for Cube.js-compatible API
|
|
@@ -1,212 +1,275 @@
|
|
|
1
|
-
import h, { Router as
|
|
2
|
-
import
|
|
3
|
-
import { S,
|
|
4
|
-
function
|
|
1
|
+
import h, { Router as $ } from "express";
|
|
2
|
+
import S from "cors";
|
|
3
|
+
import { S as R, j as n, f as v, h as L, a as D, b as x, c as Q, d as N, e as M, g as V, i as P } from "../validation-_UkKJ2pC.js";
|
|
4
|
+
function A(f) {
|
|
5
5
|
const {
|
|
6
|
-
cubes:
|
|
7
|
-
drizzle:
|
|
8
|
-
schema:
|
|
6
|
+
cubes: y,
|
|
7
|
+
drizzle: j,
|
|
8
|
+
schema: q,
|
|
9
9
|
extractSecurityContext: l,
|
|
10
|
-
engineType:
|
|
11
|
-
cors:
|
|
12
|
-
basePath:
|
|
10
|
+
engineType: w,
|
|
11
|
+
cors: g,
|
|
12
|
+
basePath: d = "/cubejs-api/v1",
|
|
13
13
|
jsonLimit: b = "10mb",
|
|
14
|
-
cache:
|
|
14
|
+
cache: C,
|
|
15
|
+
mcp: p = { enabled: !0 }
|
|
15
16
|
} = f;
|
|
16
|
-
if (!
|
|
17
|
+
if (!y || y.length === 0)
|
|
17
18
|
throw new Error("At least one cube must be provided in the cubes array");
|
|
18
|
-
const c =
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
drizzle:
|
|
22
|
-
schema:
|
|
23
|
-
engineType:
|
|
24
|
-
cache:
|
|
19
|
+
const c = $();
|
|
20
|
+
g && c.use(S(g)), c.use(h.json({ limit: b })), c.use(h.urlencoded({ extended: !0, limit: b }));
|
|
21
|
+
const i = new R({
|
|
22
|
+
drizzle: j,
|
|
23
|
+
schema: q,
|
|
24
|
+
engineType: w,
|
|
25
|
+
cache: C
|
|
25
26
|
});
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}), c.post(`${
|
|
27
|
+
if (y.forEach((o) => {
|
|
28
|
+
i.registerCube(o);
|
|
29
|
+
}), c.post(`${d}/load`, async (o, t) => {
|
|
29
30
|
try {
|
|
30
|
-
const e =
|
|
31
|
-
if (!
|
|
32
|
-
return t.status(400).json(
|
|
33
|
-
`Query validation failed: ${
|
|
31
|
+
const e = o.body.query || o.body, s = await l(o, t), r = i.validateQuery(e);
|
|
32
|
+
if (!r.isValid)
|
|
33
|
+
return t.status(400).json(n(
|
|
34
|
+
`Query validation failed: ${r.errors.join(", ")}`,
|
|
34
35
|
400
|
|
35
36
|
));
|
|
36
|
-
const
|
|
37
|
-
t.json(
|
|
37
|
+
const a = o.headers["x-cache-control"] === "no-cache", u = await i.executeMultiCubeQuery(e, s, { skipCache: a });
|
|
38
|
+
t.json(v(e, u, i));
|
|
38
39
|
} catch (e) {
|
|
39
|
-
console.error("Query execution error:", e), t.status(500).json(
|
|
40
|
+
console.error("Query execution error:", e), t.status(500).json(n(
|
|
40
41
|
e instanceof Error ? e.message : "Query execution failed",
|
|
41
42
|
500
|
|
42
43
|
));
|
|
43
44
|
}
|
|
44
|
-
}), c.get(`${
|
|
45
|
+
}), c.get(`${d}/load`, async (o, t) => {
|
|
45
46
|
try {
|
|
46
|
-
const e =
|
|
47
|
+
const e = o.query.query;
|
|
47
48
|
if (!e)
|
|
48
|
-
return t.status(400).json(
|
|
49
|
+
return t.status(400).json(n(
|
|
49
50
|
"Query parameter is required",
|
|
50
51
|
400
|
|
51
52
|
));
|
|
52
|
-
let
|
|
53
|
+
let s;
|
|
53
54
|
try {
|
|
54
|
-
|
|
55
|
+
s = JSON.parse(e);
|
|
55
56
|
} catch {
|
|
56
|
-
return t.status(400).json(
|
|
57
|
+
return t.status(400).json(n(
|
|
57
58
|
"Invalid JSON in query parameter",
|
|
58
59
|
400
|
|
59
60
|
));
|
|
60
61
|
}
|
|
61
|
-
const
|
|
62
|
-
if (!
|
|
63
|
-
return t.status(400).json(
|
|
64
|
-
`Query validation failed: ${
|
|
62
|
+
const r = await l(o, t), a = i.validateQuery(s);
|
|
63
|
+
if (!a.isValid)
|
|
64
|
+
return t.status(400).json(n(
|
|
65
|
+
`Query validation failed: ${a.errors.join(", ")}`,
|
|
65
66
|
400
|
|
66
67
|
));
|
|
67
|
-
const u =
|
|
68
|
-
t.json(
|
|
68
|
+
const u = o.headers["x-cache-control"] === "no-cache", m = await i.executeMultiCubeQuery(s, r, { skipCache: u });
|
|
69
|
+
t.json(v(s, m, i));
|
|
69
70
|
} catch (e) {
|
|
70
|
-
console.error("Query execution error:", e), t.status(500).json(
|
|
71
|
+
console.error("Query execution error:", e), t.status(500).json(n(
|
|
71
72
|
e instanceof Error ? e.message : "Query execution failed",
|
|
72
73
|
500
|
|
73
74
|
));
|
|
74
75
|
}
|
|
75
|
-
}), c.post(`${
|
|
76
|
+
}), c.post(`${d}/batch`, async (o, t) => {
|
|
76
77
|
try {
|
|
77
|
-
const { queries: e } =
|
|
78
|
+
const { queries: e } = o.body;
|
|
78
79
|
if (!e || !Array.isArray(e))
|
|
79
|
-
return t.status(400).json(
|
|
80
|
+
return t.status(400).json(n(
|
|
80
81
|
'Request body must contain a "queries" array',
|
|
81
82
|
400
|
|
82
83
|
));
|
|
83
84
|
if (e.length === 0)
|
|
84
|
-
return t.status(400).json(
|
|
85
|
+
return t.status(400).json(n(
|
|
85
86
|
"Queries array cannot be empty",
|
|
86
87
|
400
|
|
87
88
|
));
|
|
88
|
-
const
|
|
89
|
-
t.json(
|
|
89
|
+
const s = await l(o, t), r = o.headers["x-cache-control"] === "no-cache", a = await L(e, s, i, { skipCache: r });
|
|
90
|
+
t.json(a);
|
|
90
91
|
} catch (e) {
|
|
91
|
-
console.error("Batch execution error:", e), t.status(500).json(
|
|
92
|
+
console.error("Batch execution error:", e), t.status(500).json(n(
|
|
92
93
|
e instanceof Error ? e.message : "Batch execution failed",
|
|
93
94
|
500
|
|
94
95
|
));
|
|
95
96
|
}
|
|
96
|
-
}), c.get(`${
|
|
97
|
+
}), c.get(`${d}/meta`, (o, t) => {
|
|
97
98
|
try {
|
|
98
|
-
const e =
|
|
99
|
-
t.json(
|
|
99
|
+
const e = i.getMetadata();
|
|
100
|
+
t.json(D(e));
|
|
100
101
|
} catch (e) {
|
|
101
|
-
console.error("Metadata error:", e), t.status(500).json(
|
|
102
|
+
console.error("Metadata error:", e), t.status(500).json(n(
|
|
102
103
|
e instanceof Error ? e.message : "Failed to fetch metadata",
|
|
103
104
|
500
|
|
104
105
|
));
|
|
105
106
|
}
|
|
106
|
-
}), c.post(`${
|
|
107
|
+
}), c.post(`${d}/sql`, async (o, t) => {
|
|
107
108
|
try {
|
|
108
|
-
const e =
|
|
109
|
-
if (!
|
|
110
|
-
return t.status(400).json(
|
|
111
|
-
`Query validation failed: ${
|
|
109
|
+
const e = o.body, s = await l(o, t), r = i.validateQuery(e);
|
|
110
|
+
if (!r.isValid)
|
|
111
|
+
return t.status(400).json(n(
|
|
112
|
+
`Query validation failed: ${r.errors.join(", ")}`,
|
|
112
113
|
400
|
|
113
114
|
));
|
|
114
|
-
const
|
|
115
|
-
if (!
|
|
116
|
-
return t.status(400).json(
|
|
115
|
+
const a = e.measures?.[0] || e.dimensions?.[0];
|
|
116
|
+
if (!a)
|
|
117
|
+
return t.status(400).json(n(
|
|
117
118
|
"No measures or dimensions specified",
|
|
118
119
|
400
|
|
119
120
|
));
|
|
120
|
-
const u =
|
|
121
|
-
t.json(
|
|
121
|
+
const u = a.split(".")[0], m = await i.generateSQL(u, e, s);
|
|
122
|
+
t.json(x(e, m));
|
|
122
123
|
} catch (e) {
|
|
123
|
-
console.error("SQL generation error:", e), t.status(500).json(
|
|
124
|
+
console.error("SQL generation error:", e), t.status(500).json(n(
|
|
124
125
|
e instanceof Error ? e.message : "SQL generation failed",
|
|
125
126
|
500
|
|
126
127
|
));
|
|
127
128
|
}
|
|
128
|
-
}), c.get(`${
|
|
129
|
+
}), c.get(`${d}/sql`, async (o, t) => {
|
|
129
130
|
try {
|
|
130
|
-
const e =
|
|
131
|
+
const e = o.query.query;
|
|
131
132
|
if (!e)
|
|
132
|
-
return t.status(400).json(
|
|
133
|
+
return t.status(400).json(n(
|
|
133
134
|
"Query parameter is required",
|
|
134
135
|
400
|
|
135
136
|
));
|
|
136
|
-
const
|
|
137
|
-
if (!
|
|
138
|
-
return t.status(400).json(
|
|
139
|
-
`Query validation failed: ${
|
|
137
|
+
const s = JSON.parse(e), r = await l(o, t), a = i.validateQuery(s);
|
|
138
|
+
if (!a.isValid)
|
|
139
|
+
return t.status(400).json(n(
|
|
140
|
+
`Query validation failed: ${a.errors.join(", ")}`,
|
|
140
141
|
400
|
|
141
142
|
));
|
|
142
|
-
const u =
|
|
143
|
+
const u = s.measures?.[0] || s.dimensions?.[0];
|
|
143
144
|
if (!u)
|
|
144
|
-
return t.status(400).json(
|
|
145
|
+
return t.status(400).json(n(
|
|
145
146
|
"No measures or dimensions specified",
|
|
146
147
|
400
|
|
147
148
|
));
|
|
148
|
-
const m = u.split(".")[0],
|
|
149
|
-
t.json(
|
|
149
|
+
const m = u.split(".")[0], E = await i.generateSQL(m, s, r);
|
|
150
|
+
t.json(x(s, E));
|
|
150
151
|
} catch (e) {
|
|
151
|
-
console.error("SQL generation error:", e), t.status(500).json(
|
|
152
|
+
console.error("SQL generation error:", e), t.status(500).json(n(
|
|
152
153
|
e instanceof Error ? e.message : "SQL generation failed",
|
|
153
154
|
500
|
|
154
155
|
));
|
|
155
156
|
}
|
|
156
|
-
}), c.post(`${
|
|
157
|
+
}), c.post(`${d}/dry-run`, async (o, t) => {
|
|
157
158
|
try {
|
|
158
|
-
const e =
|
|
159
|
-
t.json(
|
|
159
|
+
const e = o.body.query || o.body, s = await l(o, t), r = await Q(e, s, i);
|
|
160
|
+
t.json(r);
|
|
160
161
|
} catch (e) {
|
|
161
162
|
console.error("Dry-run error:", e), t.status(400).json({
|
|
162
163
|
error: e instanceof Error ? e.message : "Dry-run validation failed",
|
|
163
164
|
valid: !1
|
|
164
165
|
});
|
|
165
166
|
}
|
|
166
|
-
}), c.get(`${
|
|
167
|
+
}), c.get(`${d}/dry-run`, async (o, t) => {
|
|
167
168
|
try {
|
|
168
|
-
const e =
|
|
169
|
+
const e = o.query.query;
|
|
169
170
|
if (!e)
|
|
170
171
|
return t.status(400).json({
|
|
171
172
|
error: "Query parameter is required",
|
|
172
173
|
valid: !1
|
|
173
174
|
});
|
|
174
|
-
const
|
|
175
|
-
t.json(
|
|
175
|
+
const s = JSON.parse(e), r = await l(o, t), a = await Q(s, r, i);
|
|
176
|
+
t.json(a);
|
|
176
177
|
} catch (e) {
|
|
177
178
|
console.error("Dry-run error:", e), t.status(400).json({
|
|
178
179
|
error: e instanceof Error ? e.message : "Dry-run validation failed",
|
|
179
180
|
valid: !1
|
|
180
181
|
});
|
|
181
182
|
}
|
|
182
|
-
}), c.post(`${
|
|
183
|
+
}), c.post(`${d}/explain`, async (o, t) => {
|
|
183
184
|
try {
|
|
184
|
-
const e =
|
|
185
|
-
if (!
|
|
185
|
+
const e = o.body.query || o.body, s = o.body.options || {}, r = await l(o, t), a = i.validateQuery(e);
|
|
186
|
+
if (!a.isValid)
|
|
186
187
|
return t.status(400).json({
|
|
187
|
-
error: `Query validation failed: ${
|
|
188
|
+
error: `Query validation failed: ${a.errors.join(", ")}`
|
|
188
189
|
});
|
|
189
|
-
const u = await
|
|
190
|
+
const u = await i.explainQuery(e, r, s);
|
|
190
191
|
t.json(u);
|
|
191
192
|
} catch (e) {
|
|
192
193
|
console.error("Explain error:", e), t.status(500).json({
|
|
193
194
|
error: e instanceof Error ? e.message : "Explain query failed"
|
|
194
195
|
});
|
|
195
196
|
}
|
|
196
|
-
}),
|
|
197
|
-
|
|
197
|
+
}), p.enabled !== !1) {
|
|
198
|
+
const o = p.tools || ["discover", "suggest", "validate", "load"], t = p.basePath ?? "/mcp";
|
|
199
|
+
o.includes("discover") && c.post(`${t}/discover`, async (e, s) => {
|
|
200
|
+
try {
|
|
201
|
+
const r = e.body, a = await N(i, r);
|
|
202
|
+
s.json(a);
|
|
203
|
+
} catch (r) {
|
|
204
|
+
console.error("Discover error:", r), s.status(500).json(n(
|
|
205
|
+
r instanceof Error ? r.message : "Discovery failed",
|
|
206
|
+
500
|
|
207
|
+
));
|
|
208
|
+
}
|
|
209
|
+
}), o.includes("suggest") && c.post(`${t}/suggest`, async (e, s) => {
|
|
210
|
+
try {
|
|
211
|
+
const r = e.body;
|
|
212
|
+
if (!r.naturalLanguage)
|
|
213
|
+
return s.status(400).json(n(
|
|
214
|
+
"naturalLanguage field is required",
|
|
215
|
+
400
|
|
216
|
+
));
|
|
217
|
+
const a = await M(i, r);
|
|
218
|
+
s.json(a);
|
|
219
|
+
} catch (r) {
|
|
220
|
+
console.error("Suggest error:", r), s.status(500).json(n(
|
|
221
|
+
r instanceof Error ? r.message : "Query suggestion failed",
|
|
222
|
+
500
|
|
223
|
+
));
|
|
224
|
+
}
|
|
225
|
+
}), o.includes("validate") && c.post(`${t}/validate`, async (e, s) => {
|
|
226
|
+
try {
|
|
227
|
+
const r = e.body;
|
|
228
|
+
if (!r.query)
|
|
229
|
+
return s.status(400).json(n(
|
|
230
|
+
"query field is required",
|
|
231
|
+
400
|
|
232
|
+
));
|
|
233
|
+
const a = await V(i, r);
|
|
234
|
+
s.json(a);
|
|
235
|
+
} catch (r) {
|
|
236
|
+
console.error("Validate error:", r), s.status(500).json(n(
|
|
237
|
+
r instanceof Error ? r.message : "Query validation failed",
|
|
238
|
+
500
|
|
239
|
+
));
|
|
240
|
+
}
|
|
241
|
+
}), o.includes("load") && c.post(`${t}/load`, async (e, s) => {
|
|
242
|
+
try {
|
|
243
|
+
const r = e.body;
|
|
244
|
+
if (!r.query)
|
|
245
|
+
return s.status(400).json(n(
|
|
246
|
+
"query field is required",
|
|
247
|
+
400
|
|
248
|
+
));
|
|
249
|
+
const a = await l(e, s), u = await P(i, a, r);
|
|
250
|
+
s.json(u);
|
|
251
|
+
} catch (r) {
|
|
252
|
+
console.error("Load error:", r), s.status(500).json(n(
|
|
253
|
+
r instanceof Error ? r.message : "Query execution failed",
|
|
254
|
+
500
|
|
255
|
+
));
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
return c.use((o, t, e, s) => {
|
|
260
|
+
console.error("Express adapter error:", o), e.headersSent || e.status(500).json(n(o, 500));
|
|
198
261
|
}), c;
|
|
199
262
|
}
|
|
200
|
-
function
|
|
201
|
-
const
|
|
202
|
-
return f.use("/",
|
|
263
|
+
function B(f, y) {
|
|
264
|
+
const j = A(y);
|
|
265
|
+
return f.use("/", j), f;
|
|
203
266
|
}
|
|
204
|
-
function
|
|
205
|
-
const
|
|
206
|
-
return
|
|
267
|
+
function _(f) {
|
|
268
|
+
const y = h();
|
|
269
|
+
return B(y, f);
|
|
207
270
|
}
|
|
208
271
|
export {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
272
|
+
_ as createCubeApp,
|
|
273
|
+
A as createCubeRouter,
|
|
274
|
+
B as mountCubeRoutes
|
|
212
275
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var j=Object.create;var v=Object.defineProperty;var $=Object.getOwnPropertyDescriptor;var S=Object.getOwnPropertyNames;var P=Object.getPrototypeOf,L=Object.prototype.hasOwnProperty;var D=(u,n,b,h)=>{if(n&&typeof n=="object"||typeof n=="function")for(let y of S(n))!L.call(u,y)&&y!==b&&v(u,y,{get:()=>n[y],enumerable:!(h=$(n,y))||h.enumerable});return u};var M=(u,n,b)=>(b=u!=null?j(P(u)):{},D(n||!u||!u.__esModule?v(b,"default",{value:u,enumerable:!0}):b,u));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("../validation-Bgauxvm6.cjs"),E=function(n,b,h){const{cubes:y,drizzle:q,schema:x,extractSecurityContext:l,engineType:Q,cors:R,basePath:p="/cubejs-api/v1",bodyLimit:m=10485760,cache:C,mcp:f={enabled:!0}}=b;if(!y||y.length===0)return h(new Error("At least one cube must be provided in the cubes array"));R&&n.register(import("@fastify/cors"),R),n.addHook("onRequest",async(r,o)=>{r.method==="POST"&&(r.body=void 0)});const i=new a.SemanticLayerCompiler({drizzle:q,schema:x,engineType:Q,cache:C});if(y.forEach(r=>{i.registerCube(r)}),n.post(`${p}/load`,{bodyLimit:m,schema:{body:{type:"object",additionalProperties:!0}}},async(r,o)=>{try{const e=r.body,s=e.query||e,t=await l(r),c=i.validateQuery(s);if(!c.isValid)return o.status(400).send(a.formatErrorResponse(`Query validation failed: ${c.errors.join(", ")}`,400));const d=r.headers["x-cache-control"]==="no-cache",g=await i.executeMultiCubeQuery(s,t,{skipCache:d});return a.formatCubeResponse(s,g,i)}catch(e){return r.log.error(e,"Query execution error"),o.status(500).send(a.formatErrorResponse(e instanceof Error?e.message:"Query execution failed",500))}}),n.get(`${p}/load`,{schema:{querystring:{type:"object",properties:{query:{type:"string"}},required:["query"]}}},async(r,o)=>{try{const{query:e}=r.query;let s;try{s=JSON.parse(e)}catch{return o.status(400).send(a.formatErrorResponse("Invalid JSON in query parameter",400))}const t=await l(r),c=i.validateQuery(s);if(!c.isValid)return o.status(400).send(a.formatErrorResponse(`Query validation failed: ${c.errors.join(", ")}`,400));const d=r.headers["x-cache-control"]==="no-cache",g=await i.executeMultiCubeQuery(s,t,{skipCache:d});return a.formatCubeResponse(s,g,i)}catch(e){return r.log.error(e,"Query execution error"),o.status(500).send(a.formatErrorResponse(e instanceof Error?e.message:"Query execution failed",500))}}),n.post(`${p}/batch`,{bodyLimit:m,schema:{body:{type:"object",required:["queries"],properties:{queries:{type:"array",items:{type:"object"}}}}}},async(r,o)=>{try{const{queries:e}=r.body;if(!e||!Array.isArray(e))return o.status(400).send(a.formatErrorResponse('Request body must contain a "queries" array',400));if(e.length===0)return o.status(400).send(a.formatErrorResponse("Queries array cannot be empty",400));const s=await l(r),t=r.headers["x-cache-control"]==="no-cache";return await a.handleBatchRequest(e,s,i,{skipCache:t})}catch(e){return r.log.error(e,"Batch execution error"),o.status(500).send(a.formatErrorResponse(e instanceof Error?e.message:"Batch execution failed",500))}}),n.get(`${p}/meta`,async(r,o)=>{try{const e=i.getMetadata();return a.formatMetaResponse(e)}catch(e){return r.log.error(e,"Metadata error"),o.status(500).send(a.formatErrorResponse(e instanceof Error?e.message:"Failed to fetch metadata",500))}}),n.post(`${p}/sql`,{bodyLimit:m,schema:{body:{type:"object",additionalProperties:!0}}},async(r,o)=>{try{const e=r.body,s=await l(r),t=i.validateQuery(e);if(!t.isValid)return o.status(400).send(a.formatErrorResponse(`Query validation failed: ${t.errors.join(", ")}`,400));const c=e.measures?.[0]||e.dimensions?.[0];if(!c)return o.status(400).send(a.formatErrorResponse("No measures or dimensions specified",400));const d=c.split(".")[0],g=await i.generateSQL(d,e,s);return a.formatSqlResponse(e,g)}catch(e){return r.log.error(e,"SQL generation error"),o.status(500).send(a.formatErrorResponse(e instanceof Error?e.message:"SQL generation failed",500))}}),n.get(`${p}/sql`,{schema:{querystring:{type:"object",properties:{query:{type:"string"}},required:["query"]}}},async(r,o)=>{try{const{query:e}=r.query,s=JSON.parse(e),t=await l(r),c=i.validateQuery(s);if(!c.isValid)return o.status(400).send(a.formatErrorResponse(`Query validation failed: ${c.errors.join(", ")}`,400));const d=s.measures?.[0]||s.dimensions?.[0];if(!d)return o.status(400).send(a.formatErrorResponse("No measures or dimensions specified",400));const g=d.split(".")[0],w=await i.generateSQL(g,s,t);return a.formatSqlResponse(s,w)}catch(e){return r.log.error(e,"SQL generation error"),o.status(500).send(a.formatErrorResponse(e instanceof Error?e.message:"SQL generation failed",500))}}),n.post(`${p}/dry-run`,{bodyLimit:m,schema:{body:{type:"object",additionalProperties:!0}}},async(r,o)=>{try{const e=r.body,s=e.query||e,t=await l(r);return await a.handleDryRun(s,t,i)}catch(e){return r.log.error(e,"Dry-run error"),o.status(400).send({error:e instanceof Error?e.message:"Dry-run validation failed",valid:!1})}}),n.get(`${p}/dry-run`,{schema:{querystring:{type:"object",properties:{query:{type:"string"}},required:["query"]}}},async(r,o)=>{try{const{query:e}=r.query,s=JSON.parse(e),t=await l(r);return await a.handleDryRun(s,t,i)}catch(e){return r.log.error(e,"Dry-run error"),o.status(400).send({error:e instanceof Error?e.message:"Dry-run validation failed",valid:!1})}}),n.post(`${p}/explain`,{bodyLimit:m,schema:{body:{type:"object",additionalProperties:!0}}},async(r,o)=>{try{const e=r.body,s=e.query||e,t=e.options||{},c=await l(r),d=i.validateQuery(s);return d.isValid?await i.explainQuery(s,c,t):o.status(400).send({error:`Query validation failed: ${d.errors.join(", ")}`})}catch(e){return r.log.error(e,"Explain error"),o.status(500).send({error:e instanceof Error?e.message:"Explain query failed"})}}),f.enabled!==!1){const r=f.tools||["discover","suggest","validate","load"],o=f.basePath??"/mcp";r.includes("discover")&&n.post(`${o}/discover`,{bodyLimit:m,schema:{body:{type:"object",additionalProperties:!0}}},async(e,s)=>{try{const t=e.body;return await a.handleDiscover(i,t)}catch(t){return e.log.error(t,"Discover error"),s.status(500).send(a.formatErrorResponse(t instanceof Error?t.message:"Discovery failed",500))}}),r.includes("suggest")&&n.post(`${o}/suggest`,{bodyLimit:m,schema:{body:{type:"object",required:["naturalLanguage"],properties:{naturalLanguage:{type:"string"},cube:{type:"string"}}}}},async(e,s)=>{try{const t=e.body;return await a.handleSuggest(i,t)}catch(t){return e.log.error(t,"Suggest error"),s.status(500).send(a.formatErrorResponse(t instanceof Error?t.message:"Query suggestion failed",500))}}),r.includes("validate")&&n.post(`${o}/validate`,{bodyLimit:m,schema:{body:{type:"object",required:["query"],properties:{query:{type:"object"}}}}},async(e,s)=>{try{const t=e.body;return await a.handleValidate(i,t)}catch(t){return e.log.error(t,"Validate error"),s.status(500).send(a.formatErrorResponse(t instanceof Error?t.message:"Query validation failed",500))}}),r.includes("load")&&n.post(`${o}/load`,{bodyLimit:m,schema:{body:{type:"object",required:["query"],properties:{query:{type:"object"}}}}},async(e,s)=>{try{const t=e.body,c=await l(e);return await a.handleLoad(i,c,t)}catch(t){return e.log.error(t,"Load error"),s.status(500).send(a.formatErrorResponse(t instanceof Error?t.message:"Query execution failed",500))}})}n.setErrorHandler(async(r,o,e)=>{o.log.error(r,"Fastify cube adapter error"),e.statusCode<400&&e.status(500);const s=r instanceof Error?r:String(r);return a.formatErrorResponse(s,e.statusCode)}),h()};async function N(u,n){await u.register(E,n)}function V(u){const n=require("fastify")({logger:!0});return n.register(E,u),n}exports.createCubeApp=V;exports.cubePlugin=E;exports.registerCubeRoutes=N;
|
|
@@ -4,6 +4,7 @@ import { SemanticQuery, SecurityContext, DatabaseExecutor, DrizzleDatabase, Cube
|
|
|
4
4
|
import { PostgresJsDatabase } from 'drizzle-orm/postgres-js';
|
|
5
5
|
import { MySql2Database } from 'drizzle-orm/mysql2';
|
|
6
6
|
import { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';
|
|
7
|
+
import { MCPOptions } from '../utils';
|
|
7
8
|
export interface FastifyAdapterOptions {
|
|
8
9
|
/**
|
|
9
10
|
* Array of cube definitions to register
|
|
@@ -47,7 +48,7 @@ export interface FastifyAdapterOptions {
|
|
|
47
48
|
/**
|
|
48
49
|
* Database engine type (optional - auto-detected if not provided)
|
|
49
50
|
*/
|
|
50
|
-
engineType?: 'postgres' | 'mysql' | 'sqlite';
|
|
51
|
+
engineType?: 'postgres' | 'mysql' | 'sqlite' | 'singlestore' | 'duckdb';
|
|
51
52
|
/**
|
|
52
53
|
* CORS configuration (optional)
|
|
53
54
|
*/
|
|
@@ -65,6 +66,12 @@ export interface FastifyAdapterOptions {
|
|
|
65
66
|
* When provided, query results will be cached using the specified provider
|
|
66
67
|
*/
|
|
67
68
|
cache?: CacheConfig;
|
|
69
|
+
/**
|
|
70
|
+
* MCP (AI-Ready) endpoint configuration
|
|
71
|
+
* Enables AI agents to discover and query your data
|
|
72
|
+
* @default { enabled: true }
|
|
73
|
+
*/
|
|
74
|
+
mcp?: MCPOptions;
|
|
68
75
|
}
|
|
69
76
|
/**
|
|
70
77
|
* Fastify plugin for Cube.js-compatible API
|