drizzle-cube 0.3.15 → 0.3.17
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 +7 -1
- package/dist/adapters/express/index.d.ts +7 -0
- package/dist/adapters/express/index.js +173 -96
- package/dist/adapters/fastify/index.cjs +7 -1
- package/dist/adapters/fastify/index.d.ts +7 -0
- package/dist/adapters/fastify/index.js +187 -96
- package/dist/adapters/hono/index.cjs +7 -1
- package/dist/adapters/hono/index.d.ts +7 -0
- package/dist/adapters/hono/index.js +261 -143
- package/dist/adapters/{compiler-DdcGVWIl.js → mcp-transport-Dew98Fh6.js} +6375 -4890
- package/dist/adapters/mcp-transport-weiPD7j5.cjs +219 -0
- package/dist/adapters/mcp-transport.d.ts +108 -0
- package/dist/adapters/nextjs/index.cjs +5 -1
- package/dist/adapters/nextjs/index.d.ts +30 -0
- package/dist/adapters/nextjs/index.js +387 -134
- package/dist/adapters/utils.d.ts +78 -1
- package/dist/client/charts.js +12 -12
- package/dist/client/chunks/{RetentionCombinedChart-CqMAkdcR.js → RetentionCombinedChart-DirfDaZH.js} +2 -2
- package/dist/client/chunks/{RetentionCombinedChart-CqMAkdcR.js.map → RetentionCombinedChart-DirfDaZH.js.map} +1 -1
- package/dist/client/chunks/{analysis-builder-D0MIKiKS.js → analysis-builder-APeCxkEH.js} +9 -9
- package/dist/client/chunks/{analysis-builder-D0MIKiKS.js.map → analysis-builder-APeCxkEH.js.map} +1 -1
- package/dist/client/chunks/{analysis-builder-shared-gS0TDC6Y.js → analysis-builder-shared-DEovRjrp.js} +6 -6
- package/dist/client/chunks/{analysis-builder-shared-gS0TDC6Y.js.map → analysis-builder-shared-DEovRjrp.js.map} +1 -1
- package/dist/client/chunks/{chart-activity-grid-B37W8fcE.js → chart-activity-grid-BnweuBvr.js} +2 -2
- package/dist/client/chunks/{chart-activity-grid-B37W8fcE.js.map → chart-activity-grid-BnweuBvr.js.map} +1 -1
- package/dist/client/chunks/{chart-area-DZcxSVB1.js → chart-area-DLmXFWWy.js} +2 -2
- package/dist/client/chunks/{chart-area-DZcxSVB1.js.map → chart-area-DLmXFWWy.js.map} +1 -1
- package/dist/client/chunks/{chart-bar-BFAdRj-E.js → chart-bar-7y0-F27Q.js} +2 -2
- package/dist/client/chunks/{chart-bar-BFAdRj-E.js.map → chart-bar-7y0-F27Q.js.map} +1 -1
- package/dist/client/chunks/{chart-bubble-eoCCbl3h.js → chart-bubble-3jYKCA2B.js} +2 -2
- package/dist/client/chunks/{chart-bubble-eoCCbl3h.js.map → chart-bubble-3jYKCA2B.js.map} +1 -1
- package/dist/client/chunks/{chart-data-table-kudRwZxJ.js → chart-data-table-rUFLqysu.js} +3 -3
- package/dist/client/chunks/{chart-data-table-kudRwZxJ.js.map → chart-data-table-rUFLqysu.js.map} +1 -1
- package/dist/client/chunks/{chart-funnel-CA0XJkfh.js → chart-funnel-C7zGBfSw.js} +2 -2
- package/dist/client/chunks/{chart-funnel-CA0XJkfh.js.map → chart-funnel-C7zGBfSw.js.map} +1 -1
- package/dist/client/chunks/{chart-heat-map-DUy9_pWM.js → chart-heat-map-B-l8hK8b.js} +2 -2
- package/dist/client/chunks/{chart-heat-map-DUy9_pWM.js.map → chart-heat-map-B-l8hK8b.js.map} +1 -1
- package/dist/client/chunks/{chart-kpi-delta-MIGGCpkG.js → chart-kpi-delta-sfZEvQZm.js} +3 -3
- package/dist/client/chunks/{chart-kpi-delta-MIGGCpkG.js.map → chart-kpi-delta-sfZEvQZm.js.map} +1 -1
- package/dist/client/chunks/{chart-kpi-number-DM0Brd91.js → chart-kpi-number-BxGNOtzI.js} +2 -2
- package/dist/client/chunks/{chart-kpi-number-DM0Brd91.js.map → chart-kpi-number-BxGNOtzI.js.map} +1 -1
- package/dist/client/chunks/{chart-kpi-text-BAb28V4X.js → chart-kpi-text-BLQ_CWQP.js} +3 -3
- package/dist/client/chunks/{chart-kpi-text-BAb28V4X.js.map → chart-kpi-text-BLQ_CWQP.js.map} +1 -1
- package/dist/client/chunks/{chart-line-e3h8sa1R.js → chart-line-FSEpBk6Y.js} +2 -2
- package/dist/client/chunks/{chart-line-e3h8sa1R.js.map → chart-line-FSEpBk6Y.js.map} +1 -1
- package/dist/client/chunks/{chart-pie-CFoHYqDB.js → chart-pie-BRQEH9e-.js} +2 -2
- package/dist/client/chunks/{chart-pie-CFoHYqDB.js.map → chart-pie-BRQEH9e-.js.map} +1 -1
- package/dist/client/chunks/{chart-radar-CPPwkfxj.js → chart-radar-DgsFyiIP.js} +2 -2
- package/dist/client/chunks/{chart-radar-CPPwkfxj.js.map → chart-radar-DgsFyiIP.js.map} +1 -1
- package/dist/client/chunks/{chart-radial-bar-BdEOM-P1.js → chart-radial-bar-CUMoXyl9.js} +2 -2
- package/dist/client/chunks/{chart-radial-bar-BdEOM-P1.js.map → chart-radial-bar-CUMoXyl9.js.map} +1 -1
- package/dist/client/chunks/{chart-sankey-Bbady-8g.js → chart-sankey-IAKDEe7A.js} +2 -2
- package/dist/client/chunks/{chart-sankey-Bbady-8g.js.map → chart-sankey-IAKDEe7A.js.map} +1 -1
- package/dist/client/chunks/{chart-scatter-JFu0Pv3a.js → chart-scatter-D6XwOD2W.js} +2 -2
- package/dist/client/chunks/{chart-scatter-JFu0Pv3a.js.map → chart-scatter-D6XwOD2W.js.map} +1 -1
- package/dist/client/chunks/{chart-sunburst-sayxze15.js → chart-sunburst-CP_pnj0S.js} +2 -2
- package/dist/client/chunks/{chart-sunburst-sayxze15.js.map → chart-sunburst-CP_pnj0S.js.map} +1 -1
- package/dist/client/chunks/{chart-tree-map-Ks2xev8b.js → chart-tree-map-DQMsn47a.js} +2 -2
- package/dist/client/chunks/{chart-tree-map-Ks2xev8b.js.map → chart-tree-map-DQMsn47a.js.map} +1 -1
- package/dist/client/chunks/{charts-_yZ9gBJU.js → charts-Dk_9XrA7.js} +12 -12
- package/dist/client/chunks/{charts-_yZ9gBJU.js.map → charts-Dk_9XrA7.js.map} +1 -1
- package/dist/client/chunks/{charts-core-Bzu9PzMd.js → charts-core-CjQZBxmv.js} +2 -2
- package/dist/client/chunks/{charts-core-Bzu9PzMd.js.map → charts-core-CjQZBxmv.js.map} +1 -1
- package/dist/client/chunks/{charts-loader-cMtx4zHx.js → charts-loader-ChTUa_-G.js} +20 -20
- package/dist/client/chunks/{charts-loader-cMtx4zHx.js.map → charts-loader-ChTUa_-G.js.map} +1 -1
- package/dist/client/chunks/{components-DQuPThfA.js → components-BKZ7EAg0.js} +9 -9
- package/dist/client/chunks/{components-DQuPThfA.js.map → components-BKZ7EAg0.js.map} +1 -1
- package/dist/client/chunks/{core-DwOXVb87.js → core-BRC075EG.js} +2 -2
- package/dist/client/chunks/{core-DwOXVb87.js.map → core-BRC075EG.js.map} +1 -1
- package/dist/client/chunks/{hooks-DPRv1Xhb.js → hooks-D7APQ8uS.js} +4 -4
- package/dist/client/chunks/{hooks-DPRv1Xhb.js.map → hooks-D7APQ8uS.js.map} +1 -1
- package/dist/client/chunks/{providers-BW8D7Wso.js → providers-Cj7PQfXn.js} +2 -2
- package/dist/client/chunks/{providers-BW8D7Wso.js.map → providers-Cj7PQfXn.js.map} +1 -1
- package/dist/client/chunks/{useDirtyStateTracking-Yu_qQXb-.js → useDirtyStateTracking-ZSi3voVl.js} +3 -3
- package/dist/client/chunks/{useDirtyStateTracking-Yu_qQXb-.js.map → useDirtyStateTracking-ZSi3voVl.js.map} +1 -1
- package/dist/client/chunks/{vendor-BSkQZgtm.js → vendor-cTQhZ_G3.js} +2 -2
- package/dist/client/chunks/vendor-cTQhZ_G3.js.map +1 -0
- package/dist/client/components.js +2 -2
- package/dist/client/hooks.js +3 -3
- package/dist/client/index.js +9 -9
- package/dist/client/providers.js +1 -1
- package/dist/client-bundle-stats.html +1 -1
- package/dist/server/index.cjs +83 -83
- package/dist/server/index.d.ts +210 -0
- package/dist/server/index.js +5891 -4896
- package/package.json +1 -1
- package/dist/adapters/compiler-mAJDpIQx.cjs +0 -214
- package/dist/client/chunks/vendor-BSkQZgtm.js.map +0 -1
|
@@ -1 +1,7 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const R=require("express"),M=require("cors"),r=require("../mcp-transport-weiPD7j5.cjs");function S(f){const{cubes:m,drizzle:E,schema:$,extractSecurityContext:d,engineType:I,cors:g,basePath:p="/cubejs-api/v1",jsonLimit:x="10mb",cache:P,mcp:h={enabled:!0}}=f;if(!m||m.length===0)throw new Error("At least one cube must be provided in the cubes array");const u=R.Router();g&&u.use(M(g)),u.use(R.json({limit:x})),u.use(R.urlencoded({extended:!0,limit:x}));const c=new r.SemanticLayerCompiler({drizzle:E,schema:$,engineType:I,cache:P});if(m.forEach(o=>{c.registerCube(o)}),u.post(`${p}/load`,async(o,t)=>{try{const e=o.body.query||o.body,s=await d(o,t),n=c.validateQuery(e);if(!n.isValid)return t.status(400).json(r.formatErrorResponse(`Query validation failed: ${n.errors.join(", ")}`,400));const a=o.headers["x-cache-control"]==="no-cache",i=await c.executeMultiCubeQuery(e,s,{skipCache:a});t.json(r.formatCubeResponse(e,i,c))}catch(e){console.error("Query execution error:",e),t.status(500).json(r.formatErrorResponse(e instanceof Error?e.message:"Query execution failed",500))}}),u.get(`${p}/load`,async(o,t)=>{try{const e=o.query.query;if(!e)return t.status(400).json(r.formatErrorResponse("Query parameter is required",400));let s;try{s=JSON.parse(e)}catch{return t.status(400).json(r.formatErrorResponse("Invalid JSON in query parameter",400))}const n=await d(o,t),a=c.validateQuery(s);if(!a.isValid)return t.status(400).json(r.formatErrorResponse(`Query validation failed: ${a.errors.join(", ")}`,400));const i=o.headers["x-cache-control"]==="no-cache",y=await c.executeMultiCubeQuery(s,n,{skipCache:i});t.json(r.formatCubeResponse(s,y,c))}catch(e){console.error("Query execution error:",e),t.status(500).json(r.formatErrorResponse(e instanceof Error?e.message:"Query execution failed",500))}}),u.post(`${p}/batch`,async(o,t)=>{try{const{queries:e}=o.body;if(!e||!Array.isArray(e))return t.status(400).json(r.formatErrorResponse('Request body must contain a "queries" array',400));if(e.length===0)return t.status(400).json(r.formatErrorResponse("Queries array cannot be empty",400));const s=await d(o,t),n=o.headers["x-cache-control"]==="no-cache",a=await r.handleBatchRequest(e,s,c,{skipCache:n});t.json(a)}catch(e){console.error("Batch execution error:",e),t.status(500).json(r.formatErrorResponse(e instanceof Error?e.message:"Batch execution failed",500))}}),u.get(`${p}/meta`,(o,t)=>{try{const e=c.getMetadata();t.json(r.formatMetaResponse(e))}catch(e){console.error("Metadata error:",e),t.status(500).json(r.formatErrorResponse(e instanceof Error?e.message:"Failed to fetch metadata",500))}}),u.post(`${p}/sql`,async(o,t)=>{try{const e=o.body,s=await d(o,t),n=c.validateQuery(e);if(!n.isValid)return t.status(400).json(r.formatErrorResponse(`Query validation failed: ${n.errors.join(", ")}`,400));const a=e.measures?.[0]||e.dimensions?.[0];if(!a)return t.status(400).json(r.formatErrorResponse("No measures or dimensions specified",400));const i=a.split(".")[0],y=await c.generateSQL(i,e,s);t.json(r.formatSqlResponse(e,y))}catch(e){console.error("SQL generation error:",e),t.status(500).json(r.formatErrorResponse(e instanceof Error?e.message:"SQL generation failed",500))}}),u.get(`${p}/sql`,async(o,t)=>{try{const e=o.query.query;if(!e)return t.status(400).json(r.formatErrorResponse("Query parameter is required",400));const s=JSON.parse(e),n=await d(o,t),a=c.validateQuery(s);if(!a.isValid)return t.status(400).json(r.formatErrorResponse(`Query validation failed: ${a.errors.join(", ")}`,400));const i=s.measures?.[0]||s.dimensions?.[0];if(!i)return t.status(400).json(r.formatErrorResponse("No measures or dimensions specified",400));const y=i.split(".")[0],C=await c.generateSQL(y,s,n);t.json(r.formatSqlResponse(s,C))}catch(e){console.error("SQL generation error:",e),t.status(500).json(r.formatErrorResponse(e instanceof Error?e.message:"SQL generation failed",500))}}),u.post(`${p}/dry-run`,async(o,t)=>{try{const e=o.body.query||o.body,s=await d(o,t),n=await r.handleDryRun(e,s,c);t.json(n)}catch(e){console.error("Dry-run error:",e),t.status(400).json({error:e instanceof Error?e.message:"Dry-run validation failed",valid:!1})}}),u.get(`${p}/dry-run`,async(o,t)=>{try{const e=o.query.query;if(!e)return t.status(400).json({error:"Query parameter is required",valid:!1});const s=JSON.parse(e),n=await d(o,t),a=await r.handleDryRun(s,n,c);t.json(a)}catch(e){console.error("Dry-run error:",e),t.status(400).json({error:e instanceof Error?e.message:"Dry-run validation failed",valid:!1})}}),u.post(`${p}/explain`,async(o,t)=>{try{const e=o.body.query||o.body,s=o.body.options||{},n=await d(o,t),a=c.validateQuery(e);if(!a.isValid)return t.status(400).json({error:`Query validation failed: ${a.errors.join(", ")}`});const i=await c.explainQuery(e,n,s);t.json(i)}catch(e){console.error("Explain error:",e),t.status(500).json({error:e instanceof Error?e.message:"Explain query failed"})}}),h.enabled!==!1){const o=h.basePath??"/mcp";u.post(`${o}`,async(t,e)=>{const s=r.validateOriginHeader(t.headers.origin,h.allowedOrigins?{allowedOrigins:h.allowedOrigins}:{});if(!s.valid)return e.status(403).json(r.buildJsonRpcError(null,-32600,s.reason));const n=t.headers.accept;if(!r.validateAcceptHeader(n))return e.status(400).json(r.buildJsonRpcError(null,-32600,"Accept header must include both application/json and text/event-stream"));const a=r.negotiateProtocol(t.headers);if(!a.ok)return e.status(426).json({error:"Unsupported MCP protocol version",supported:a.supported});const i=r.parseJsonRpc(t.body);if(!i)return e.status(400).json(r.buildJsonRpcError(null,-32600,"Invalid JSON-RPC 2.0 request"));const y=r.wantsEventStream(n),C=i.method==="initialize";try{const l=await r.dispatchMcpMethod(i.method,i.params,{semanticLayer:c,extractSecurityContext:d,rawRequest:t,rawResponse:e,negotiatedProtocol:a.negotiated});if(r.isNotification(i))return e.status(202).end();const j=C&&l&&typeof l=="object"&&"sessionId"in l?l.sessionId:void 0;j&&e.setHeader(r.MCP_SESSION_ID_HEADER,j);const v=r.buildJsonRpcResult(i.id??null,l);if(y){const b=r.primeEventId();return e.status(200),e.setHeader("Content-Type","text/event-stream"),e.setHeader("Cache-Control","no-cache"),e.setHeader("Connection","keep-alive"),e.write(`id: ${b}
|
|
2
|
+
|
|
3
|
+
`),e.write(r.serializeSseEvent(v,b)),e.end()}return e.json(v)}catch(l){if(r.isNotification(i))return console.error("MCP notification processing error:",l),e.status(202).end();console.error("MCP RPC error:",l);const j=l?.code??-32603,v=l?.data,b=l.message||"MCP request failed",w=r.buildJsonRpcError(i.id??null,j,b,v);if(y){const Q=r.primeEventId();return e.status(200),e.setHeader("Content-Type","text/event-stream"),e.setHeader("Cache-Control","no-cache"),e.setHeader("Connection","keep-alive"),e.write(`id: ${Q}
|
|
4
|
+
|
|
5
|
+
`),e.write(r.serializeSseEvent(w,Q)),e.end()}return e.status(200).json(w)}}),u.get(`${o}`,async(t,e)=>{const s=r.primeEventId();e.status(200),e.setHeader("Content-Type","text/event-stream"),e.setHeader("Cache-Control","no-cache"),e.setHeader("Connection","keep-alive"),e.write(r.serializeSseEvent({jsonrpc:"2.0",method:"mcp/ready",params:{protocol:"streamable-http"}},s,15e3));const n=setInterval(()=>{e.write(`: keep-alive
|
|
6
|
+
|
|
7
|
+
`)},15e3);t.on("close",()=>{clearInterval(n)})}),u.delete(`${o}`,(t,e)=>e.status(405).json({error:"Session termination not supported"}))}return u.use((o,t,e,s)=>{console.error("Express adapter error:",o),e.headersSent||e.status(500).json(r.formatErrorResponse(o,500))}),u}function q(f,m){const E=S(m);return f.use("/",E),f}function H(f){const m=R();return q(m,f)}exports.createCubeApp=H;exports.createCubeRouter=S;exports.mountCubeRoutes=q;
|
|
@@ -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
|
|
@@ -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,51 +1,52 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import { S,
|
|
4
|
-
function
|
|
1
|
+
import R, { Router as L } from "express";
|
|
2
|
+
import A from "cors";
|
|
3
|
+
import { S as J, o as c, f as M, h as D, a as _, b as P, c as H, v as V, d as C, e as z, n as B, p as T, w as F, g as U, k as I, M as G, l as K, m as w, s as Q } from "../mcp-transport-Dew98Fh6.js";
|
|
4
|
+
function W(f) {
|
|
5
5
|
const {
|
|
6
|
-
cubes:
|
|
7
|
-
drizzle:
|
|
8
|
-
schema:
|
|
6
|
+
cubes: m,
|
|
7
|
+
drizzle: g,
|
|
8
|
+
schema: N,
|
|
9
9
|
extractSecurityContext: l,
|
|
10
|
-
engineType:
|
|
11
|
-
cors:
|
|
10
|
+
engineType: k,
|
|
11
|
+
cors: E,
|
|
12
12
|
basePath: y = "/cubejs-api/v1",
|
|
13
|
-
jsonLimit:
|
|
14
|
-
cache:
|
|
13
|
+
jsonLimit: S = "10mb",
|
|
14
|
+
cache: O,
|
|
15
|
+
mcp: h = { enabled: !0 }
|
|
15
16
|
} = f;
|
|
16
|
-
if (!
|
|
17
|
+
if (!m || m.length === 0)
|
|
17
18
|
throw new Error("At least one cube must be provided in the cubes array");
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
drizzle:
|
|
22
|
-
schema:
|
|
23
|
-
engineType:
|
|
24
|
-
cache:
|
|
19
|
+
const u = L();
|
|
20
|
+
E && u.use(A(E)), u.use(R.json({ limit: S })), u.use(R.urlencoded({ extended: !0, limit: S }));
|
|
21
|
+
const i = new J({
|
|
22
|
+
drizzle: g,
|
|
23
|
+
schema: N,
|
|
24
|
+
engineType: k,
|
|
25
|
+
cache: O
|
|
25
26
|
});
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}),
|
|
27
|
+
if (m.forEach((r) => {
|
|
28
|
+
i.registerCube(r);
|
|
29
|
+
}), u.post(`${y}/load`, async (r, t) => {
|
|
29
30
|
try {
|
|
30
|
-
const e = r.body.query || r.body, o = await l(r, t),
|
|
31
|
-
if (!
|
|
32
|
-
return t.status(400).json(
|
|
33
|
-
`Query validation failed: ${
|
|
31
|
+
const e = r.body.query || r.body, o = await l(r, t), a = i.validateQuery(e);
|
|
32
|
+
if (!a.isValid)
|
|
33
|
+
return t.status(400).json(c(
|
|
34
|
+
`Query validation failed: ${a.errors.join(", ")}`,
|
|
34
35
|
400
|
|
35
36
|
));
|
|
36
|
-
const
|
|
37
|
-
t.json(
|
|
37
|
+
const s = r.headers["x-cache-control"] === "no-cache", n = await i.executeMultiCubeQuery(e, o, { skipCache: s });
|
|
38
|
+
t.json(M(e, n, 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(c(
|
|
40
41
|
e instanceof Error ? e.message : "Query execution failed",
|
|
41
42
|
500
|
|
42
43
|
));
|
|
43
44
|
}
|
|
44
|
-
}),
|
|
45
|
+
}), u.get(`${y}/load`, async (r, t) => {
|
|
45
46
|
try {
|
|
46
47
|
const e = r.query.query;
|
|
47
48
|
if (!e)
|
|
48
|
-
return t.status(400).json(
|
|
49
|
+
return t.status(400).json(c(
|
|
49
50
|
"Query parameter is required",
|
|
50
51
|
400
|
|
51
52
|
));
|
|
@@ -53,117 +54,117 @@ function N(f) {
|
|
|
53
54
|
try {
|
|
54
55
|
o = JSON.parse(e);
|
|
55
56
|
} catch {
|
|
56
|
-
return t.status(400).json(
|
|
57
|
+
return t.status(400).json(c(
|
|
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 a = await l(r, t), s = i.validateQuery(o);
|
|
63
|
+
if (!s.isValid)
|
|
64
|
+
return t.status(400).json(c(
|
|
65
|
+
`Query validation failed: ${s.errors.join(", ")}`,
|
|
65
66
|
400
|
|
66
67
|
));
|
|
67
|
-
const
|
|
68
|
-
t.json(
|
|
68
|
+
const n = r.headers["x-cache-control"] === "no-cache", p = await i.executeMultiCubeQuery(o, a, { skipCache: n });
|
|
69
|
+
t.json(M(o, p, 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(c(
|
|
71
72
|
e instanceof Error ? e.message : "Query execution failed",
|
|
72
73
|
500
|
|
73
74
|
));
|
|
74
75
|
}
|
|
75
|
-
}),
|
|
76
|
+
}), u.post(`${y}/batch`, async (r, t) => {
|
|
76
77
|
try {
|
|
77
78
|
const { queries: e } = r.body;
|
|
78
79
|
if (!e || !Array.isArray(e))
|
|
79
|
-
return t.status(400).json(
|
|
80
|
+
return t.status(400).json(c(
|
|
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(c(
|
|
85
86
|
"Queries array cannot be empty",
|
|
86
87
|
400
|
|
87
88
|
));
|
|
88
|
-
const o = await l(r, t),
|
|
89
|
-
t.json(
|
|
89
|
+
const o = await l(r, t), a = r.headers["x-cache-control"] === "no-cache", s = await D(e, o, i, { skipCache: a });
|
|
90
|
+
t.json(s);
|
|
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(c(
|
|
92
93
|
e instanceof Error ? e.message : "Batch execution failed",
|
|
93
94
|
500
|
|
94
95
|
));
|
|
95
96
|
}
|
|
96
|
-
}),
|
|
97
|
+
}), u.get(`${y}/meta`, (r, t) => {
|
|
97
98
|
try {
|
|
98
|
-
const e =
|
|
99
|
-
t.json(
|
|
99
|
+
const e = i.getMetadata();
|
|
100
|
+
t.json(_(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(c(
|
|
102
103
|
e instanceof Error ? e.message : "Failed to fetch metadata",
|
|
103
104
|
500
|
|
104
105
|
));
|
|
105
106
|
}
|
|
106
|
-
}),
|
|
107
|
+
}), u.post(`${y}/sql`, async (r, t) => {
|
|
107
108
|
try {
|
|
108
|
-
const e = r.body, o = await l(r, t),
|
|
109
|
-
if (!
|
|
110
|
-
return t.status(400).json(
|
|
111
|
-
`Query validation failed: ${
|
|
109
|
+
const e = r.body, o = await l(r, t), a = i.validateQuery(e);
|
|
110
|
+
if (!a.isValid)
|
|
111
|
+
return t.status(400).json(c(
|
|
112
|
+
`Query validation failed: ${a.errors.join(", ")}`,
|
|
112
113
|
400
|
|
113
114
|
));
|
|
114
|
-
const
|
|
115
|
-
if (!
|
|
116
|
-
return t.status(400).json(
|
|
115
|
+
const s = e.measures?.[0] || e.dimensions?.[0];
|
|
116
|
+
if (!s)
|
|
117
|
+
return t.status(400).json(c(
|
|
117
118
|
"No measures or dimensions specified",
|
|
118
119
|
400
|
|
119
120
|
));
|
|
120
|
-
const
|
|
121
|
-
t.json(
|
|
121
|
+
const n = s.split(".")[0], p = await i.generateSQL(n, e, o);
|
|
122
|
+
t.json(P(e, p));
|
|
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(c(
|
|
124
125
|
e instanceof Error ? e.message : "SQL generation failed",
|
|
125
126
|
500
|
|
126
127
|
));
|
|
127
128
|
}
|
|
128
|
-
}),
|
|
129
|
+
}), u.get(`${y}/sql`, async (r, t) => {
|
|
129
130
|
try {
|
|
130
131
|
const e = r.query.query;
|
|
131
132
|
if (!e)
|
|
132
|
-
return t.status(400).json(
|
|
133
|
+
return t.status(400).json(c(
|
|
133
134
|
"Query parameter is required",
|
|
134
135
|
400
|
|
135
136
|
));
|
|
136
|
-
const o = JSON.parse(e),
|
|
137
|
-
if (!
|
|
138
|
-
return t.status(400).json(
|
|
139
|
-
`Query validation failed: ${
|
|
137
|
+
const o = JSON.parse(e), a = await l(r, t), s = i.validateQuery(o);
|
|
138
|
+
if (!s.isValid)
|
|
139
|
+
return t.status(400).json(c(
|
|
140
|
+
`Query validation failed: ${s.errors.join(", ")}`,
|
|
140
141
|
400
|
|
141
142
|
));
|
|
142
|
-
const
|
|
143
|
-
if (!
|
|
144
|
-
return t.status(400).json(
|
|
143
|
+
const n = o.measures?.[0] || o.dimensions?.[0];
|
|
144
|
+
if (!n)
|
|
145
|
+
return t.status(400).json(c(
|
|
145
146
|
"No measures or dimensions specified",
|
|
146
147
|
400
|
|
147
148
|
));
|
|
148
|
-
const
|
|
149
|
-
t.json(
|
|
149
|
+
const p = n.split(".")[0], x = await i.generateSQL(p, o, a);
|
|
150
|
+
t.json(P(o, x));
|
|
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(c(
|
|
152
153
|
e instanceof Error ? e.message : "SQL generation failed",
|
|
153
154
|
500
|
|
154
155
|
));
|
|
155
156
|
}
|
|
156
|
-
}),
|
|
157
|
+
}), u.post(`${y}/dry-run`, async (r, t) => {
|
|
157
158
|
try {
|
|
158
|
-
const e = r.body.query || r.body, o = await l(r, t),
|
|
159
|
-
t.json(
|
|
159
|
+
const e = r.body.query || r.body, o = await l(r, t), a = await H(e, o, i);
|
|
160
|
+
t.json(a);
|
|
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
|
-
}),
|
|
167
|
+
}), u.get(`${y}/dry-run`, async (r, t) => {
|
|
167
168
|
try {
|
|
168
169
|
const e = r.query.query;
|
|
169
170
|
if (!e)
|
|
@@ -171,42 +172,118 @@ function N(f) {
|
|
|
171
172
|
error: "Query parameter is required",
|
|
172
173
|
valid: !1
|
|
173
174
|
});
|
|
174
|
-
const o = JSON.parse(e),
|
|
175
|
-
t.json(
|
|
175
|
+
const o = JSON.parse(e), a = await l(r, t), s = await H(o, a, i);
|
|
176
|
+
t.json(s);
|
|
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
|
-
}),
|
|
183
|
+
}), u.post(`${y}/explain`, async (r, t) => {
|
|
183
184
|
try {
|
|
184
|
-
const e = r.body.query || r.body, o = r.body.options || {},
|
|
185
|
-
if (!
|
|
185
|
+
const e = r.body.query || r.body, o = r.body.options || {}, a = await l(r, t), s = i.validateQuery(e);
|
|
186
|
+
if (!s.isValid)
|
|
186
187
|
return t.status(400).json({
|
|
187
|
-
error: `Query validation failed: ${
|
|
188
|
+
error: `Query validation failed: ${s.errors.join(", ")}`
|
|
188
189
|
});
|
|
189
|
-
const
|
|
190
|
-
t.json(
|
|
190
|
+
const n = await i.explainQuery(e, a, o);
|
|
191
|
+
t.json(n);
|
|
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
|
-
|
|
198
|
-
|
|
197
|
+
}), h.enabled !== !1) {
|
|
198
|
+
const r = h.basePath ?? "/mcp";
|
|
199
|
+
u.post(`${r}`, async (t, e) => {
|
|
200
|
+
const o = V(
|
|
201
|
+
t.headers.origin,
|
|
202
|
+
h.allowedOrigins ? { allowedOrigins: h.allowedOrigins } : {}
|
|
203
|
+
);
|
|
204
|
+
if (!o.valid)
|
|
205
|
+
return e.status(403).json(C(null, -32600, o.reason));
|
|
206
|
+
const a = t.headers.accept;
|
|
207
|
+
if (!z(a))
|
|
208
|
+
return e.status(400).json(C(null, -32600, "Accept header must include both application/json and text/event-stream"));
|
|
209
|
+
const s = B(t.headers);
|
|
210
|
+
if (!s.ok)
|
|
211
|
+
return e.status(426).json({
|
|
212
|
+
error: "Unsupported MCP protocol version",
|
|
213
|
+
supported: s.supported
|
|
214
|
+
});
|
|
215
|
+
const n = T(t.body);
|
|
216
|
+
if (!n)
|
|
217
|
+
return e.status(400).json(C(null, -32600, "Invalid JSON-RPC 2.0 request"));
|
|
218
|
+
const p = F(a), x = n.method === "initialize";
|
|
219
|
+
try {
|
|
220
|
+
const d = await U(
|
|
221
|
+
n.method,
|
|
222
|
+
n.params,
|
|
223
|
+
{
|
|
224
|
+
semanticLayer: i,
|
|
225
|
+
extractSecurityContext: l,
|
|
226
|
+
rawRequest: t,
|
|
227
|
+
rawResponse: e,
|
|
228
|
+
negotiatedProtocol: s.negotiated
|
|
229
|
+
}
|
|
230
|
+
);
|
|
231
|
+
if (I(n))
|
|
232
|
+
return e.status(202).end();
|
|
233
|
+
const j = x && d && typeof d == "object" && "sessionId" in d ? d.sessionId : void 0;
|
|
234
|
+
j && e.setHeader(G, j);
|
|
235
|
+
const v = K(n.id ?? null, d);
|
|
236
|
+
if (p) {
|
|
237
|
+
const b = w();
|
|
238
|
+
return e.status(200), e.setHeader("Content-Type", "text/event-stream"), e.setHeader("Cache-Control", "no-cache"), e.setHeader("Connection", "keep-alive"), e.write(`id: ${b}
|
|
239
|
+
|
|
240
|
+
`), e.write(Q(v, b)), e.end();
|
|
241
|
+
}
|
|
242
|
+
return e.json(v);
|
|
243
|
+
} catch (d) {
|
|
244
|
+
if (I(n))
|
|
245
|
+
return console.error("MCP notification processing error:", d), e.status(202).end();
|
|
246
|
+
console.error("MCP RPC error:", d);
|
|
247
|
+
const j = d?.code ?? -32603, v = d?.data, b = d.message || "MCP request failed", q = C(n.id ?? null, j, b, v);
|
|
248
|
+
if (p) {
|
|
249
|
+
const $ = w();
|
|
250
|
+
return e.status(200), e.setHeader("Content-Type", "text/event-stream"), e.setHeader("Cache-Control", "no-cache"), e.setHeader("Connection", "keep-alive"), e.write(`id: ${$}
|
|
251
|
+
|
|
252
|
+
`), e.write(Q(q, $)), e.end();
|
|
253
|
+
}
|
|
254
|
+
return e.status(200).json(q);
|
|
255
|
+
}
|
|
256
|
+
}), u.get(`${r}`, async (t, e) => {
|
|
257
|
+
const o = w();
|
|
258
|
+
e.status(200), e.setHeader("Content-Type", "text/event-stream"), e.setHeader("Cache-Control", "no-cache"), e.setHeader("Connection", "keep-alive"), e.write(Q({
|
|
259
|
+
jsonrpc: "2.0",
|
|
260
|
+
method: "mcp/ready",
|
|
261
|
+
params: { protocol: "streamable-http" }
|
|
262
|
+
}, o, 15e3));
|
|
263
|
+
const a = setInterval(() => {
|
|
264
|
+
e.write(`: keep-alive
|
|
265
|
+
|
|
266
|
+
`);
|
|
267
|
+
}, 15e3);
|
|
268
|
+
t.on("close", () => {
|
|
269
|
+
clearInterval(a);
|
|
270
|
+
});
|
|
271
|
+
}), u.delete(`${r}`, (t, e) => e.status(405).json({ error: "Session termination not supported" }));
|
|
272
|
+
}
|
|
273
|
+
return u.use((r, t, e, o) => {
|
|
274
|
+
console.error("Express adapter error:", r), e.headersSent || e.status(500).json(c(r, 500));
|
|
275
|
+
}), u;
|
|
199
276
|
}
|
|
200
|
-
function
|
|
201
|
-
const
|
|
202
|
-
return f.use("/",
|
|
277
|
+
function X(f, m) {
|
|
278
|
+
const g = W(m);
|
|
279
|
+
return f.use("/", g), f;
|
|
203
280
|
}
|
|
204
|
-
function
|
|
205
|
-
const
|
|
206
|
-
return
|
|
281
|
+
function te(f) {
|
|
282
|
+
const m = R();
|
|
283
|
+
return X(m, f);
|
|
207
284
|
}
|
|
208
285
|
export {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
286
|
+
te as createCubeApp,
|
|
287
|
+
W as createCubeRouter,
|
|
288
|
+
X as mountCubeRoutes
|
|
212
289
|
};
|
|
@@ -1 +1,7 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var N=Object.create;var Q=Object.defineProperty;var O=Object.getOwnPropertyDescriptor;var J=Object.getOwnPropertyNames;var k=Object.getPrototypeOf,A=Object.prototype.hasOwnProperty;var L=(d,n,g,f)=>{if(n&&typeof n=="object"||typeof n=="function")for(let y of J(n))!A.call(d,y)&&y!==g&&Q(d,y,{get:()=>n[y],enumerable:!(f=O(n,y))||f.enumerable});return d};var D=(d,n,g)=>(g=d!=null?N(k(d)):{},L(n||!d||!d.__esModule?Q(g,"default",{value:d,enumerable:!0}):g,d));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("../mcp-transport-weiPD7j5.cjs"),x=function(n,g,f){const{cubes:y,drizzle:$,schema:j,extractSecurityContext:m,engineType:I,cors:q,basePath:h="/cubejs-api/v1",bodyLimit:b=10485760,cache:M,mcp:v={enabled:!0}}=g;if(!y||y.length===0)return f(new Error("At least one cube must be provided in the cubes array"));q&&n.register(import("@fastify/cors"),q),n.addHook("onRequest",async(r,o)=>{r.method==="POST"&&(r.body=void 0)});const u=new t.SemanticLayerCompiler({drizzle:$,schema:j,engineType:I,cache:M});if(y.forEach(r=>{u.registerCube(r)}),n.post(`${h}/load`,{bodyLimit:b,schema:{body:{type:"object",additionalProperties:!0}}},async(r,o)=>{try{const e=r.body,s=e.query||e,a=await m(r),i=u.validateQuery(s);if(!i.isValid)return o.status(400).send(t.formatErrorResponse(`Query validation failed: ${i.errors.join(", ")}`,400));const c=r.headers["x-cache-control"]==="no-cache",l=await u.executeMultiCubeQuery(s,a,{skipCache:c});return t.formatCubeResponse(s,l,u)}catch(e){return r.log.error(e,"Query execution error"),o.status(500).send(t.formatErrorResponse(e instanceof Error?e.message:"Query execution failed",500))}}),n.get(`${h}/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(t.formatErrorResponse("Invalid JSON in query parameter",400))}const a=await m(r),i=u.validateQuery(s);if(!i.isValid)return o.status(400).send(t.formatErrorResponse(`Query validation failed: ${i.errors.join(", ")}`,400));const c=r.headers["x-cache-control"]==="no-cache",l=await u.executeMultiCubeQuery(s,a,{skipCache:c});return t.formatCubeResponse(s,l,u)}catch(e){return r.log.error(e,"Query execution error"),o.status(500).send(t.formatErrorResponse(e instanceof Error?e.message:"Query execution failed",500))}}),n.post(`${h}/batch`,{bodyLimit:b,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(t.formatErrorResponse('Request body must contain a "queries" array',400));if(e.length===0)return o.status(400).send(t.formatErrorResponse("Queries array cannot be empty",400));const s=await m(r),a=r.headers["x-cache-control"]==="no-cache";return await t.handleBatchRequest(e,s,u,{skipCache:a})}catch(e){return r.log.error(e,"Batch execution error"),o.status(500).send(t.formatErrorResponse(e instanceof Error?e.message:"Batch execution failed",500))}}),n.get(`${h}/meta`,async(r,o)=>{try{const e=u.getMetadata();return t.formatMetaResponse(e)}catch(e){return r.log.error(e,"Metadata error"),o.status(500).send(t.formatErrorResponse(e instanceof Error?e.message:"Failed to fetch metadata",500))}}),n.post(`${h}/sql`,{bodyLimit:b,schema:{body:{type:"object",additionalProperties:!0}}},async(r,o)=>{try{const e=r.body,s=await m(r),a=u.validateQuery(e);if(!a.isValid)return o.status(400).send(t.formatErrorResponse(`Query validation failed: ${a.errors.join(", ")}`,400));const i=e.measures?.[0]||e.dimensions?.[0];if(!i)return o.status(400).send(t.formatErrorResponse("No measures or dimensions specified",400));const c=i.split(".")[0],l=await u.generateSQL(c,e,s);return t.formatSqlResponse(e,l)}catch(e){return r.log.error(e,"SQL generation error"),o.status(500).send(t.formatErrorResponse(e instanceof Error?e.message:"SQL generation failed",500))}}),n.get(`${h}/sql`,{schema:{querystring:{type:"object",properties:{query:{type:"string"}},required:["query"]}}},async(r,o)=>{try{const{query:e}=r.query,s=JSON.parse(e),a=await m(r),i=u.validateQuery(s);if(!i.isValid)return o.status(400).send(t.formatErrorResponse(`Query validation failed: ${i.errors.join(", ")}`,400));const c=s.measures?.[0]||s.dimensions?.[0];if(!c)return o.status(400).send(t.formatErrorResponse("No measures or dimensions specified",400));const l=c.split(".")[0],w=await u.generateSQL(l,s,a);return t.formatSqlResponse(s,w)}catch(e){return r.log.error(e,"SQL generation error"),o.status(500).send(t.formatErrorResponse(e instanceof Error?e.message:"SQL generation failed",500))}}),n.post(`${h}/dry-run`,{bodyLimit:b,schema:{body:{type:"object",additionalProperties:!0}}},async(r,o)=>{try{const e=r.body,s=e.query||e,a=await m(r);return await t.handleDryRun(s,a,u)}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(`${h}/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),a=await m(r);return await t.handleDryRun(s,a,u)}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(`${h}/explain`,{bodyLimit:b,schema:{body:{type:"object",additionalProperties:!0}}},async(r,o)=>{try{const e=r.body,s=e.query||e,a=e.options||{},i=await m(r),c=u.validateQuery(s);return c.isValid?await u.explainQuery(s,i,a):o.status(400).send({error:`Query validation failed: ${c.errors.join(", ")}`})}catch(e){return r.log.error(e,"Explain error"),o.status(500).send({error:e instanceof Error?e.message:"Explain query failed"})}}),v.enabled!==!1){const r=v.basePath??"/mcp";n.post(`${r}`,{bodyLimit:b,schema:{body:{type:"object",additionalProperties:!0}}},async(o,e)=>{const s=t.validateOriginHeader(o.headers.origin,v.allowedOrigins?{allowedOrigins:v.allowedOrigins}:{});if(!s.valid)return e.status(403).send(t.buildJsonRpcError(null,-32600,s.reason));const a=o.headers.accept;if(!t.validateAcceptHeader(a))return e.status(400).send(t.buildJsonRpcError(null,-32600,"Accept header must include both application/json and text/event-stream"));const i=t.negotiateProtocol(o.headers);if(!i.ok)return e.status(426).send({error:"Unsupported MCP protocol version",supported:i.supported});const c=t.parseJsonRpc(o.body);if(!c)return e.status(400).send(t.buildJsonRpcError(null,-32600,"Invalid JSON-RPC 2.0 request"));const l=t.wantsEventStream(a),w=c.method==="initialize";try{const p=await t.dispatchMcpMethod(c.method,c.params,{semanticLayer:u,extractSecurityContext:m,rawRequest:o,rawResponse:e,negotiatedProtocol:i.negotiated});if(t.isNotification(c))return e.status(202).send();const R=w&&p&&typeof p=="object"&&"sessionId"in p?p.sessionId:void 0;R&&e.header(t.MCP_SESSION_ID_HEADER,R);const E=t.buildJsonRpcResult(c.id??null,p);if(l){const C=t.primeEventId();e.header("Content-Type","text/event-stream").header("Cache-Control","no-cache").header("Connection","keep-alive").send(`id: ${C}
|
|
2
|
+
|
|
3
|
+
${t.serializeSseEvent(E,C)}`);return}return e.send(E)}catch(p){if(t.isNotification(c))return o.log.error(p,"MCP notification processing error"),e.status(202).send();o.log.error(p,"MCP RPC error");const R=p?.code??-32603,E=p?.data,C=p.message||"MCP request failed",S=t.buildJsonRpcError(c.id??null,R,C,E);if(l){const P=t.primeEventId();e.header("Content-Type","text/event-stream").header("Cache-Control","no-cache").header("Connection","keep-alive").send(`id: ${P}
|
|
4
|
+
|
|
5
|
+
${t.serializeSseEvent(S,P)}`);return}return e.send(S)}}),n.get(`${r}`,async(o,e)=>{const s=t.primeEventId();e.raw.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"}),e.raw.write(t.serializeSseEvent({jsonrpc:"2.0",method:"mcp/ready",params:{protocol:"streamable-http"}},s,15e3));const a=setInterval(()=>{e.raw.write(`: keep-alive
|
|
6
|
+
|
|
7
|
+
`)},15e3);o.raw.on("close",()=>{clearInterval(a)})}),n.delete(`${r}`,async(o,e)=>e.status(405).send({error:"Session termination not supported"}))}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 t.formatErrorResponse(s,e.statusCode)}),f()};async function z(d,n){await d.register(x,n)}function H(d){const n=require("fastify")({logger:!0});return n.register(x,d),n}exports.createCubeApp=H;exports.cubePlugin=x;exports.registerCubeRoutes=z;
|
|
@@ -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
|
|
@@ -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
|