drizzle-cube 0.3.17 → 0.3.18
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.js +1 -1
- package/dist/adapters/fastify/index.cjs +1 -1
- package/dist/adapters/fastify/index.js +1 -1
- package/dist/adapters/hono/index.cjs +1 -1
- package/dist/adapters/hono/index.js +1 -1
- package/dist/adapters/{mcp-transport-Dew98Fh6.js → mcp-transport-COtZVd4-.js} +2 -1
- package/dist/adapters/{mcp-transport-weiPD7j5.cjs → mcp-transport-xS_s8WBZ.cjs} +1 -1
- package/dist/adapters/nextjs/index.cjs +1 -1
- package/dist/adapters/nextjs/index.js +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const R=require("express"),M=require("cors"),r=require("../mcp-transport-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const R=require("express"),M=require("cors"),r=require("../mcp-transport-xS_s8WBZ.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
2
|
|
|
3
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
4
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import R, { Router as L } from "express";
|
|
2
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-
|
|
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-COtZVd4-.js";
|
|
4
4
|
function W(f) {
|
|
5
5
|
const {
|
|
6
6
|
cubes: m,
|
|
@@ -1,4 +1,4 @@
|
|
|
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-
|
|
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-xS_s8WBZ.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
2
|
|
|
3
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
4
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { S as D, o as u, f as $, h as H, a as V, b as j, c as M, v as z, d as C, e as T, n as _, p as B, w as F, g as U, k as I, M as G, l as K, m as q, s as R } from "../mcp-transport-
|
|
1
|
+
import { S as D, o as u, f as $, h as H, a as V, b as j, c as M, v as z, d as C, e as T, n as _, p as B, w as F, g as U, k as I, M as G, l as K, m as q, s as R } from "../mcp-transport-COtZVd4-.js";
|
|
2
2
|
const k = function(n, N, E) {
|
|
3
3
|
const {
|
|
4
4
|
cubes: w,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const $=require("hono"),n=require("../mcp-transport-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const $=require("hono"),n=require("../mcp-transport-xS_s8WBZ.cjs");var O=C=>{const d={...{origin:"*",allowMethods:["GET","HEAD","PUT","POST","DELETE","PATCH"],allowHeaders:[],exposeHeaders:[]},...C},Q=(l=>typeof l=="string"?l==="*"?()=>l:a=>l===a?a:null:typeof l=="function"?l:a=>l.includes(a)?a:null)(d.origin),y=(l=>typeof l=="function"?l:Array.isArray(l)?()=>l:()=>[])(d.allowMethods);return async function(a,f){function q(u,s){a.res.headers.set(u,s)}const w=await Q(a.req.header("origin")||"",a);if(w&&q("Access-Control-Allow-Origin",w),d.credentials&&q("Access-Control-Allow-Credentials","true"),d.exposeHeaders?.length&&q("Access-Control-Expose-Headers",d.exposeHeaders.join(",")),a.req.method==="OPTIONS"){d.origin!=="*"&&q("Vary","Origin"),d.maxAge!=null&&q("Access-Control-Max-Age",d.maxAge.toString());const u=await y(a.req.header("origin")||"",a);u.length&&q("Access-Control-Allow-Methods",u.join(","));let s=d.allowHeaders;if(!s?.length){const r=a.req.header("Access-Control-Request-Headers");r&&(s=r.split(/\s*,\s*/))}return s?.length&&(q("Access-Control-Allow-Headers",s.join(",")),a.res.headers.append("Vary","Access-Control-Request-Headers")),a.res.headers.delete("Content-Length"),a.res.headers.delete("Content-Type"),new Response(null,{headers:a.res.headers,status:204,statusText:"No Content"})}await f(),d.origin!=="*"&&a.header("Vary","Origin",{append:!0})}};function T(C){const{cubes:j,drizzle:d,schema:Q,extractSecurityContext:y,engineType:l,cors:a,basePath:f="/cubejs-api/v1",cache:q,mcp:w={enabled:!0}}=C;if(!j||j.length===0)throw new Error("At least one cube must be provided in the cubes array");const u=new $.Hono;a&&u.use("/*",O(a));const s=new n.SemanticLayerCompiler({drizzle:d,schema:Q,engineType:l,cache:q});if(j.forEach(r=>{s.registerCube(r)}),u.post(`${f}/load`,async r=>{try{const e=await r.req.json(),o=e.query||e,i=await y(r),t=s.validateQuery(o);if(!t.isValid)return r.json({error:`Query validation failed: ${t.errors.join(", ")}`},400);const c=r.req.header("x-cache-control")==="no-cache",p=await s.executeMultiCubeQuery(o,i,{skipCache:c});return r.json(n.formatCubeResponse(o,p,s))}catch(e){return console.error("Query execution error:",e),r.json({error:e instanceof Error?e.message:"Query execution failed"},500)}}),u.get(`${f}/load`,async r=>{try{const e=r.req.query("query");if(!e)return r.json({error:"Query parameter is required"},400);let o;try{o=JSON.parse(e)}catch{return r.json({error:"Invalid JSON in query parameter"},400)}const i=await y(r),t=s.validateQuery(o);if(!t.isValid)return r.json({error:`Query validation failed: ${t.errors.join(", ")}`},400);const c=r.req.header("x-cache-control")==="no-cache",p=await s.executeMultiCubeQuery(o,i,{skipCache:c});return r.json(n.formatCubeResponse(o,p,s))}catch(e){return console.error("Query execution error:",e),r.json({error:e instanceof Error?e.message:"Query execution failed"},500)}}),u.post(`${f}/batch`,async r=>{try{const e=await r.req.json(),{queries:o}=e;if(!o||!Array.isArray(o))return r.json({error:'Request body must contain a "queries" array'},400);if(o.length===0)return r.json({error:"Queries array cannot be empty"},400);const i=await y(r),t=r.req.header("x-cache-control")==="no-cache",c=await n.handleBatchRequest(o,i,s,{skipCache:t});return r.json(c)}catch(e){return console.error("Batch execution error:",e),r.json({error:e instanceof Error?e.message:"Batch execution failed"},500)}}),u.get(`${f}/meta`,r=>{try{const e=s.getMetadata();return r.json(n.formatMetaResponse(e))}catch(e){return console.error("Metadata error:",e),r.json({error:e instanceof Error?e.message:"Failed to fetch metadata"},500)}}),u.post(`${f}/sql`,async r=>{try{const e=await r.req.json(),o=await y(r),i=s.validateQuery(e);if(!i.isValid)return r.json({error:`Query validation failed: ${i.errors.join(", ")}`},400);const t=e.measures?.[0]||e.dimensions?.[0];if(!t)return r.json({error:"No measures or dimensions specified"},400);const c=t.split(".")[0],p=await s.generateSQL(c,e,o);return r.json(n.formatSqlResponse(e,p))}catch(e){return console.error("SQL generation error:",e),r.json({error:e instanceof Error?e.message:"SQL generation failed"},500)}}),u.get(`${f}/sql`,async r=>{try{const e=r.req.query("query");if(!e)return r.json({error:"Query parameter is required"},400);const o=JSON.parse(e),i=await y(r),t=s.validateQuery(o);if(!t.isValid)return r.json({error:`Query validation failed: ${t.errors.join(", ")}`},400);const c=o.measures?.[0]||o.dimensions?.[0];if(!c)return r.json({error:"No measures or dimensions specified"},400);const p=c.split(".")[0],g=await s.generateSQL(p,o,i);return r.json(n.formatSqlResponse(o,g))}catch(e){return console.error("SQL generation error:",e),r.json({error:e instanceof Error?e.message:"SQL generation failed"},500)}}),u.post(`${f}/dry-run`,async r=>{try{const e=await r.req.json(),o=e.query||e,i=await y(r),t=await n.handleDryRun(o,i,s);return r.json(t)}catch(e){return console.error("Dry-run error:",e),r.json({error:e instanceof Error?e.message:"Dry-run validation failed",valid:!1},400)}}),u.get(`${f}/dry-run`,async r=>{try{const e=r.req.query("query");if(!e)return r.json({error:"Query parameter is required",valid:!1},400);const o=JSON.parse(e),i=await y(r),t=await n.handleDryRun(o,i,s);return r.json(t)}catch(e){return console.error("Dry-run error:",e),r.json({error:e instanceof Error?e.message:"Dry-run validation failed",valid:!1},400)}}),u.post(`${f}/explain`,async r=>{try{const e=await r.req.json(),o=e.query||e,i=e.options||{},t=await y(r),c=s.validateQuery(o);if(!c.isValid)return r.json({error:`Query validation failed: ${c.errors.join(", ")}`},400);const p=await s.explainQuery(o,t,i);return r.json(p)}catch(e){return console.error("Explain error:",e),r.json({error:e instanceof Error?e.message:"Explain query failed"},500)}}),w.enabled!==!1){const r={uri:"drizzle-cube://schema",name:"Cube Schema",description:"Current cube metadata as JSON",mimeType:"application/json",text:JSON.stringify(s.getMetadata(),null,2)},e=[...n.getDefaultResources(),r],o=n.getDefaultPrompts(),i=w.basePath??"/mcp";u.post(`${i}`,async t=>{const c=n.validateOriginHeader(t.req.header("origin"),w.allowedOrigins?{allowedOrigins:w.allowedOrigins}:{});if(!c.valid)return t.json(n.buildJsonRpcError(null,-32600,c.reason),403);const p=t.req.header("accept");if(!n.validateAcceptHeader(p))return t.json(n.buildJsonRpcError(null,-32600,"Accept header must include both application/json and text/event-stream"),400);const g=n.negotiateProtocol(t.req.header());if(!g.ok)return t.json({error:"Unsupported MCP protocol version",supported:g.supported},426);const P=await t.req.json().catch(()=>null),m=n.parseJsonRpc(P);if(!m)return t.json(n.buildJsonRpcError(null,-32600,"Invalid JSON-RPC 2.0 request"),400);const M=n.wantsEventStream(p),N=m.method==="initialize";try{const h=await n.dispatchMcpMethod(m.method,m.params,{semanticLayer:s,extractSecurityContext:y,rawRequest:t,rawResponse:null,negotiatedProtocol:g.negotiated,resources:e,prompts:o});if(n.isNotification(m))return t.body(null,202);const E=n.buildJsonRpcResult(m.id??null,h),S=N&&h&&typeof h=="object"&&"sessionId"in h?h.sessionId:void 0,v={};if(S&&(v[n.MCP_SESSION_ID_HEADER]=S),M){const b=new TextEncoder,R=n.primeEventId(),A=new ReadableStream({start(x){x.enqueue(b.encode(`id: ${R}
|
|
2
2
|
|
|
3
3
|
`)),x.enqueue(b.encode(n.serializeSseEvent(E,R))),x.close()}});return new Response(A,{status:200,headers:{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive",...v}})}return t.json(E,200,v)}catch(h){if(n.isNotification(m))return console.error("MCP notification processing error:",h),t.body(null,202);console.error("MCP RPC error:",h);const E=h?.code??-32603,S=h?.data,v=h.message||"MCP request failed",b=n.buildJsonRpcError(m.id??null,E,v,S);if(M){const R=new TextEncoder,A=n.primeEventId(),x=new ReadableStream({start(H){H.enqueue(R.encode(`id: ${A}
|
|
4
4
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Hono as k } from "hono";
|
|
2
|
-
import { S as L, f as I, h as V, a as B, b as N, c as O, v as z, d as Q, e as _, n as U, p as F, w as G, g as K, i as W, j as X, k as D, l as Y, M as Z, m as $, s as H } from "../mcp-transport-
|
|
2
|
+
import { S as L, f as I, h as V, a as B, b as N, c as O, v as z, d as Q, e as _, n as U, p as F, w as G, g as K, i as W, j as X, k as D, l as Y, M as Z, m as $, s as H } from "../mcp-transport-COtZVd4-.js";
|
|
3
3
|
var ee = (q) => {
|
|
4
4
|
const l = {
|
|
5
5
|
...{
|
|
@@ -29971,7 +29971,8 @@ async function zo(s, e, t) {
|
|
|
29971
29971
|
sessionId: Fo(),
|
|
29972
29972
|
serverInfo: {
|
|
29973
29973
|
name: "drizzle-cube",
|
|
29974
|
-
|
|
29974
|
+
// Use safe check for process.env to support edge runtimes (Cloudflare Workers, etc.)
|
|
29975
|
+
version: typeof process < "u" ? process.env?.npm_package_version || "dev" : "worker"
|
|
29975
29976
|
}
|
|
29976
29977
|
};
|
|
29977
29978
|
}
|
|
@@ -212,7 +212,7 @@ ${JSON.stringify(r,void 0,2)}`)}}}var c;(function(s){s[s.SPACE=0]="SPACE",s[s.NO
|
|
|
212
212
|
`.repeat(this.cfg.linesBetweenQueries+1))}formatStatement(e){const t=new be({cfg:this.cfg,dialectCfg:this.dialect.formatOptions,params:this.params,layout:new ss(new ns(ya(this.cfg)))}).format(e.children);return e.hasSemicolon&&(this.cfg.newlineBeforeSemicolon?t.add(c.NEWLINE,";"):t.add(c.NO_NEWLINE,";")),t.toString()}}class Me extends Error{}function no(s){const e=["multilineLists","newlineBeforeOpenParen","newlineBeforeCloseParen","aliasAs","commaPosition","tabulateAlias"];for(const t of e)if(t in s)throw new Me(`${t} config is no more supported.`);if(s.expressionWidth<=0)throw new Me(`expressionWidth config must be positive number. Received ${s.expressionWidth} instead.`);if(s.params&&!io(s.params)&&console.warn('WARNING: All "params" option values should be strings.'),s.paramTypes&&!ro(s.paramTypes))throw new Me("Empty regex given in custom paramTypes. That would result in matching infinite amount of parameters.");return s}function io(s){return(s instanceof Array?s:Object.values(s)).every(t=>typeof t=="string")}function ro(s){return s.custom&&Array.isArray(s.custom)?s.custom.every(e=>e.regex!==""):!0}var To=function(s,e){var t={};for(var E in s)Object.prototype.hasOwnProperty.call(s,E)&&e.indexOf(E)<0&&(t[E]=s[E]);if(s!=null&&typeof Object.getOwnPropertySymbols=="function")for(var n=0,E=Object.getOwnPropertySymbols(s);n<E.length;n++)e.indexOf(E[n])<0&&Object.prototype.propertyIsEnumerable.call(s,E[n])&&(t[E[n]]=s[E[n]]);return t};const is={bigquery:"bigquery",clickhouse:"clickhouse",db2:"db2",db2i:"db2i",duckdb:"duckdb",hive:"hive",mariadb:"mariadb",mysql:"mysql",n1ql:"n1ql",plsql:"plsql",postgresql:"postgresql",redshift:"redshift",spark:"spark",sqlite:"sqlite",sql:"sql",tidb:"tidb",trino:"trino",transactsql:"transactsql",tsql:"transactsql",singlestoredb:"singlestoredb",snowflake:"snowflake"},ao=Object.keys(is),oo={tabWidth:2,useTabs:!1,keywordCase:"preserve",identifierCase:"preserve",dataTypeCase:"preserve",functionCase:"preserve",indentStyle:"standard",logicalOperatorNewline:"before",expressionWidth:50,linesBetweenQueries:1,denseOperators:!1,newlineBeforeSemicolon:!1},Ro=(s,e={})=>{if(typeof e.language=="string"&&!ao.includes(e.language))throw new Me(`Unsupported SQL dialect: ${e.language}`);const t=is[e.language||"sql"];return Ao(s,Object.assign(Object.assign({},e),{dialect:Ca[t]}))},Ao=(s,e)=>{var{dialect:t}=e,E=To(e,["dialect"]);if(typeof s!="string")throw new Error("Invalid query argument. Expected string, instead got "+typeof s);const n=no(Object.assign(Object.assign({},oo),E));return new so(ha(t),n).format(s)};function So(s){let e=0;return e+=(s.measures?.length||0)*1,e+=(s.dimensions?.length||0)*1,e+=(s.filters?.length||0)*2,e+=(s.timeDimensions?.length||0)*3,e<=5?"low":e<=15?"medium":"high"}function rs(s,e){if("and"in s||"or"in s){const t=s.and||s.or||[];for(const E of t)rs(E,e);return}if("member"in s){const[t]=s.member.split(".");t&&e.add(t)}}function Ts(){const s=Date.now(),e=Math.random().toString(36).substring(2,9);return`${s}-${e}`}function No(s){const e=s.dimensions||[],t=s.timeDimensions||[],E=s.measures||[];return{sortedDimensions:e,sortedTimeDimensions:t,timeDimensions:t,measures:E,leafMeasureAdditive:!0,leafMeasures:E,measureToLeafMeasures:{},hasNoTimeDimensionsWithoutGranularity:!0,allFiltersWithinSelectedDimensions:!0,isAdditive:!0,granularityHierarchies:{},hasMultipliedMeasures:!1,hasCumulativeMeasures:!1,windowGranularity:null,filterDimensionsSingleValueEqual:{},ownedDimensions:e,ownedTimeDimensionsWithRollupGranularity:[],ownedTimeDimensionsAsIs:[],allBackAliasMembers:{},hasMultiStage:!1}}function Io(s){if(s.hasExecutor()){const e=s.databaseExecutor;if(e?.engineType)return e.engineType}return"postgres"}async function Oo(s,e,t){if(s.funnel&&s.funnel.steps?.length>=2)return _o(s,e,t);if(s.flow&&s.flow.bindingKey&&s.flow.eventDimension)return co(s,e,t);if(s.retention&&s.retention.bindingKey&&s.retention.timeDimension)return Do(s,e,t);const E=t.validateQuery(s);if(!E.isValid)throw new Error(`Query validation failed: ${E.errors.join(", ")}`);const n=new Set;s.measures?.forEach(o=>{const A=o.split(".")[0];n.add(A)}),s.dimensions?.forEach(o=>{const A=o.split(".")[0];n.add(A)}),s.timeDimensions?.forEach(o=>{const A=o.dimension.split(".")[0];n.add(A)}),s.filters?.forEach(o=>{rs(o,n)});const i=n.size>1;let r;if(i)r=await t.generateMultiCubeSQL(s,e);else{const o=Array.from(n)[0];r=await t.generateSQL(o,s,e)}const T=Array.from(n).map(o=>({cube:o,query:{measures:s.measures?.filter(A=>A.startsWith(o+"."))||[],dimensions:s.dimensions?.filter(A=>A.startsWith(o+"."))||[],filters:s.filters||[],timeDimensions:s.timeDimensions||[],order:s.order||{},limit:s.limit,offset:s.offset}}));let R;try{R=t.analyzeQuery(s,e)}catch(o){console.warn("Query analysis failed:",o)}return{queryType:"regularQuery",normalizedQueries:T,queryOrder:Array.from(n),transformedQueries:T,pivotQuery:{query:s,cubes:Array.from(n)},sql:{sql:[r.sql],params:r.params||[]},complexity:So(s),valid:!0,cubesUsed:Array.from(n),joinType:i?"multi_cube_join":"single_cube",query:s,analysis:R}}function as(s,e,t){const E=Io(t),n=Ts(),i=new Date().toISOString(),r=No(s);return{queryType:"regularQuery",results:[{query:s,lastRefreshTime:i,usedPreAggregations:{},transformedQuery:r,requestId:n,annotation:e.annotation,dataSource:"default",dbType:E,extDbType:E,external:!1,slowQuery:!1,data:e.data,...e.cache&&{cache:e.cache}}],pivotQuery:{...s,queryType:"regularQuery"},slowQuery:!1}}function Se(s,e){try{return Ro(s,{language:{postgres:"postgresql",mysql:"mysql",sqlite:"sqlite",singlestore:"mysql",duckdb:"postgresql"}[e],tabWidth:2,keywordCase:"upper",indentStyle:"standard"})}catch(t){return console.warn("SQL formatting failed:",t),s}}function Co(s,e){return{sql:e.sql,params:e.params||[],query:s}}function lo(s){return{cubes:s}}function uo(s,e=500){return{error:s instanceof Error?s.message:s,status:e}}async function Lo(s,e,t,E){return{results:(await Promise.allSettled(s.map(async r=>{const T=await t.executeMultiCubeQuery(r,e,{skipCache:E?.skipCache});return as(r,T,t)}))).map((r,T)=>r.status==="fulfilled"?{success:!0,...r.value}:{success:!1,error:r.reason instanceof Error?r.reason.message:String(r.reason),query:s[T]})}}async function _o(s,e,t){const E=t.validateQuery(s);if(!E.isValid)throw new Error(`Funnel query validation failed: ${E.errors.join(", ")}`);const n=await t.dryRunFunnel(s,e),i=new Set,r=s.funnel;if(typeof r.bindingKey=="string"){const[T]=r.bindingKey.split(".");T&&i.add(T)}else if(Array.isArray(r.bindingKey))for(const T of r.bindingKey)i.add(T.cube);if(typeof r.timeDimension=="string"){const[T]=r.timeDimension.split(".");T&&i.add(T)}else if(Array.isArray(r.timeDimension))for(const T of r.timeDimension)i.add(T.cube);for(const T of r.steps)"cube"in T&&T.cube&&i.add(T.cube);return{queryType:"funnelQuery",normalizedQueries:[],queryOrder:Array.from(i),transformedQueries:[],pivotQuery:{query:s,cubes:Array.from(i)},sql:{sql:[n.sql],params:n.params||[]},complexity:"high",valid:!0,cubesUsed:Array.from(i),joinType:"funnel_cte",query:s,funnel:{stepCount:r.steps.length,steps:r.steps.map((T,R)=>({index:R,name:T.name,timeToConvert:T.timeToConvert,cube:"cube"in T?T.cube:void 0})),bindingKey:r.bindingKey,timeDimension:r.timeDimension,includeTimeMetrics:r.includeTimeMetrics,globalTimeWindow:r.globalTimeWindow}}}async function co(s,e,t){const E=t.validateQuery(s);if(!E.isValid)throw new Error(`Flow query validation failed: ${E.errors.join(", ")}`);const n=await t.dryRunFlow(s,e),i=new Set,r=s.flow;if(typeof r.bindingKey=="string"){const[T]=r.bindingKey.split(".");T&&i.add(T)}else if(Array.isArray(r.bindingKey))for(const T of r.bindingKey)i.add(T.cube);if(typeof r.timeDimension=="string"){const[T]=r.timeDimension.split(".");T&&i.add(T)}if(typeof r.eventDimension=="string"){const[T]=r.eventDimension.split(".");T&&i.add(T)}return{queryType:"flowQuery",normalizedQueries:[],queryOrder:Array.from(i),transformedQueries:[],pivotQuery:{measures:[],dimensions:[],timeDimensions:[],order:{},filters:[],queryType:"flowQuery",joinType:"flow_cte",query:s,flow:{stepsBefore:r.stepsBefore,stepsAfter:r.stepsAfter,bindingKey:r.bindingKey,timeDimension:r.timeDimension,eventDimension:r.eventDimension,startingStep:r.startingStep}},sql:{sql:n.sql,params:n.params||[]}}}async function Do(s,e,t){const E=t.validateQuery(s);if(!E.isValid)throw new Error(`Retention query validation failed: ${E.errors.join(", ")}`);const n=await t.dryRunRetention(s,e),i=new Set,r=s.retention;if(typeof r.timeDimension=="string"){const[T]=r.timeDimension.split(".");T&&i.add(T)}else r.timeDimension&&typeof r.timeDimension=="object"&&i.add(r.timeDimension.cube);if(typeof r.bindingKey=="string"){const[T]=r.bindingKey.split(".");T&&i.add(T)}else if(Array.isArray(r.bindingKey))for(const T of r.bindingKey)i.add(T.cube);if(r.breakdownDimensions&&Array.isArray(r.breakdownDimensions))for(const T of r.breakdownDimensions){const[R]=T.split(".");R&&i.add(R)}return{queryType:"retentionQuery",normalizedQueries:[],queryOrder:Array.from(i),transformedQueries:[],pivotQuery:{measures:[],dimensions:[],timeDimensions:[],order:{},filters:[],queryType:"retentionQuery",joinType:"retention_cte",query:s,retention:{timeDimension:r.timeDimension,bindingKey:r.bindingKey,granularity:r.granularity,periods:r.periods,retentionType:r.retentionType,breakdownDimensions:r.breakdownDimensions}},sql:{sql:n.sql,params:n.params||[]}}}async function Ut(s,e){const t=s.getMetadata();return{cubes:As(t,{topic:e.topic,intent:e.intent,limit:e.limit,minScore:e.minScore})}}async function ht(s,e){const t=s.getMetadata();return bo(t,e.naturalLanguage,e.cube)}async function gt(s,e){const t=s.getMetadata();return wo(e.query,t)}async function Gt(s,e,t){const E=t.query,n=s.validateQuery(E);if(!n.isValid)throw new Error(`Query validation failed: ${n.errors.join(", ")}`);const i=await s.executeMultiCubeQuery(E,e);return{data:i.data,annotation:i.annotation,query:E}}class mo{cubes=new Map;dbExecutor;metadataCache;cacheConfig;constructor(e){e?.databaseExecutor?this.dbExecutor=e.databaseExecutor:e?.drizzle&&(this.dbExecutor=Jt(e.drizzle,e.schema,e.engineType)),this.cacheConfig=e?.cache}setDatabaseExecutor(e){this.dbExecutor=e}getEngineType(){return this.dbExecutor?.getEngineType()}setDrizzle(e,t,E){this.dbExecutor=Jt(e,t,E)}hasExecutor(){return!!this.dbExecutor}registerCube(e){e.meta&&console.log(`[DEBUG] registerCube: ${e.name} has meta:`,JSON.stringify(e.meta)),this.validateCalculatedMeasures(e),new se(this.cubes).populateDependencies(e),this.cubes.set(e.name,e),this.invalidateMetadataCache()}validateCalculatedMeasures(e){const t=[];for(const[E,n]of Object.entries(e.measures))if(n.type==="calculated"){if(!n.calculatedSql){t.push(`Calculated measure '${e.name}.${E}' must have calculatedSql property`);continue}const i=En(n.calculatedSql);if(!i.isValid){t.push(`Invalid calculatedSql syntax in '${e.name}.${E}': ${i.errors.join(", ")}`);continue}const r=new Map(this.cubes);r.set(e.name,e);const T=new se(r);try{T.validateDependencies(e)}catch(R){t.push(R instanceof Error?R.message:String(R))}}if(t.length===0){const E=new Map(this.cubes);E.set(e.name,e);const n=new se(E);n.buildGraph(e);const i=n.detectCycle();i&&t.push(`Circular dependency detected in calculated measures: ${i.join(" -> ")}`)}if(t.length>0)throw new Error(`Calculated measure validation failed for cube '${e.name}':
|
|
213
213
|
${t.join(`
|
|
214
214
|
`)}`)}getCube(e){return this.cubes.get(e)}getAllCubes(){return Array.from(this.cubes.values())}getAllCubesMap(){return this.cubes}async execute(e,t,E){if(!this.dbExecutor)throw new Error("Database executor not configured");return new te(this.dbExecutor,this.cacheConfig).execute(this.cubes,e,t,E)}async executeMultiCubeQuery(e,t,E){return this.execute(e,t,E)}async executeQuery(e,t,E){if(!this.cubes.get(e))throw new Error(`Cube '${e}' not found`);return this.execute(t,E)}getMetadata(){return this.metadataCache?this.metadataCache:(this.metadataCache=Array.from(this.cubes.values()).map(e=>this.generateCubeMetadata(e)),this.metadataCache)}getColumnName(e){if(e&&e.name||e&&e.columnType&&e.name)return e.name;if(typeof e=="string")return e;if(e&&typeof e=="object"){if(e._.name)return e._.name;if(e.name)return e.name;if(e.columnName)return e.columnName}return"unknown_column"}generateCubeMetadata(e){const t=Object.keys(e.measures),E=Object.keys(e.dimensions),n=new Array(t.length),i=new Array(E.length);for(let R=0;R<t.length;R++){const o=t[R],A=e.measures[o];n[R]={name:`${e.name}.${o}`,title:A.title||o,shortTitle:A.title||o,type:A.type,format:void 0,description:A.description,synonyms:A.synonyms}}for(let R=0;R<E.length;R++){const o=E[R],A=e.dimensions[o];i[R]={name:`${e.name}.${o}`,title:A.title||o,shortTitle:A.title||o,type:A.type,format:void 0,description:A.description,synonyms:A.synonyms}}const r=[];if(e.joins)for(const[,R]of Object.entries(e.joins)){const o=typeof R.targetCube=="function"?R.targetCube():R.targetCube;r.push({targetCube:o.name,relationship:R.relationship,joinFields:R.on.map(A=>({sourceField:this.getColumnName(A.source),targetField:this.getColumnName(A.target)}))})}const T={name:e.name,title:e.title||e.name,description:e.description,exampleQuestions:e.exampleQuestions,measures:n,dimensions:i,segments:[],relationships:r.length>0?r:void 0,meta:e.meta};return e.meta&&console.log(`[DEBUG] Cube ${e.name} has meta:`,JSON.stringify(e.meta)),T}async generateSQL(e,t,E){const n=this.getCube(e);if(!n)throw new Error(`Cube '${e}' not found`);if(!this.dbExecutor)throw new Error("Database executor not configured");const r=await new te(this.dbExecutor).generateSQL(n,t,E),T=this.dbExecutor.getEngineType();return{sql:Se(r.sql,T),params:r.params}}async generateMultiCubeSQL(e,t){if(!this.dbExecutor)throw new Error("Database executor not configured");const n=await new te(this.dbExecutor).generateMultiCubeSQL(this.cubes,e,t),i=this.dbExecutor.getEngineType();return{sql:Se(n.sql,i),params:n.params}}async dryRunFunnel(e,t){if(!this.dbExecutor)throw new Error("Database executor not configured");const n=await new te(this.dbExecutor).dryRunFunnel(this.cubes,e,t),i=this.dbExecutor.getEngineType();return{sql:Se(n.sql,i),params:n.params}}async dryRunFlow(e,t){if(!this.dbExecutor)throw new Error("Database executor not configured");const n=await new te(this.dbExecutor).dryRunFlow(this.cubes,e,t),i=this.dbExecutor.getEngineType();return{sql:Se(n.sql,i),params:n.params}}async dryRunRetention(e,t){if(!this.dbExecutor)throw new Error("Database executor not configured");const n=await new te(this.dbExecutor).dryRunRetention(this.cubes,e,t),i=this.dbExecutor.getEngineType();return{sql:Se(n.sql,i),params:n.params}}async explainQuery(e,t,E){if(!this.dbExecutor)throw new Error("Database executor not configured");return new te(this.dbExecutor).explainQuery(this.cubes,e,t,E)}hasCube(e){return this.cubes.has(e)}removeCube(e){const t=this.cubes.delete(e);return t&&this.invalidateMetadataCache(),t}clearCubes(){this.cubes.clear(),this.invalidateMetadataCache()}invalidateMetadataCache(){this.metadataCache=void 0}getCubeNames(){return Array.from(this.cubes.keys())}validateQuery(e){return os(this.cubes,e)}analyzeQuery(e,t){if(!this.dbExecutor)throw new Error("Database executor not configured");const E=new KE,n={db:this.dbExecutor.db,schema:this.dbExecutor.schema,securityContext:t};return E.analyzeQueryPlan(this.cubes,e,n)}}function os(s,e){const t=[];if(e.funnel!==void 0&&e.funnel.steps?.length>=2){const n=e.funnel.bindingKey;if(typeof n=="string"){const[i]=n.split(".");i&&!s.has(i)&&t.push(`Funnel binding key cube not found: ${i}`)}else if(Array.isArray(n))for(const i of n)s.has(i.cube)||t.push(`Funnel binding key cube not found: ${i.cube}`);return{isValid:t.length===0,errors:t}}if(e.flow!==void 0&&e.flow.startingStep!==void 0&&e.flow.eventDimension!==void 0){const n=e.flow.bindingKey;if(typeof n=="string"){const[i]=n.split(".");i&&!s.has(i)&&t.push(`Flow binding key cube not found: ${i}`)}return{isValid:t.length===0,errors:t}}if(e.retention!==void 0&&e.retention.timeDimension!=null&&e.retention.bindingKey!=null){const n=Po(e.retention.timeDimension);n&&!s.has(n)&&t.push(`Retention cube not found: ${n}`);const i=e.retention.bindingKey;if(typeof i=="string"){const[r]=i.split(".");r&&!s.has(r)&&t.push(`Retention binding key cube not found: ${r}`)}else if(Array.isArray(i))for(const r of i)s.has(r.cube)||t.push(`Retention binding key cube not found: ${r.cube}`);if(e.retention.breakdownDimensions&&Array.isArray(e.retention.breakdownDimensions))for(const r of e.retention.breakdownDimensions){const[T]=r.split(".");T&&!s.has(T)&&t.push(`Retention breakdown cube not found: ${T}`)}return{isValid:t.length===0,errors:t}}const E=new Set;if(e.measures)for(const n of e.measures){const[i,r]=n.split(".");if(!i||!r){t.push(`Invalid measure format: ${n}. Expected format: 'CubeName.fieldName'`);continue}E.add(i);const T=s.get(i);if(!T){t.push(`Cube '${i}' not found (referenced in measure '${n}')`);continue}T.measures[r]||t.push(`Measure '${r}' not found on cube '${i}'`)}if(e.dimensions)for(const n of e.dimensions){const[i,r]=n.split(".");if(!i||!r){t.push(`Invalid dimension format: ${n}. Expected format: 'CubeName.fieldName'`);continue}E.add(i);const T=s.get(i);if(!T){t.push(`Cube '${i}' not found (referenced in dimension '${n}')`);continue}T.dimensions[r]||t.push(`Dimension '${r}' not found on cube '${i}'`)}if(e.timeDimensions)for(const n of e.timeDimensions){const[i,r]=n.dimension.split(".");if(!i||!r){t.push(`Invalid timeDimension format: ${n.dimension}. Expected format: 'CubeName.fieldName'`);continue}E.add(i);const T=s.get(i);if(!T){t.push(`Cube '${i}' not found (referenced in timeDimension '${n.dimension}')`);continue}T.dimensions[r]||t.push(`TimeDimension '${r}' not found on cube '${i}' (must be a dimension with time type)`)}if(e.filters)for(const n of e.filters)Rs(n,s,t,E);return E.size===0&&t.push("Query must reference at least one cube through measures, dimensions, or filters"),{isValid:t.length===0,errors:t}}function Rs(s,e,t,E){if("and"in s||"or"in s){const T=s.and||s.or||[];for(const R of T)Rs(R,e,t,E);return}if(!("member"in s)){t.push("Filter must have a member field");return}const[n,i]=s.member.split(".");if(!n||!i){t.push(`Invalid filter member format: ${s.member}. Expected format: 'CubeName.fieldName'`);return}E.add(n);const r=e.get(n);if(!r){t.push(`Cube '${n}' not found (referenced in filter '${s.member}')`);return}!r.dimensions[i]&&!r.measures[i]&&t.push(`Filter field '${i}' not found on cube '${n}' (must be a dimension or measure)`)}function Po(s){if(typeof s=="string"){const[e]=s.split(".");return e||null}return s.cube}const yE={funnel:{description:"Track conversion through sequential steps. Entities (identified by bindingKey) move through ordered steps.",structure:{funnel:{bindingKey:"Cube.dimension - identifies entities moving through funnel",timeDimension:"Cube.dimension - time field for ordering events",steps:[{name:"string - human readable step name",filter:{member:"Cube.dimension",operator:"equals | notEquals | contains | ...",values:["array of filter values"]},timeToConvert:'optional - max time window e.g. "7 days"'}],dateRange:'[start, end] array OR string like "last 7 days", "last 3 months", "this quarter"'}}},flow:{description:"Analyze paths users take before/after a specific event. Shows event sequences.",structure:{flow:{bindingKey:"Cube.dimension - identifies entities",timeDimension:"Cube.dimension - time field for ordering",eventDimension:"Cube.dimension - the event type field",startingStep:{filter:{member:"Cube.dimension",operator:"equals",values:["event value"]}},stepsBefore:"number - how many steps to show before starting step",stepsAfter:"number - how many steps to show after starting step",dateRange:'[start, end] array OR string like "last 7 days", "last 3 months", "this quarter"'}}},retention:{description:"Measure how many users return over time periods after initial activity.",structure:{retention:{bindingKey:"Cube.dimension - identifies entities",timeDimension:"Cube.dimension - time field for cohort assignment",granularity:"day | week | month - period size",periods:"number - how many periods to analyze",dateRange:'[start, end] array OR string like "last 7 days", "last 3 months", "this quarter"'}}}};function po(s,e){const t=[];for(let E=0;E<=e.length;E++)t[E]=[E];for(let E=0;E<=s.length;E++)t[0][E]=E;for(let E=1;E<=e.length;E++)for(let n=1;n<=s.length;n++)e.charAt(E-1)===s.charAt(n-1)?t[E][n]=t[E-1][n-1]:t[E][n]=Math.min(t[E-1][n-1]+1,t[E][n-1]+1,t[E-1][n]+1);return t[e.length][s.length]}function W(s,e){const t=s.toLowerCase().trim(),E=e.toLowerCase().trim();if(t===E)return 1;if(E.includes(t))return .9;const n=E.split(/[\s_-]+/);for(const R of n){if(R===t)return .85;if(R.startsWith(t))return .75}const i=po(t,E),r=Math.max(t.length,E.length),T=1-i/r;return T>.5?T*.7:0}function Fe(s,e){let t=0;for(const E of e){const n=W(s,E);n>t&&(t=n)}return t}function Mo(s){const e=new Set(["a","an","the","is","are","was","were","be","been","being","have","has","had","do","does","did","will","would","could","should","may","might","must","can","and","or","but","if","then","else","when","where","why","how","what","which","who","this","that","these","those","i","me","my","we","our","you","your","he","she","it","they","them","their","in","on","at","to","for","of","with","by","from","up","down","out","over","under","about","into","through","during","before","after","above","below","between","show","me","get","find","list","give","tell","display","want","need","see","know"]);return s.toLowerCase().replace(/[^\w\s]/g," ").split(/\s+/).filter(t=>t.length>2&&!e.has(t))}function fo(s,e){let t=0;const E=[],n=new Map,i=new Map;for(const o of e){const A=W(o,s.name);A>.5&&(t+=A*2,E.includes("name")||E.push("name"));const S=W(o,s.title);if(S>.5&&(t+=S*1.5,E.includes("title")||E.push("title")),s.description){const N=W(o,s.description);N>.3&&(t+=N,E.includes("description")||E.push("description"))}if(s.exampleQuestions)for(const N of s.exampleQuestions){const I=W(o,N);I>.3&&(t+=I*1.5,E.includes("exampleQuestions")||E.push("exampleQuestions"))}for(const N of s.measures){let I=0;const O=N.name.split(".").pop()||N.name;if(I=Math.max(I,W(o,O)),I=Math.max(I,W(o,N.title)),N.description&&(I=Math.max(I,W(o,N.description)*.8)),N.synonyms&&(I=Math.max(I,Fe(o,N.synonyms))),I>.4){t+=I,E.includes("measures")||E.push("measures");const l=n.get(N.name)||0;n.set(N.name,Math.max(l,I))}}for(const N of s.dimensions){let I=0;const O=N.name.split(".").pop()||N.name;if(I=Math.max(I,W(o,O)),I=Math.max(I,W(o,N.title)),N.description&&(I=Math.max(I,W(o,N.description)*.8)),N.synonyms&&(I=Math.max(I,Fe(o,N.synonyms))),I>.4){t+=I,E.includes("dimensions")||E.push("dimensions");const l=i.get(N.name)||0;i.set(N.name,Math.max(l,I))}}}const r=Math.min(1,t/(e.length*2)),T=Array.from(n.entries()).sort((o,A)=>A[1]-o[1]).slice(0,5).map(([o])=>o),R=Array.from(i.entries()).sort((o,A)=>A[1]-o[1]).slice(0,5).map(([o])=>o);return{score:r,matchedOn:E,suggestedMeasures:T,suggestedDimensions:R}}function pt(s){const e=!!s.meta?.eventStream,t=s.dimensions.some(i=>i.type==="time"),E=s.dimensions.some(i=>i.name.toLowerCase().includes("id")||i.type==="number"||s.meta?.eventStream?.bindingKey&&i.name===s.meta.eventStream.bindingKey),n=e||t&&E;return{query:!0,funnel:n,flow:n,retention:n}}function bE(s){const e=pt(s);if(!e.funnel&&!e.flow&&!e.retention)return;const t=[];if(s.meta?.eventStream?.bindingKey){const i=s.dimensions.find(r=>r.name===s.meta?.eventStream?.bindingKey);t.push({dimension:s.meta.eventStream.bindingKey,description:i?.description||"Configured binding key"})}for(const i of s.dimensions)(i.name.split(".").pop()?.toLowerCase()||"").includes("id")&&!t.some(T=>T.dimension===i.name)&&t.push({dimension:i.name,description:i.description||"Potential entity identifier"});const E=[];if(s.meta?.eventStream?.timeDimension){const i=s.dimensions.find(r=>r.name===s.meta?.eventStream?.timeDimension);E.push({dimension:s.meta.eventStream.timeDimension,description:i?.description||"Configured time dimension"})}for(const i of s.dimensions)i.type==="time"&&!E.some(r=>r.dimension===i.name)&&E.push({dimension:i.name,description:i.description});const n=[];for(const i of s.dimensions){const r=i.name.split(".").pop()?.toLowerCase()||"";i.type==="string"&&(r.includes("type")||r.includes("event")||r.includes("status")||r.includes("state")||r.includes("action"))&&n.push({dimension:i.name,description:i.description||"Potential event type dimension"})}return{candidateBindingKeys:t,candidateTimeDimensions:E,candidateEventDimensions:n}}function FE(s,e){const t=[];if(!e)return t;if(e.candidateBindingKeys.length>1&&t.push("Choose bindingKey based on what entity to track through the analysis"),e.candidateEventDimensions.length>0){const E=e.candidateEventDimensions[0].dimension;t.push(`Query ${E} dimension to discover available values for funnel steps`)}return t.push("Use /mcp/load with a standard query to discover dimension values before building analysis queries"),t}function As(s,e={}){const{topic:t,intent:E,limit:n=10,minScore:i=.1}=e,r=[t,E].filter(Boolean).join(" ");if(!r.trim())return s.slice(0,n).map(o=>{const A=pt(o),S=bE(o),N=FE(o,S),I=A.funnel||A.flow||A.retention;return{cube:o.name,title:o.title,description:o.description,relevanceScore:1,matchedOn:[],suggestedMeasures:o.measures.slice(0,5).map(O=>O.name),suggestedDimensions:o.dimensions.slice(0,5).map(O=>O.name),capabilities:A,analysisConfig:S,hints:N.length>0?N:void 0,querySchemas:I?yE:void 0}});const T=Mo(r);if(T.length===0)return[];const R=[];for(const o of s){const{score:A,matchedOn:S,suggestedMeasures:N,suggestedDimensions:I}=fo(o,T);if(A>=i){const O=pt(o),l=bE(o),L=FE(o,l),C=O.funnel||O.flow||O.retention;R.push({cube:o.name,title:o.title,description:o.description,relevanceScore:A,matchedOn:S,suggestedMeasures:N,suggestedDimensions:I,capabilities:O,analysisConfig:l,hints:L.length>0?L:void 0,querySchemas:C?yE:void 0})}}return R.sort((o,A)=>A.relevanceScore-o.relevanceScore).slice(0,n)}function yt(s,e,t){let E=null;for(const n of s){if(!t||t==="measure")for(const i of n.measures){const r=i.name.split(".").pop()||i.name;let T=W(e,r);T=Math.max(T,W(e,i.title)),i.synonyms&&(T=Math.max(T,Fe(e,i.synonyms))),T>.5&&(!E||T>E.score)&&(E={field:i.name,cube:n.name,score:T,type:"measure"})}if(!t||t==="dimension")for(const i of n.dimensions){const r=i.name.split(".").pop()||i.name;let T=W(e,r);T=Math.max(T,W(e,i.title)),i.synonyms&&(T=Math.max(T,Fe(e,i.synonyms))),T>.5&&(!E||T>E.score)&&(E={field:i.name,cube:n.name,score:T,type:"dimension"})}}return E}function Uo(){const s=new Date,e=s.toISOString().split("T")[0],t=T=>T.toISOString().split("T")[0],E=T=>new Date(T.getFullYear(),T.getMonth(),1),n=T=>new Date(T.getFullYear(),0,1),i=T=>{const R=Math.floor(T.getMonth()/3);return new Date(T.getFullYear(),R*3,1)},r=T=>{const R=T.getDay(),o=T.getDate()-R+(R===0?-6:1);return new Date(T.getFullYear(),T.getMonth(),o)};return[{pattern:/\btoday\b/i,getDateRange:()=>[e,e],granularity:"day"},{pattern:/\byesterday\b/i,getDateRange:()=>{const T=new Date(s);T.setDate(T.getDate()-1);const R=t(T);return[R,R]},granularity:"day"},{pattern:/\bthis week\b/i,getDateRange:()=>[t(r(s)),e],granularity:"day"},{pattern:/\blast week\b/i,getDateRange:()=>{const T=new Date(r(s));T.setDate(T.getDate()-7);const R=new Date(T);return R.setDate(R.getDate()+6),[t(T),t(R)]},granularity:"day"},{pattern:/\bthis month\b/i,getDateRange:()=>[t(E(s)),e],granularity:"day"},{pattern:/\blast month\b/i,getDateRange:()=>{const T=new Date(s.getFullYear(),s.getMonth()-1,1),R=new Date(s.getFullYear(),s.getMonth(),0);return[t(T),t(R)]},granularity:"day"},{pattern:/\bthis quarter\b/i,getDateRange:()=>[t(i(s)),e],granularity:"month"},{pattern:/\blast quarter\b/i,getDateRange:()=>{const T=new Date(i(s));T.setMonth(T.getMonth()-3);const R=new Date(i(s));return R.setDate(R.getDate()-1),[t(T),t(R)]},granularity:"month"},{pattern:/\bthis year\b/i,getDateRange:()=>[t(n(s)),e],granularity:"month"},{pattern:/\blast year\b/i,getDateRange:()=>{const T=new Date(s.getFullYear()-1,0,1),R=new Date(s.getFullYear()-1,11,31);return[t(T),t(R)]},granularity:"month"},{pattern:/\blast (\d+) days?\b/i,getDateRange:()=>{const T=new Date(s);return T.setDate(T.getDate()-7),[t(T),e]},granularity:"day"},{pattern:/\blast (\d+) weeks?\b/i,getDateRange:()=>{const T=new Date(s);return T.setDate(T.getDate()-28),[t(T),e]},granularity:"week"},{pattern:/\blast (\d+) months?\b/i,getDateRange:()=>{const T=new Date(s);return T.setMonth(T.getMonth()-3),[t(T),e]},granularity:"month"},{pattern:/\bq([1-4])\b/i,getDateRange:()=>[t(new Date(s.getFullYear(),0,1)),t(new Date(s.getFullYear(),2,31))],granularity:"month"}]}const Lt={funnel:/\b(funnel|conversion|drop.?off|steps?|journey|pipeline|stages?)\b/i,flow:/\b(flows?|paths?|sequence|before|after|next|previous|user.?journey)\b/i,retention:/\b(retention|cohort|return|churn|comeback|retained|day.?\d+)\b/i};function ho(s){const e=s.toLowerCase();return Lt.funnel.test(e)?"funnel":Lt.flow.test(e)?"flow":Lt.retention.test(e)?"retention":"query"}function BE(s,e){const t=e||"the relevant cube";switch(s){case"funnel":return[`Use /mcp/discover to get ${t} funnel configuration and schema`,"Query the event dimension to discover available event types for funnel steps","Build funnel query with discovered values using the schema from discover"];case"flow":return[`Use /mcp/discover to get ${t} flow configuration and schema`,"Query the event dimension to discover available event types","Build flow query specifying the starting event and steps before/after"];case"retention":return[`Use /mcp/discover to get ${t} retention configuration and schema`,"Build retention query specifying granularity (day/week/month) and number of periods"]}}function go(s){const e=Uo(),t=s.toLowerCase();for(const E of e){const n=t.match(E.pattern);if(n){if(n[1]&&/^\d+$/.test(n[1])){const i=parseInt(n[1],10),r=new Date,T=r.toISOString().split("T")[0],R=o=>o.toISOString().split("T")[0];if(/days?/.test(t)){const o=new Date(r);return o.setDate(o.getDate()-i),{dateRange:[R(o),T],granularity:"day"}}if(/weeks?/.test(t)){const o=new Date(r);return o.setDate(o.getDate()-i*7),{dateRange:[R(o),T],granularity:i<=4?"day":"week"}}if(/months?/.test(t)){const o=new Date(r);return o.setMonth(o.getMonth()-i),{dateRange:[R(o),T],granularity:i<=3?"day":"month"}}}if(/^q[1-4]$/i.test(n[0])){const i=parseInt(n[1],10),T=new Date().getFullYear(),R=(i-1)*3,o=new Date(T,R,1),A=new Date(T,R+3,0),S=N=>N.toISOString().split("T")[0];return{dateRange:[S(o),S(A)],granularity:"month"}}return{dateRange:E.getDateRange(),granularity:E.granularity}}}return null}function Go(s){const e=s.toLowerCase(),t=[{pattern:/\b(total|sum|combined)\b/i,type:"sum"},{pattern:/\b(count|number of|how many)\b/i,type:"count"},{pattern:/\b(average|avg|mean)\b/i,type:"avg"},{pattern:/\b(maximum|max|highest|top)\b/i,type:"max"},{pattern:/\b(minimum|min|lowest|bottom)\b/i,type:"min"}];for(const{pattern:E,type:n}of t)if(E.test(e))return{type:n,confidence:.8};return null}function yo(s){const e=s.toLowerCase(),t=[],E=/\bby\s+(\w+(?:\s+\w+)?)/gi;let n;for(;(n=E.exec(e))!==null;)t.push(n[1].trim());const i=/\bper\s+(\w+)/gi;for(;(n=i.exec(e))!==null;)t.push(n[1].trim());const r=/\bfor each\s+(\w+)/gi;for(;(n=r.exec(e))!==null;)t.push(n[1].trim());return t}function bo(s,e,t){const E=[],n=[],i={},r=ho(e);let T;if(t){const L=s.find(C=>C.name===t);L?(T=[L],E.push(`Using specified cube: ${t}`)):(n.push(`Specified cube '${t}' not found`),T=[])}else T=As(s,{intent:e,limit:3}).map(C=>s.find(_=>_.name===C.cube)).filter(C=>C!==void 0),T.length>0&&E.push(`Identified relevant cubes: ${T.map(C=>C.name).join(", ")}`);if(T.length===0){const L=r!=="query"?BE(r,void 0):void 0;return{query:{},confidence:0,reasoning:["Could not identify relevant cubes for this query"],warnings:n,analysisMode:r,nextSteps:L}}const R=T[0];let o=.5;const A=Go(e);A&&(E.push(`Detected ${A.type} aggregation intent`),o+=.1);const S=[],N=e.toLowerCase();for(const L of R.measures){const _=[(L.name.split(".").pop()||L.name).toLowerCase(),L.title.toLowerCase(),...(L.synonyms||[]).map(P=>P.toLowerCase())];for(const P of _)if(N.includes(P)){S.push(L.name),E.push(`Matched measure '${L.name}' via keyword '${P}'`),o+=.15;break}}if(S.length===0&&A){const L=R.measures.filter(C=>C.type===A.type);if(L.length>0)S.push(L[0].name),E.push(`Suggested ${L[0].name} based on ${A.type} intent`);else if(A.type==="count"){const C=R.measures.find(_=>_.type==="count"||_.type==="countDistinct");C&&(S.push(C.name),E.push(`Suggested ${C.name} for counting`))}}S.length===0&&R.measures.length>0&&(S.push(R.measures[0].name),E.push(`Using default measure: ${R.measures[0].name}`),n.push("Could not determine specific measure from query, using default")),i.measures=S;const I=yo(e),O=[];for(const L of I){const C=yt(T,L,"dimension");C&&(O.push(C.field),E.push(`Matched dimension '${C.field}' from grouping keyword '${L}'`),o+=.1)}for(const L of T)for(const C of L.dimensions){const P=[(C.name.split(".").pop()||C.name).toLowerCase(),C.title.toLowerCase(),...(C.synonyms||[]).map(D=>D.toLowerCase())];for(const D of P)if(N.includes(D)&&!O.includes(C.name)&&(N.includes(`by ${D}`)||N.includes(`per ${D}`))){O.push(C.name),E.push(`Matched dimension '${C.name}' as grouping`),o+=.1;break}}O.length>0&&(i.dimensions=O);const l=go(e);if(l){const L=R.dimensions.find(C=>C.type==="time");if(L){const C={dimension:L.name,dateRange:l.dateRange};l.granularity&&(C.granularity=l.granularity),i.timeDimensions=[C],E.push(`Applied time filter: ${l.dateRange[0]} to ${l.dateRange[1]}`),o+=.15}else n.push("Time expression found but no time dimension in cube")}if(o=Math.min(1,o),r!=="query"){const L=T.length>0?T[0].name:void 0;return{query:{},confidence:.7,reasoning:[`Detected ${r} intent from natural language`,...L?[`Found relevant cube: ${L}`]:[]],warnings:n.length>0?n:void 0,analysisMode:r,nextSteps:BE(r,L)}}return{query:i,confidence:o,reasoning:E,warnings:n.length>0?n:void 0,analysisMode:"query"}}function Fo(s,e){const t=[];for(let E=0;E<=e.length;E++)t[E]=[E];for(let E=0;E<=s.length;E++)t[0][E]=E;for(let E=1;E<=e.length;E++)for(let n=1;n<=s.length;n++)e.charAt(E-1)===s.charAt(n-1)?t[E][n]=t[E-1][n-1]:t[E][n]=Math.min(t[E-1][n-1]+1,t[E][n-1]+1,t[E-1][n]+1);return t[e.length][s.length]}function Re(s,e){let t=null;for(const E of e){const n=Fo(s.toLowerCase(),E.toLowerCase());n<=3&&(!t||n<t.distance)&&(t={field:E,distance:n})}return t}function Bo(s,e,t,E){const n=s.split(".");if(n.length!==2){t.push({type:"syntax_error",message:`Invalid measure format: '${s}'. Expected 'CubeName.measureName'`,field:s});return}const[i,r]=n,T=e.find(o=>o.name===i);if(!T){const o=e.map(S=>S.name),A=Re(i,o);A?(t.push({type:"cube_not_found",message:`Cube '${i}' not found`,field:s,suggestion:`Did you mean '${A.field}'?`,correctedValue:`${A.field}.${r}`}),E.set(s,`${A.field}.${r}`)):t.push({type:"cube_not_found",message:`Cube '${i}' not found`,field:s,suggestion:`Available cubes: ${o.join(", ")}`});return}if(!T.measures.some(o=>o.name===s)){const o=yt(e,r,"measure");if(o&&o.cube===i)t.push({type:"measure_not_found",message:`Measure '${r}' not found on cube '${i}'`,field:s,suggestion:`Did you mean '${o.field}'?`,correctedValue:o.field}),E.set(s,o.field);else{const A=T.measures.map(N=>N.name.split(".").pop()),S=Re(r,A);if(S){const N=`${i}.${S.field}`;t.push({type:"measure_not_found",message:`Measure '${r}' not found on cube '${i}'`,field:s,suggestion:`Did you mean '${S.field}'?`,correctedValue:N}),E.set(s,N)}else t.push({type:"measure_not_found",message:`Measure '${r}' not found on cube '${i}'`,field:s,suggestion:`Available measures: ${A.slice(0,5).join(", ")}${A.length>5?"...":""}`})}}}function j(s,e,t,E){const n=s.split(".");if(n.length!==2){t.push({type:"syntax_error",message:`Invalid dimension format: '${s}'. Expected 'CubeName.dimensionName'`,field:s});return}const[i,r]=n,T=e.find(o=>o.name===i);if(!T){const o=e.map(S=>S.name),A=Re(i,o);A?(t.push({type:"cube_not_found",message:`Cube '${i}' not found`,field:s,suggestion:`Did you mean '${A.field}'?`,correctedValue:`${A.field}.${r}`}),E.set(s,`${A.field}.${r}`)):t.push({type:"cube_not_found",message:`Cube '${i}' not found`,field:s,suggestion:`Available cubes: ${o.join(", ")}`});return}if(!T.dimensions.some(o=>o.name===s)){const o=yt(e,r,"dimension");if(o&&o.cube===i)t.push({type:"dimension_not_found",message:`Dimension '${r}' not found on cube '${i}'`,field:s,suggestion:`Did you mean '${o.field}'?`,correctedValue:o.field}),E.set(s,o.field);else{const A=T.dimensions.map(N=>N.name.split(".").pop()),S=Re(r,A);if(S){const N=`${i}.${S.field}`;t.push({type:"dimension_not_found",message:`Dimension '${r}' not found on cube '${i}'`,field:s,suggestion:`Did you mean '${S.field}'?`,correctedValue:N}),E.set(s,N)}else t.push({type:"dimension_not_found",message:`Dimension '${r}' not found on cube '${i}'`,field:s,suggestion:`Available dimensions: ${A.slice(0,5).join(", ")}${A.length>5?"...":""}`})}}}function Be(s,e,t,E){for(const n of s){if("and"in n&&Array.isArray(n.and)){Be(n.and,e,t,E);continue}if("or"in n&&Array.isArray(n.or)){Be(n.or,e,t,E);continue}if("member"in n){const i=n.member,r=i.split(".");if(r.length!==2){t.push({type:"invalid_filter",message:`Invalid filter member format: '${i}'`,field:i});continue}const[T,R]=r,o=e.find(N=>N.name===T);if(!o){const N=e.map(O=>O.name),I=Re(T,N);I&&E.set(i,`${I.field}.${R}`),t.push({type:"cube_not_found",message:`Cube '${T}' not found in filter`,field:i,suggestion:I?`Did you mean '${I.field}'?`:void 0,correctedValue:I?`${I.field}.${R}`:void 0});continue}const A=o.dimensions.some(N=>N.name===i),S=o.measures.some(N=>N.name===i);if(!A&&!S){const N=[...o.dimensions.map(O=>O.name.split(".").pop()),...o.measures.map(O=>O.name.split(".").pop())],I=Re(R,N);if(I){const O=`${T}.${I.field}`;E.set(i,O),t.push({type:"invalid_filter",message:`Filter field '${R}' not found on cube '${T}'`,field:i,suggestion:`Did you mean '${I.field}'?`,correctedValue:O})}else t.push({type:"invalid_filter",message:`Filter field '${R}' not found on cube '${T}'`,field:i})}}}}function Ho(s,e,t,E,n){const i=s.funnel;if(i)if(i.bindingKey?typeof i.bindingKey=="string"&&j(i.bindingKey,e,t,n):t.push({type:"syntax_error",message:"funnel.bindingKey is required"}),i.timeDimension?typeof i.timeDimension=="string"&&j(i.timeDimension,e,t,n):t.push({type:"syntax_error",message:"funnel.timeDimension is required"}),!i.steps||!Array.isArray(i.steps))t.push({type:"syntax_error",message:"funnel.steps array is required"});else if(i.steps.length<2)t.push({type:"syntax_error",message:"funnel requires at least 2 steps"});else for(let r=0;r<i.steps.length;r++){const T=i.steps[r];T.name||E.push({type:"best_practice",message:`Step ${r+1} is missing a name`,suggestion:"Add descriptive names to funnel steps"}),T.filter&&"member"in T.filter&&Be([T.filter],e,t,n)}}function Yo(s,e,t,E,n){const i=s.flow;i&&(i.bindingKey?typeof i.bindingKey=="string"&&j(i.bindingKey,e,t,n):t.push({type:"syntax_error",message:"flow.bindingKey is required"}),i.timeDimension?typeof i.timeDimension=="string"&&j(i.timeDimension,e,t,n):t.push({type:"syntax_error",message:"flow.timeDimension is required"}),i.eventDimension?typeof i.eventDimension=="string"&&j(i.eventDimension,e,t,n):t.push({type:"syntax_error",message:"flow.eventDimension is required"}),i.stepsBefore===void 0&&i.stepsAfter===void 0&&E.push({type:"best_practice",message:"Neither stepsBefore nor stepsAfter specified",suggestion:"Set stepsBefore and/or stepsAfter to see event sequences"}))}function $o(s,e,t,E,n){const i=s.retention;i&&(i.bindingKey?typeof i.bindingKey=="string"&&j(i.bindingKey,e,t,n):t.push({type:"syntax_error",message:"retention.bindingKey is required"}),i.timeDimension?typeof i.timeDimension=="string"&&j(i.timeDimension,e,t,n):t.push({type:"syntax_error",message:"retention.timeDimension is required"}),i.granularity||E.push({type:"best_practice",message:"retention.granularity not specified",suggestion:'Specify granularity: "day", "week", or "month"'}),i.periods||E.push({type:"best_practice",message:"retention.periods not specified",suggestion:"Specify number of periods to analyze"}))}function wo(s,e){const t=[],E=[],n=new Map;if(s.funnel)return Ho(s,e,t,E,n),{isValid:t.length===0,errors:t,warnings:E,correctedQuery:void 0};if(s.flow)return Yo(s,e,t,E,n),{isValid:t.length===0,errors:t,warnings:E,correctedQuery:void 0};if(s.retention)return $o(s,e,t,E,n),{isValid:t.length===0,errors:t,warnings:E,correctedQuery:void 0};if(s.measures)for(const r of s.measures)Bo(r,e,t,n);if(s.dimensions)for(const r of s.dimensions)j(r,e,t,n);if(s.timeDimensions)for(const r of s.timeDimensions){j(r.dimension,e,t,n);const[T]=r.dimension.split("."),R=e.find(o=>o.name===T);if(R){const o=R.dimensions.find(A=>A.name===r.dimension);o&&o.type!=="time"&&E.push({type:"best_practice",message:`Dimension '${r.dimension}' is not a time type (it's '${o.type}')`,field:r.dimension,suggestion:'Use a dimension with type "time" for timeDimensions'})}}s.filters&&Be(s.filters,e,t,n),!s.measures?.length&&!s.dimensions?.length&&t.push({type:"syntax_error",message:"Query must have at least one measure or dimension"}),s.measures&&s.measures.length>10&&E.push({type:"performance",message:`Query has ${s.measures.length} measures, which may impact performance`,suggestion:"Consider splitting into multiple queries"}),s.dimensions&&s.dimensions.length>5&&E.push({type:"performance",message:`Query has ${s.dimensions.length} dimensions, which may produce many rows`,suggestion:"Consider adding filters or reducing dimensions"});let i;if(n.size>0){const r=JSON.parse(JSON.stringify(s));r.measures&&(r.measures=r.measures.map(T=>n.get(T)||T)),r.dimensions&&(r.dimensions=r.dimensions.map(T=>n.get(T)||T)),r.timeDimensions&&(r.timeDimensions=r.timeDimensions.map(T=>({...T,dimension:n.get(T.dimension)||T.dimension}))),i=r}return{isValid:t.length===0,errors:t,warnings:E,correctedQuery:n.size>0?i:void 0}}const fe=["2025-11-25","2025-06-18","2025-03-26"],Ss="2025-11-25";function Vo(s){const t=jo(s["mcp-protocol-version"])||Ss;return{ok:fe.includes(t),negotiated:fe.includes(t)?t:null,supported:fe}}function Wo(s){if(!s)return!1;const e=s.split(",").map(n=>n.trim().toLowerCase()),t=e.includes("text/event-stream"),E=e.includes("application/json");return t&&!E}const vo="mcp-session-id";function Xo(s){if(!s)return!1;const e=s.split(",").map(n=>n.trim().toLowerCase().split(";")[0]),t=e.some(n=>n==="application/json"),E=e.some(n=>n==="text/event-stream");return t&&E}function Ko(s,e={}){const{allowMissingOrigin:t=!0,allowedOrigins:E}=e;if(!s)return t?{valid:!0}:{valid:!1,reason:"Origin header is required"};if(!E||E.length===0)return{valid:!0};let n;try{n=new URL(s)}catch{return{valid:!1,reason:"Invalid Origin header format"}}return E.map(r=>{try{return new URL(r).origin}catch{return r}}).includes(n.origin)?{valid:!0}:{valid:!1,reason:"Origin not in allowed list"}}function xo(s,e,t){const E=[];return e&&E.push(`id: ${e}`),t&&t>0&&E.push(`retry: ${t}`),E.push("event: message"),E.push(`data: ${JSON.stringify(s)}`),E.push(""),E.join(`
|
|
215
|
-
`)}function Jo(s,e,t,E){return{jsonrpc:"2.0",id:s??null,error:{code:e,message:t,...E!==void 0?{data:E}:{}}}}function Qo(s,e){return{jsonrpc:"2.0",id:s??null,result:e}}function ko(s){if(!s||typeof s!="object")return null;const e=s;return e.jsonrpc!=="2.0"||typeof e.method!="string"?null:{jsonrpc:"2.0",method:e.method,id:e.id,params:e.params}}async function qo(s,e,t){const{semanticLayer:E,extractSecurityContext:n,rawRequest:i,rawResponse:r}=t,T=t.prompts??Is,R=t.resources??Os;switch(s){case"initialize":{const o=e?.protocolVersion;let A;return o&&fe.includes(o)?A=o:A=Ss,{protocolVersion:A,capabilities:{tools:{listChanged:!1},resources:{listChanged:!1},prompts:{listChanged:!1},sampling:{}},sessionId:Ns(),serverInfo:{name:"drizzle-cube",version:process.env
|
|
215
|
+
`)}function Jo(s,e,t,E){return{jsonrpc:"2.0",id:s??null,error:{code:e,message:t,...E!==void 0?{data:E}:{}}}}function Qo(s,e){return{jsonrpc:"2.0",id:s??null,result:e}}function ko(s){if(!s||typeof s!="object")return null;const e=s;return e.jsonrpc!=="2.0"||typeof e.method!="string"?null:{jsonrpc:"2.0",method:e.method,id:e.id,params:e.params}}async function qo(s,e,t){const{semanticLayer:E,extractSecurityContext:n,rawRequest:i,rawResponse:r}=t,T=t.prompts??Is,R=t.resources??Os;switch(s){case"initialize":{const o=e?.protocolVersion;let A;return o&&fe.includes(o)?A=o:A=Ss,{protocolVersion:A,capabilities:{tools:{listChanged:!1},resources:{listChanged:!1},prompts:{listChanged:!1},sampling:{}},sessionId:Ns(),serverInfo:{name:"drizzle-cube",version:typeof process<"u"?process.env?.npm_package_version||"dev":"worker"}}}case"list_tools":case"tools/list":return{tools:zo(),nextCursor:""};case"call_tool":case"tools/call":return eR(e,t);case"resources/list":return{resources:R.map(({uri:o,name:A,description:S,mimeType:N})=>({uri:o,name:A,description:S,mimeType:N})),nextCursor:""};case"resources/templates/list":return{resourceTemplates:[],nextCursor:""};case"resources/read":{const o=e?.uri,A=R.find(S=>S.uri===o)||R[0];if(!A)throw x(-32602,"resource not found");return{contents:[{uri:A.uri,mimeType:A.mimeType,text:A.text}]}}case"prompts/list":return{prompts:T.map(({name:o,description:A})=>({name:o,description:A})),nextCursor:""};case"ping":return{};case"notifications/initialized":return{};case"prompts/get":{const o=e?.name,A=T.find(S=>S.name===o)||T[0];if(!A)throw x(-32602,"prompt not found");return{name:A.name,description:A.description,messages:A.messages}}case"discover":return Ut(E,e||{});case"suggest":{const o=e||{};if(!o.naturalLanguage)throw x(-32602,"naturalLanguage is required");return ht(E,o)}case"validate":{const o=e||{};if(!o.query)throw x(-32602,"query is required");return gt(E,o)}case"load":{const o=e||{};if(!o.query)throw x(-32602,"query is required");const A=await n(i,r);return Gt(E,A,o)}default:throw x(-32601,`Unknown MCP method: ${s}`)}}function x(s,e,t){const E=new Error(e);return E.code=s,E}function jo(s){return s?Array.isArray(s)?s[0]||null:s:null}function Zo(s){return s.id===void 0||s.id===null}function Ns(){return`evt-${Ts()}`}function zo(){return[{name:"discover",description:"Find relevant cubes based on topic/intent",inputSchema:{type:"object",properties:{topic:{type:"string"},intent:{type:"string"},limit:{type:"number"},minScore:{type:"number"}}}},{name:"suggest",description:"Generate a query from natural language",inputSchema:{type:"object",required:["naturalLanguage"],properties:{naturalLanguage:{type:"string"},cube:{type:"string"}}}},{name:"validate",description:"Validate a query with helpful corrections",inputSchema:{type:"object",required:["query"],properties:{query:{type:"object"}}}},{name:"load",description:"Execute a query and return results",inputSchema:{type:"object",required:["query"],properties:{query:{type:"object"}}}}]}async function eR(s,e){const{semanticLayer:t,extractSecurityContext:E,rawRequest:n,rawResponse:i}=e,r=s||{};if(!r.name)throw x(-32602,"name is required for tools/call");const T=r.arguments;switch(r.name){case"discover":return Le(await Ut(t,T||{}));case"suggest":{const R=T||{};if(!R.naturalLanguage)throw x(-32602,"naturalLanguage is required");return Le(await ht(t,R))}case"validate":{const R=T||{};if(!R.query)throw x(-32602,"query is required");return Le(await gt(t,R))}case"load":{const R=T||{};if(!R.query)throw x(-32602,"query is required");const o=await E(n,i);return Le(await Gt(t,o,R))}default:throw x(-32601,`Unknown tool: ${r.name}`)}}function Le(s){return{content:[{type:"text",text:typeof s=="string"?s:JSON.stringify(s)}],isError:!1}}const Is=[{name:"drizzle-cube-mcp-guide",description:"How to use drizzle-cube MCP tools to generate and run queries",messages:[{role:"user",content:{type:"text",text:["You are an analyst agent using drizzle-cube MCP.","Workflow:","1) Call tools/list to confirm tools.","2) tools/call name=discover {topic|intent} to find cubes.","3) tools/call name=suggest {naturalLanguage, cube?} to get a draft query.","4) tools/call name=validate {query} to fix schema issues.","5) tools/call name=load {query} to execute.","Include security context headers if required by the host.","JSON only; do not hallucinate cube/field names—use discover first.","","Query shapes:","- Regular: { measures, dimensions, filters[], timeDimensions[], order, limit, offset }","- Funnel: { funnel: { bindingKey, timeDimension, steps[], includeTimeMetrics? } }","- Flow: { flow: { bindingKey, eventDimension, steps?, window? } }","- Retention: { retention: { bindingKey, timeDimension, periods, granularity, retentionType, breakdownDimensions } }","Filters must be flat arrays of { member, operator, values }; avoid nested arrays.","Place time filters on step 0 for funnels; use inDateRange only there.","","Time handling:",'- If the user asks for a relative window (e.g., "last 3 months"), add ONLY an inDateRange filter on the time dimension (do NOT add timeDimensions unless they also ask for grouping).','- If the user asks for grouping (e.g., "by month", "per week"), add a timeDimensions entry with granularity ("month", "week", "day") on the same time dimension.',"- You can use both: one inDateRange filter AND one timeDimensions entry with granularity when both are implied."].join(`
|
|
216
216
|
`)}}]},{name:"drizzle-cube-query-rules",description:"Key generation rules aligned with Gemini single-step prompt",messages:[{role:"user",content:{type:"text",text:["Rules (keep JSON only):","- Use only measures/dimensions/timeDimensions from schema.","- timeDimensions: include granularity when grouping; use inDateRange filter for relative windows; combine when both requested.","- Funnel detection keywords: funnel, conversion, journey, drop off, step by step; use funnel format only if eventStream metadata exists.","- Funnel rules: bindingKey/timeDimension from cube metadata; include time filter on step 0 (default last 6 months) using inDateRange; steps ordered; flat filters.","- Chart selection: line/area for time trends; bar for categories; scatter for 2-measure correlations; bubble for 3-measure correlations; funnel for funnels.","- Correlation keywords (correlation/relationship/vs/compare) -> scatter/bubble, never line.","- Prefer .name fields over .id; avoid Id dimensions unless requested.","- Filters: flat array of {member, operator, values}; operators equals, notEquals, contains, notContains, gt, gte, lt, lte, inDateRange, set, notSet."].join(`
|
|
217
217
|
`)}}]}],Os=[{uri:"drizzle-cube://quickstart",name:"Drizzle Cube MCP Quickstart",description:"Minimal guide for using discover/suggest/validate/load",mimeType:"text/markdown",text:["# Drizzle Cube MCP Quickstart","","Tools:","- discover: { topic?, intent?, limit?, minScore? } → cubes list","- suggest: { naturalLanguage, cube? } → draft query","- validate: { query } → corrected query + issues","- load: { query } → data + annotation","","Recommended flow:","1) tools/list",'2) tools/call name=discover intent="<goal>"','3) tools/call name=suggest naturalLanguage="<goal>"',"4) tools/call name=validate query=<from suggest>","5) tools/call name=load query=<validated>","","Query shapes supported:","- regular Cube.js-style query { measures, dimensions, filters, timeDimensions, order, limit, offset }","- funnel { bindingKey, timeDimension, steps[], includeTimeMetrics? }","- flow { bindingKey, eventDimension, steps?, window? }","- retention { bindingKey, timeDimension, periods, granularity, retentionType, breakdownDimensions }","","Filter rules: flat arrays of { member, operator, values }; do not nest arrays."].join(`
|
|
218
218
|
`)},{uri:"drizzle-cube://query-shapes",name:"Query Shapes Reference",description:"Detailed schema examples for regular, funnel, flow, and retention queries",mimeType:"text/markdown",text:["# Query Shapes","","## Regular query","```json","{",' "measures": ["Sales.count"],',' "dimensions": ["Sales.channel"],',' "filters": [ { "member": "Sales.status", "operator": "equals", "values": ["paid"] } ],',' "timeDimensions": [ { "dimension": "Sales.createdAt", "dateRange": "last 30 days", "granularity": "day" } ],',' "order": { "Sales.createdAt": "asc" },',' "limit": 500',"}","```","","## Funnel","```json","{",' "funnel": {',' "bindingKey": "Events.userId",',' "timeDimension": "Events.timestamp",',' "steps": [',' { "name": "Signup", "filter": [{ "member": "Events.eventType", "operator": "equals", "values": ["signup"] }] },',' { "name": "Purchase", "filter": [{ "member": "Events.eventType", "operator": "equals", "values": ["purchase"] }] }'," ],",' "includeTimeMetrics": true'," }","}","```","","## Flow","```json","{",' "flow": {',' "bindingKey": "Events.sessionId",',' "eventDimension": "Events.eventType",',' "steps": ["view", "add_to_cart", "checkout"],',' "window": { "unit": "minute", "value": 30 }'," }","}","```","","## Retention","```json","{",' "retention": {',' "bindingKey": "Users.id",',' "timeDimension": "Events.timestamp",',' "periods": 8,',' "granularity": "week",',' "retentionType": "rolling",',' "breakdownDimensions": ["Events.country"]'," }","}","```","","### Filter rules","- Always a flat array of filter objects: [{ member, operator, values }]","- For funnels, put time filter (inDateRange) only on step 0","- Operators: equals, notEquals, inDateRange, gt, gte, lt, lte, contains, notContains, set, notSet","","### Time handling",'- Relative ranges ("last 3 months") -> add ONLY an inDateRange filter on the time dimension (do NOT add timeDimensions unless grouping is requested).','- Grouping ("by month/week/day") -> add timeDimensions entry with granularity.',"- Both can be combined: inDateRange filter + timeDimensions granularity."].join(`
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("next/server"),r=require("../mcp-transport-weiPD7j5.cjs");function x(o){const{cubes:a,drizzle:n,schema:i,engineType:d,cache:c}=o;if(!a||a.length===0)throw new Error("At least one cube must be provided in the cubes array");const s=new r.SemanticLayerCompiler({drizzle:n,schema:i,engineType:d,cache:c});return a.forEach(e=>{s.registerCube(e)}),s}function y(o,a){const n=o.headers.get("origin"),i={};return a.origin&&(typeof a.origin=="string"?i["Access-Control-Allow-Origin"]=a.origin:Array.isArray(a.origin)?n&&a.origin.includes(n)&&(i["Access-Control-Allow-Origin"]=n):typeof a.origin=="function"&&n&&a.origin(n)&&(i["Access-Control-Allow-Origin"]=n)),a.methods&&(i["Access-Control-Allow-Methods"]=a.methods.join(", ")),a.allowedHeaders&&(i["Access-Control-Allow-Headers"]=a.allowedHeaders.join(", ")),a.credentials&&(i["Access-Control-Allow-Credentials"]="true"),i}function _(o){return async function(n){const i=y(n,o);return new Response(null,{status:200,headers:i})}}function P(o){const{extractSecurityContext:a,cors:n}=o,i=x(o);return async function(c,s){try{let e;if(c.method==="POST"){const R=await c.json();e=R.query||R}else if(c.method==="GET"){const R=c.nextUrl.searchParams.get("query");if(!R)return t.NextResponse.json(r.formatErrorResponse("Query parameter is required",400),{status:400});try{e=JSON.parse(R)}catch{return t.NextResponse.json(r.formatErrorResponse("Invalid JSON in query parameter",400),{status:400})}}else return t.NextResponse.json(r.formatErrorResponse("Method not allowed",405),{status:405});const l=await a(c,s),f=i.validateQuery(e);if(!f.isValid)return t.NextResponse.json(r.formatErrorResponse(`Query validation failed: ${f.errors.join(", ")}`,400),{status:400});const u=c.headers.get("x-cache-control")==="no-cache",p=await i.executeMultiCubeQuery(e,l,{skipCache:u}),E=r.formatCubeResponse(e,p,i);return t.NextResponse.json(E,{headers:n?y(c,n):{}})}catch(e){return process.env.NODE_ENV!=="test"&&console.error("Next.js load handler error:",e),t.NextResponse.json(r.formatErrorResponse(e instanceof Error?e.message:"Query execution failed",500),{status:500})}}}function M(o){const{cors:a}=o,n=x(o);return async function(d,c){try{const s=n.getMetadata(),e=r.formatMetaResponse(s);return t.NextResponse.json(e,{headers:a?y(d,a):{}})}catch(s){return process.env.NODE_ENV!=="test"&&console.error("Next.js meta handler error:",s),t.NextResponse.json(r.formatErrorResponse(s instanceof Error?s.message:"Failed to fetch metadata",500),{status:500})}}}function T(o){const{extractSecurityContext:a,cors:n}=o,i=x(o);return async function(c,s){try{let e;if(c.method==="POST"){const j=await c.json();e=j.query||j}else if(c.method==="GET"){const j=c.nextUrl.searchParams.get("query");if(!j)return t.NextResponse.json(r.formatErrorResponse("Query parameter is required",400),{status:400});try{e=JSON.parse(j)}catch{return t.NextResponse.json(r.formatErrorResponse("Invalid JSON in query parameter",400),{status:400})}}else return t.NextResponse.json(r.formatErrorResponse("Method not allowed",405),{status:405});const l=await a(c,s),f=i.validateQuery(e);if(!f.isValid)return t.NextResponse.json(r.formatErrorResponse(`Query validation failed: ${f.errors.join(", ")}`,400),{status:400});const u=e.measures?.[0]||e.dimensions?.[0];if(!u)return t.NextResponse.json(r.formatErrorResponse("No measures or dimensions specified",400),{status:400});const p=u.split(".")[0],E=await i.generateSQL(p,e,l),R=r.formatSqlResponse(e,E);return t.NextResponse.json(R,{headers:n?y(c,n):{}})}catch(e){return process.env.NODE_ENV!=="test"&&console.error("Next.js SQL handler error:",e),t.NextResponse.json(r.formatErrorResponse(e instanceof Error?e.message:"SQL generation failed",500),{status:500})}}}function L(o){const{extractSecurityContext:a,cors:n}=o,i=x(o);return async function(c,s){try{let e;if(c.method==="POST"){const u=await c.json();e=u.query||u}else if(c.method==="GET"){const u=c.nextUrl.searchParams.get("query");if(!u)return t.NextResponse.json({error:"Query parameter is required",valid:!1},{status:400});try{e=JSON.parse(u)}catch{return t.NextResponse.json({error:"Invalid JSON in query parameter",valid:!1},{status:400})}}else return t.NextResponse.json({error:"Method not allowed",valid:!1},{status:405});const l=await a(c,s),f=await r.handleDryRun(e,l,i);return t.NextResponse.json(f,{headers:n?y(c,n):{}})}catch(e){return process.env.NODE_ENV!=="test"&&console.error("Next.js dry-run handler error:",e),t.NextResponse.json({error:e instanceof Error?e.message:"Dry-run validation failed",valid:!1},{status:400})}}}function D(o){const{extractSecurityContext:a,cors:n}=o,i=x(o);return async function(c,s){try{if(c.method!=="POST")return t.NextResponse.json(r.formatErrorResponse("Method not allowed - use POST",405),{status:405});const e=await c.json(),{queries:l}=e;if(!l||!Array.isArray(l))return t.NextResponse.json(r.formatErrorResponse('Request body must contain a "queries" array',400),{status:400});if(l.length===0)return t.NextResponse.json(r.formatErrorResponse("Queries array cannot be empty",400),{status:400});const f=await a(c,s),u=c.headers.get("x-cache-control")==="no-cache",p=await r.handleBatchRequest(l,f,i,{skipCache:u});return t.NextResponse.json(p,{headers:n?y(c,n):{}})}catch(e){return process.env.NODE_ENV!=="test"&&console.error("Next.js batch handler error:",e),t.NextResponse.json(r.formatErrorResponse(e instanceof Error?e.message:"Batch execution failed",500),{status:500})}}}function A(o){const{extractSecurityContext:a,cors:n}=o,i=x(o);return async function(c,s){try{if(c.method!=="POST")return t.NextResponse.json({error:"Method not allowed"},{status:405});const e=await c.json(),l=e.query||e,f=e.options||{},u=await a(c,s),p=i.validateQuery(l);if(!p.isValid)return t.NextResponse.json({error:`Query validation failed: ${p.errors.join(", ")}`},{status:400});const E=await i.explainQuery(l,u,f);return t.NextResponse.json(E,{headers:n?y(c,n):{}})}catch(e){return process.env.NODE_ENV!=="test"&&console.error("Next.js explain handler error:",e),t.NextResponse.json({error:e instanceof Error?e.message:"Explain query failed"},{status:500})}}}function I(o){const{cors:a}=o,n=x(o);return async function(d,c){try{if(d.method!=="POST")return t.NextResponse.json(r.formatErrorResponse("Method not allowed - use POST",405),{status:405});const s=await d.json(),e=await r.handleDiscover(n,s);return t.NextResponse.json(e,{headers:a?y(d,a):{}})}catch(s){return process.env.NODE_ENV!=="test"&&console.error("Next.js discover handler error:",s),t.NextResponse.json(r.formatErrorResponse(s instanceof Error?s.message:"Discovery failed",500),{status:500})}}}function J(o){const{cors:a}=o,n=x(o);return async function(d,c){try{if(d.method!=="POST")return t.NextResponse.json(r.formatErrorResponse("Method not allowed - use POST",405),{status:405});const s=await d.json();if(!s.naturalLanguage)return t.NextResponse.json(r.formatErrorResponse("naturalLanguage field is required",400),{status:400});const e=await r.handleSuggest(n,s);return t.NextResponse.json(e,{headers:a?y(d,a):{}})}catch(s){return process.env.NODE_ENV!=="test"&&console.error("Next.js suggest handler error:",s),t.NextResponse.json(r.formatErrorResponse(s instanceof Error?s.message:"Query suggestion failed",500),{status:500})}}}function z(o){const{cors:a}=o,n=x(o);return async function(d,c){try{if(d.method!=="POST")return t.NextResponse.json(r.formatErrorResponse("Method not allowed - use POST",405),{status:405});const s=await d.json();if(!s.query)return t.NextResponse.json(r.formatErrorResponse("query field is required",400),{status:400});const e=await r.handleValidate(n,s);return t.NextResponse.json(e,{headers:a?y(d,a):{}})}catch(s){return process.env.NODE_ENV!=="test"&&console.error("Next.js validate handler error:",s),t.NextResponse.json(r.formatErrorResponse(s instanceof Error?s.message:"Query validation failed",500),{status:500})}}}function k(o){const{extractSecurityContext:a,cors:n}=o,i=x(o);return async function(c,s){try{if(c.method!=="POST")return t.NextResponse.json(r.formatErrorResponse("Method not allowed - use POST",405),{status:405});const e=await c.json();if(!e.query)return t.NextResponse.json(r.formatErrorResponse("query field is required",400),{status:400});const l=await a(c,s),f=await r.handleLoad(i,l,e);return t.NextResponse.json(f,{headers:n?y(c,n):{}})}catch(e){return process.env.NODE_ENV!=="test"&&console.error("Next.js MCP load handler error:",e),t.NextResponse.json(r.formatErrorResponse(e instanceof Error?e.message:"Query execution failed",500),{status:500})}}}function Q(o){const{extractSecurityContext:a,cors:n,mcp:i={enabled:!0}}=o,d=x(o);return async function(s){if(s.method==="DELETE")return t.NextResponse.json({error:"Session termination not supported"},{status:405});if(s.method==="GET"){const m=new TextEncoder,w=r.primeEventId(),N=new ReadableStream({start(h){h.enqueue(m.encode(r.serializeSseEvent({jsonrpc:"2.0",method:"mcp/ready",params:{protocol:"streamable-http"}},w,15e3)))}}),v=new Headers({"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"});if(n){const h=y(s,n);Object.entries(h).forEach(([S,C])=>v.set(S,C))}return new t.NextResponse(N,{status:200,headers:v})}if(s.method!=="POST")return t.NextResponse.json(r.formatErrorResponse("Method not allowed - use POST",405),{status:405});const e=r.validateOriginHeader(s.headers.get("origin"),i.allowedOrigins?{allowedOrigins:i.allowedOrigins}:{});if(!e.valid)return t.NextResponse.json(r.buildJsonRpcError(null,-32600,e.reason),{status:403});const l=s.headers.get("accept");if(!r.validateAcceptHeader(l))return t.NextResponse.json(r.buildJsonRpcError(null,-32600,"Accept header must include both application/json and text/event-stream"),{status:400});const f=r.negotiateProtocol(Object.fromEntries(s.headers.entries()));if(!f.ok)return t.NextResponse.json({error:"Unsupported MCP protocol version",supported:f.supported},{status:426});let u=null;try{u=await s.json()}catch{u=null}const p=r.parseJsonRpc(u);if(!p)return t.NextResponse.json(r.buildJsonRpcError(null,-32600,"Invalid JSON-RPC 2.0 request"),{status:400});const E=r.wantsEventStream(l),R=p.method==="initialize",j=(m,w=200,N={})=>t.NextResponse.json(m,{status:w,headers:{...n?y(s,n):{},...N}});try{const m=await r.dispatchMcpMethod(p.method,p.params,{semanticLayer:d,extractSecurityContext:h=>a(h),rawRequest:s,rawResponse:null});if(r.isNotification(p))return new t.NextResponse(null,{status:202});const w=R&&m&&typeof m=="object"&&"sessionId"in m?m.sessionId:void 0,N={};w&&(N[r.MCP_SESSION_ID_HEADER]=w);const v=r.buildJsonRpcResult(p.id??null,m);if(E){const h=new TextEncoder,S=r.primeEventId(),C=new ReadableStream({start(g){g.enqueue(h.encode(`id: ${S}
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("next/server"),r=require("../mcp-transport-xS_s8WBZ.cjs");function x(o){const{cubes:a,drizzle:n,schema:i,engineType:d,cache:c}=o;if(!a||a.length===0)throw new Error("At least one cube must be provided in the cubes array");const s=new r.SemanticLayerCompiler({drizzle:n,schema:i,engineType:d,cache:c});return a.forEach(e=>{s.registerCube(e)}),s}function y(o,a){const n=o.headers.get("origin"),i={};return a.origin&&(typeof a.origin=="string"?i["Access-Control-Allow-Origin"]=a.origin:Array.isArray(a.origin)?n&&a.origin.includes(n)&&(i["Access-Control-Allow-Origin"]=n):typeof a.origin=="function"&&n&&a.origin(n)&&(i["Access-Control-Allow-Origin"]=n)),a.methods&&(i["Access-Control-Allow-Methods"]=a.methods.join(", ")),a.allowedHeaders&&(i["Access-Control-Allow-Headers"]=a.allowedHeaders.join(", ")),a.credentials&&(i["Access-Control-Allow-Credentials"]="true"),i}function _(o){return async function(n){const i=y(n,o);return new Response(null,{status:200,headers:i})}}function P(o){const{extractSecurityContext:a,cors:n}=o,i=x(o);return async function(c,s){try{let e;if(c.method==="POST"){const R=await c.json();e=R.query||R}else if(c.method==="GET"){const R=c.nextUrl.searchParams.get("query");if(!R)return t.NextResponse.json(r.formatErrorResponse("Query parameter is required",400),{status:400});try{e=JSON.parse(R)}catch{return t.NextResponse.json(r.formatErrorResponse("Invalid JSON in query parameter",400),{status:400})}}else return t.NextResponse.json(r.formatErrorResponse("Method not allowed",405),{status:405});const l=await a(c,s),f=i.validateQuery(e);if(!f.isValid)return t.NextResponse.json(r.formatErrorResponse(`Query validation failed: ${f.errors.join(", ")}`,400),{status:400});const u=c.headers.get("x-cache-control")==="no-cache",p=await i.executeMultiCubeQuery(e,l,{skipCache:u}),E=r.formatCubeResponse(e,p,i);return t.NextResponse.json(E,{headers:n?y(c,n):{}})}catch(e){return process.env.NODE_ENV!=="test"&&console.error("Next.js load handler error:",e),t.NextResponse.json(r.formatErrorResponse(e instanceof Error?e.message:"Query execution failed",500),{status:500})}}}function M(o){const{cors:a}=o,n=x(o);return async function(d,c){try{const s=n.getMetadata(),e=r.formatMetaResponse(s);return t.NextResponse.json(e,{headers:a?y(d,a):{}})}catch(s){return process.env.NODE_ENV!=="test"&&console.error("Next.js meta handler error:",s),t.NextResponse.json(r.formatErrorResponse(s instanceof Error?s.message:"Failed to fetch metadata",500),{status:500})}}}function T(o){const{extractSecurityContext:a,cors:n}=o,i=x(o);return async function(c,s){try{let e;if(c.method==="POST"){const j=await c.json();e=j.query||j}else if(c.method==="GET"){const j=c.nextUrl.searchParams.get("query");if(!j)return t.NextResponse.json(r.formatErrorResponse("Query parameter is required",400),{status:400});try{e=JSON.parse(j)}catch{return t.NextResponse.json(r.formatErrorResponse("Invalid JSON in query parameter",400),{status:400})}}else return t.NextResponse.json(r.formatErrorResponse("Method not allowed",405),{status:405});const l=await a(c,s),f=i.validateQuery(e);if(!f.isValid)return t.NextResponse.json(r.formatErrorResponse(`Query validation failed: ${f.errors.join(", ")}`,400),{status:400});const u=e.measures?.[0]||e.dimensions?.[0];if(!u)return t.NextResponse.json(r.formatErrorResponse("No measures or dimensions specified",400),{status:400});const p=u.split(".")[0],E=await i.generateSQL(p,e,l),R=r.formatSqlResponse(e,E);return t.NextResponse.json(R,{headers:n?y(c,n):{}})}catch(e){return process.env.NODE_ENV!=="test"&&console.error("Next.js SQL handler error:",e),t.NextResponse.json(r.formatErrorResponse(e instanceof Error?e.message:"SQL generation failed",500),{status:500})}}}function L(o){const{extractSecurityContext:a,cors:n}=o,i=x(o);return async function(c,s){try{let e;if(c.method==="POST"){const u=await c.json();e=u.query||u}else if(c.method==="GET"){const u=c.nextUrl.searchParams.get("query");if(!u)return t.NextResponse.json({error:"Query parameter is required",valid:!1},{status:400});try{e=JSON.parse(u)}catch{return t.NextResponse.json({error:"Invalid JSON in query parameter",valid:!1},{status:400})}}else return t.NextResponse.json({error:"Method not allowed",valid:!1},{status:405});const l=await a(c,s),f=await r.handleDryRun(e,l,i);return t.NextResponse.json(f,{headers:n?y(c,n):{}})}catch(e){return process.env.NODE_ENV!=="test"&&console.error("Next.js dry-run handler error:",e),t.NextResponse.json({error:e instanceof Error?e.message:"Dry-run validation failed",valid:!1},{status:400})}}}function D(o){const{extractSecurityContext:a,cors:n}=o,i=x(o);return async function(c,s){try{if(c.method!=="POST")return t.NextResponse.json(r.formatErrorResponse("Method not allowed - use POST",405),{status:405});const e=await c.json(),{queries:l}=e;if(!l||!Array.isArray(l))return t.NextResponse.json(r.formatErrorResponse('Request body must contain a "queries" array',400),{status:400});if(l.length===0)return t.NextResponse.json(r.formatErrorResponse("Queries array cannot be empty",400),{status:400});const f=await a(c,s),u=c.headers.get("x-cache-control")==="no-cache",p=await r.handleBatchRequest(l,f,i,{skipCache:u});return t.NextResponse.json(p,{headers:n?y(c,n):{}})}catch(e){return process.env.NODE_ENV!=="test"&&console.error("Next.js batch handler error:",e),t.NextResponse.json(r.formatErrorResponse(e instanceof Error?e.message:"Batch execution failed",500),{status:500})}}}function A(o){const{extractSecurityContext:a,cors:n}=o,i=x(o);return async function(c,s){try{if(c.method!=="POST")return t.NextResponse.json({error:"Method not allowed"},{status:405});const e=await c.json(),l=e.query||e,f=e.options||{},u=await a(c,s),p=i.validateQuery(l);if(!p.isValid)return t.NextResponse.json({error:`Query validation failed: ${p.errors.join(", ")}`},{status:400});const E=await i.explainQuery(l,u,f);return t.NextResponse.json(E,{headers:n?y(c,n):{}})}catch(e){return process.env.NODE_ENV!=="test"&&console.error("Next.js explain handler error:",e),t.NextResponse.json({error:e instanceof Error?e.message:"Explain query failed"},{status:500})}}}function I(o){const{cors:a}=o,n=x(o);return async function(d,c){try{if(d.method!=="POST")return t.NextResponse.json(r.formatErrorResponse("Method not allowed - use POST",405),{status:405});const s=await d.json(),e=await r.handleDiscover(n,s);return t.NextResponse.json(e,{headers:a?y(d,a):{}})}catch(s){return process.env.NODE_ENV!=="test"&&console.error("Next.js discover handler error:",s),t.NextResponse.json(r.formatErrorResponse(s instanceof Error?s.message:"Discovery failed",500),{status:500})}}}function J(o){const{cors:a}=o,n=x(o);return async function(d,c){try{if(d.method!=="POST")return t.NextResponse.json(r.formatErrorResponse("Method not allowed - use POST",405),{status:405});const s=await d.json();if(!s.naturalLanguage)return t.NextResponse.json(r.formatErrorResponse("naturalLanguage field is required",400),{status:400});const e=await r.handleSuggest(n,s);return t.NextResponse.json(e,{headers:a?y(d,a):{}})}catch(s){return process.env.NODE_ENV!=="test"&&console.error("Next.js suggest handler error:",s),t.NextResponse.json(r.formatErrorResponse(s instanceof Error?s.message:"Query suggestion failed",500),{status:500})}}}function z(o){const{cors:a}=o,n=x(o);return async function(d,c){try{if(d.method!=="POST")return t.NextResponse.json(r.formatErrorResponse("Method not allowed - use POST",405),{status:405});const s=await d.json();if(!s.query)return t.NextResponse.json(r.formatErrorResponse("query field is required",400),{status:400});const e=await r.handleValidate(n,s);return t.NextResponse.json(e,{headers:a?y(d,a):{}})}catch(s){return process.env.NODE_ENV!=="test"&&console.error("Next.js validate handler error:",s),t.NextResponse.json(r.formatErrorResponse(s instanceof Error?s.message:"Query validation failed",500),{status:500})}}}function k(o){const{extractSecurityContext:a,cors:n}=o,i=x(o);return async function(c,s){try{if(c.method!=="POST")return t.NextResponse.json(r.formatErrorResponse("Method not allowed - use POST",405),{status:405});const e=await c.json();if(!e.query)return t.NextResponse.json(r.formatErrorResponse("query field is required",400),{status:400});const l=await a(c,s),f=await r.handleLoad(i,l,e);return t.NextResponse.json(f,{headers:n?y(c,n):{}})}catch(e){return process.env.NODE_ENV!=="test"&&console.error("Next.js MCP load handler error:",e),t.NextResponse.json(r.formatErrorResponse(e instanceof Error?e.message:"Query execution failed",500),{status:500})}}}function Q(o){const{extractSecurityContext:a,cors:n,mcp:i={enabled:!0}}=o,d=x(o);return async function(s){if(s.method==="DELETE")return t.NextResponse.json({error:"Session termination not supported"},{status:405});if(s.method==="GET"){const m=new TextEncoder,w=r.primeEventId(),N=new ReadableStream({start(h){h.enqueue(m.encode(r.serializeSseEvent({jsonrpc:"2.0",method:"mcp/ready",params:{protocol:"streamable-http"}},w,15e3)))}}),v=new Headers({"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"});if(n){const h=y(s,n);Object.entries(h).forEach(([S,C])=>v.set(S,C))}return new t.NextResponse(N,{status:200,headers:v})}if(s.method!=="POST")return t.NextResponse.json(r.formatErrorResponse("Method not allowed - use POST",405),{status:405});const e=r.validateOriginHeader(s.headers.get("origin"),i.allowedOrigins?{allowedOrigins:i.allowedOrigins}:{});if(!e.valid)return t.NextResponse.json(r.buildJsonRpcError(null,-32600,e.reason),{status:403});const l=s.headers.get("accept");if(!r.validateAcceptHeader(l))return t.NextResponse.json(r.buildJsonRpcError(null,-32600,"Accept header must include both application/json and text/event-stream"),{status:400});const f=r.negotiateProtocol(Object.fromEntries(s.headers.entries()));if(!f.ok)return t.NextResponse.json({error:"Unsupported MCP protocol version",supported:f.supported},{status:426});let u=null;try{u=await s.json()}catch{u=null}const p=r.parseJsonRpc(u);if(!p)return t.NextResponse.json(r.buildJsonRpcError(null,-32600,"Invalid JSON-RPC 2.0 request"),{status:400});const E=r.wantsEventStream(l),R=p.method==="initialize",j=(m,w=200,N={})=>t.NextResponse.json(m,{status:w,headers:{...n?y(s,n):{},...N}});try{const m=await r.dispatchMcpMethod(p.method,p.params,{semanticLayer:d,extractSecurityContext:h=>a(h),rawRequest:s,rawResponse:null});if(r.isNotification(p))return new t.NextResponse(null,{status:202});const w=R&&m&&typeof m=="object"&&"sessionId"in m?m.sessionId:void 0,N={};w&&(N[r.MCP_SESSION_ID_HEADER]=w);const v=r.buildJsonRpcResult(p.id??null,m);if(E){const h=new TextEncoder,S=r.primeEventId(),C=new ReadableStream({start(g){g.enqueue(h.encode(`id: ${S}
|
|
2
2
|
|
|
3
3
|
`)),g.enqueue(h.encode(r.serializeSseEvent(v,S))),g.close()}}),b=new Headers({"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive",...N});if(n){const g=y(s,n);Object.entries(g).forEach(([H,O])=>b.set(H,O))}return new t.NextResponse(C,{status:200,headers:b})}return j(v,200,N)}catch(m){if(r.isNotification(p))return process.env.NODE_ENV!=="test"&&console.error("Next.js MCP notification processing error:",m),new t.NextResponse(null,{status:202});process.env.NODE_ENV!=="test"&&console.error("Next.js MCP RPC handler error:",m);const w=m?.code??-32603,N=m?.data,v=m.message||"MCP request failed",h=r.buildJsonRpcError(p.id??null,w,v,N);if(E){const S=new TextEncoder,C=r.primeEventId(),b=new ReadableStream({start(H){H.enqueue(S.encode(`id: ${C}
|
|
4
4
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NextResponse as t } from "next/server";
|
|
2
|
-
import { o as i, f as A, a as Q, b as _, c as V, h as I, q as J, r as k, t as z, u as $, m as T, s as M, v as q, d as P, e as G, n as U, p as B, w as F, g as K, k as L, M as W, l as X, S as Y } from "../mcp-transport-
|
|
2
|
+
import { o as i, f as A, a as Q, b as _, c as V, h as I, q as J, r as k, t as z, u as $, m as T, s as M, v as q, d as P, e as G, n as U, p as B, w as F, g as K, k as L, M as W, l as X, S as Y } from "../mcp-transport-COtZVd4-.js";
|
|
3
3
|
function p(s) {
|
|
4
4
|
const { cubes: a, drizzle: n, schema: c, engineType: d, cache: o } = s;
|
|
5
5
|
if (!a || a.length === 0)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "drizzle-cube",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.18",
|
|
4
4
|
"description": "Drizzle ORM-first semantic layer with Cube.js compatibility. Type-safe analytics and dashboards with SQL injection protection.",
|
|
5
5
|
"main": "./dist/server/index.js",
|
|
6
6
|
"types": "./dist/server/index.d.ts",
|