drizzle-cube 0.4.34 → 0.4.36

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.
Files changed (69) hide show
  1. package/README.md +1 -1
  2. package/dist/adapters/express/index.cjs +1 -1
  3. package/dist/adapters/express/index.d.ts +7 -1
  4. package/dist/adapters/express/index.js +5 -4
  5. package/dist/adapters/fastify/index.cjs +1 -1
  6. package/dist/adapters/fastify/index.d.ts +7 -1
  7. package/dist/adapters/fastify/index.js +5 -4
  8. package/dist/adapters/{handler-ClgB__a-.cjs → handler-DzUX7CBs.cjs} +1 -1
  9. package/dist/adapters/{handler-rPpxuopb.js → handler-J55KQKe5.js} +1 -1
  10. package/dist/adapters/hono/index.cjs +1 -1
  11. package/dist/adapters/hono/index.d.ts +7 -1
  12. package/dist/adapters/hono/index.js +5 -4
  13. package/dist/adapters/{mcp-transport-DPpei63d.cjs → mcp-transport-CjA5_6G_.cjs} +2 -2
  14. package/dist/adapters/{mcp-transport-DWSNkwUY.js → mcp-transport-x_A7Q5OL.js} +35 -20
  15. package/dist/adapters/nextjs/index.cjs +1 -1
  16. package/dist/adapters/nextjs/index.d.ts +7 -1
  17. package/dist/adapters/nextjs/index.js +9 -8
  18. package/dist/adapters/{utils-BLFzzCI9.cjs → utils-CDExg9uP.cjs} +1 -1
  19. package/dist/adapters/{utils-B7VkyzMv.js → utils-DkKcpkx5.js} +1 -5
  20. package/dist/adapters/utils.cjs +1 -1
  21. package/dist/adapters/utils.js +1 -1
  22. package/dist/client/charts.js +3 -3
  23. package/dist/client/chunks/{DashboardEditModal-DenRJiYr.js → DashboardEditModal-kWEk4KJC.js} +8 -8
  24. package/dist/client/chunks/{DashboardEditModal-DenRJiYr.js.map → DashboardEditModal-kWEk4KJC.js.map} +1 -1
  25. package/dist/client/chunks/{FieldSearchModal-BQS1v1up.js → FieldSearchModal-rB26lhBD.js} +3 -3
  26. package/dist/client/chunks/{FieldSearchModal-BQS1v1up.js.map → FieldSearchModal-rB26lhBD.js.map} +1 -1
  27. package/dist/client/chunks/{analysis-builder-DG38V1gO.js → analysis-builder-CdDPUAEU.js} +8 -8
  28. package/dist/client/chunks/{analysis-builder-DG38V1gO.js.map → analysis-builder-CdDPUAEU.js.map} +1 -1
  29. package/dist/client/chunks/{analysis-builder-shared-DaFu78dk.js → analysis-builder-shared-3V70XUNW.js} +15 -19
  30. package/dist/client/chunks/{analysis-builder-shared-DaFu78dk.js.map → analysis-builder-shared-3V70XUNW.js.map} +1 -1
  31. package/dist/client/chunks/{chart-data-table-B2m_6EZe.js → chart-data-table-BlkFWPhF.js} +602 -581
  32. package/dist/client/chunks/chart-data-table-BlkFWPhF.js.map +1 -0
  33. package/dist/client/chunks/{chart-kpi-delta-S6qDEoJO.js → chart-kpi-delta-CUIjCDS3.js} +2 -2
  34. package/dist/client/chunks/{chart-kpi-delta-S6qDEoJO.js.map → chart-kpi-delta-CUIjCDS3.js.map} +1 -1
  35. package/dist/client/chunks/{chart-kpi-number-CEUBsVW2.js → chart-kpi-number-CxlpSKYh.js} +3 -3
  36. package/dist/client/chunks/{chart-kpi-number-CEUBsVW2.js.map → chart-kpi-number-CxlpSKYh.js.map} +1 -1
  37. package/dist/client/chunks/{chart-kpi-text-DgRig_jQ.js → chart-kpi-text-C16fwohp.js} +2 -2
  38. package/dist/client/chunks/{chart-kpi-text-DgRig_jQ.js.map → chart-kpi-text-C16fwohp.js.map} +1 -1
  39. package/dist/client/chunks/{chart-markdown-DXxc43w1.js → chart-markdown-B2X4IwLO.js} +1132 -1119
  40. package/dist/client/chunks/chart-markdown-B2X4IwLO.js.map +1 -0
  41. package/dist/client/chunks/{charts-loader-BI07yxaQ.js → charts-loader-BFhQWB_d.js} +6 -6
  42. package/dist/client/chunks/{charts-loader-BI07yxaQ.js.map → charts-loader-BFhQWB_d.js.map} +1 -1
  43. package/dist/client/chunks/{core-D1TOj17W.js → core-DJrniqct.js} +2 -6
  44. package/dist/client/chunks/{core-D1TOj17W.js.map → core-DJrniqct.js.map} +1 -1
  45. package/dist/client/chunks/{schema-visualization-DPL5_Tkh.js → schema-visualization-qmLI8MGQ.js} +13 -14
  46. package/dist/client/chunks/{schema-visualization-DPL5_Tkh.js.map → schema-visualization-qmLI8MGQ.js.map} +1 -1
  47. package/dist/client/chunks/{syntaxHighlighting-87bOwTxj.js → syntaxHighlighting-BLl0ch4A.js} +2 -2
  48. package/dist/client/chunks/{syntaxHighlighting-87bOwTxj.js.map → syntaxHighlighting-BLl0ch4A.js.map} +1 -1
  49. package/dist/client/chunks/{useDebounce-DkuM7nQk.js → useDebounce-xfPFr2fi.js} +2 -2
  50. package/dist/client/chunks/{useDebounce-DkuM7nQk.js.map → useDebounce-xfPFr2fi.js.map} +1 -1
  51. package/dist/client/chunks/{useExplainAI-RflLTDVL.js → useExplainAI-6COjssus.js} +4 -4
  52. package/dist/client/chunks/{useExplainAI-RflLTDVL.js.map → useExplainAI-6COjssus.js.map} +1 -1
  53. package/dist/client/chunks/{utils--32ZtfbZ.js → utils-nCeVL-Hm.js} +2 -2
  54. package/dist/client/chunks/{utils--32ZtfbZ.js.map → utils-nCeVL-Hm.js.map} +1 -1
  55. package/dist/client/chunks/{vendor-CZX7UVzM.js → vendor-WzXX36hd.js} +3 -3
  56. package/dist/client/chunks/{vendor-CZX7UVzM.js.map → vendor-WzXX36hd.js.map} +1 -1
  57. package/dist/client/components.js +3 -3
  58. package/dist/client/hooks.js +3 -3
  59. package/dist/client/icons.js +1 -1
  60. package/dist/client/index.js +12 -12
  61. package/dist/client/providers.js +1 -1
  62. package/dist/client/utils.js +4 -4
  63. package/dist/client-bundle-stats.html +1 -1
  64. package/dist/server/index.cjs +2 -2
  65. package/dist/server/index.d.ts +47 -5
  66. package/dist/server/index.js +34 -19
  67. package/package.json +3 -3
  68. package/dist/client/chunks/chart-data-table-B2m_6EZe.js.map +0 -1
  69. package/dist/client/chunks/chart-markdown-DXxc43w1.js.map +0 -1
@@ -1367,6 +1367,7 @@ export declare interface DrizzleDatabase {
1367
1367
  };
1368
1368
  with: (...args: any[]) => any;
1369
1369
  schema?: unknown;
1370
+ transaction?: <T>(fn: (tx: any) => Promise<T>, ...args: any[]) => Promise<T>;
1370
1371
  }
1371
1372
 
1372
1373
  /**
@@ -1519,6 +1520,13 @@ export declare class DrizzleSqlBuilder {
1519
1520
  buildLogicalFilter(filter: Filter, cubes: Map<string, Cube>, context: QueryContext): SQL | null;
1520
1521
  }
1521
1522
 
1523
+ /**
1524
+ * Transaction-scoped database instance passed to RLS setup.
1525
+ * Structurally identical to DrizzleDatabase — the alias communicates
1526
+ * that the value lives inside a transaction, not the root connection.
1527
+ */
1528
+ export declare type DrizzleTransaction = DrizzleDatabase;
1529
+
1522
1530
  export declare class DuckDBExecutor extends BaseDatabaseExecutor {
1523
1531
  execute<T = any[]>(query: SQL | any, numericFields?: string[]): Promise<T>;
1524
1532
  /**
@@ -3850,7 +3858,19 @@ export declare class QueryExecutor {
3850
3858
  private cacheConfig?;
3851
3859
  private logicalPlanBuilder;
3852
3860
  private planOptimiser;
3853
- constructor(dbExecutor: DatabaseExecutor, cacheConfig?: CacheConfig);
3861
+ private rlsSetup?;
3862
+ constructor(dbExecutor: DatabaseExecutor, cacheConfig?: CacheConfig, rlsSetup?: RLSSetupFn);
3863
+ /**
3864
+ * Execute a function within a RLS-configured transaction context.
3865
+ * If no rlsSetup function is configured, the function is called directly.
3866
+ * Otherwise, opens a transaction, calls rlsSetup to configure RLS, then
3867
+ * runs fn with this.dbExecutor replaced by a transaction-scoped executor.
3868
+ *
3869
+ * Concurrency-safe: the dbExecutor is per-request (created fresh by
3870
+ * SemanticLayerCompiler.createQueryExecutor), so reassigning this.dbExecutor
3871
+ * only affects this request.
3872
+ */
3873
+ private withRLSContext;
3854
3874
  /**
3855
3875
  * Unified query execution method that handles both single and multi-cube queries
3856
3876
  * @param options.skipCache - Skip cache lookup (but still cache the fresh result)
@@ -4370,6 +4390,16 @@ export declare interface RetentionTimeDimensionMapping {
4370
4390
  dimension: string;
4371
4391
  }
4372
4392
 
4393
+ /**
4394
+ * Row-Level Security setup function.
4395
+ * Called inside a transaction before query execution to configure
4396
+ * database-level RLS (e.g., setting JWT claims and switching roles in Postgres).
4397
+ *
4398
+ * @param tx - The transaction-scoped Drizzle database instance
4399
+ * @param securityContext - The security context extracted from the request
4400
+ */
4401
+ export declare type RLSSetupFn = (tx: DrizzleTransaction, securityContext: SecurityContext) => Promise<void>;
4402
+
4373
4403
  /**
4374
4404
  * A link (edge) in the Sankey diagram
4375
4405
  * Represents a transition between two nodes
@@ -4414,9 +4444,12 @@ export declare interface SecurityContext {
4414
4444
 
4415
4445
  export declare class SemanticLayerCompiler {
4416
4446
  private cubes;
4417
- private dbExecutor?;
4418
4447
  private metadataCache?;
4419
4448
  private cacheConfig?;
4449
+ private rlsSetup?;
4450
+ private db?;
4451
+ private schema?;
4452
+ private engineType?;
4420
4453
  constructor(options?: {
4421
4454
  drizzle?: DatabaseExecutor['db'];
4422
4455
  schema?: any;
@@ -4424,9 +4457,16 @@ export declare class SemanticLayerCompiler {
4424
4457
  engineType?: 'postgres' | 'mysql' | 'sqlite' | 'singlestore' | 'duckdb' | 'databend' | 'snowflake';
4425
4458
  /** Cache configuration for query result caching */
4426
4459
  cache?: CacheConfig;
4460
+ /**
4461
+ * Row-Level Security setup function.
4462
+ * When provided, every query execution opens a transaction, calls this function
4463
+ * to configure RLS (e.g., set JWT claims and switch roles), then runs the query.
4464
+ * Dry-run/SQL generation is NOT wrapped in a transaction.
4465
+ */
4466
+ rlsSetup?: RLSSetupFn;
4427
4467
  });
4428
4468
  /**
4429
- * Set or update the database executor
4469
+ * Set or update the database connection
4430
4470
  */
4431
4471
  setDatabaseExecutor(executor: DatabaseExecutor): void;
4432
4472
  /**
@@ -4442,11 +4482,13 @@ export declare class SemanticLayerCompiler {
4442
4482
  */
4443
4483
  hasExecutor(): boolean;
4444
4484
  /**
4445
- * Get configured executor or throw.
4485
+ * Create a fresh DatabaseExecutor from stored ingredients, or throw.
4446
4486
  */
4447
- private requireExecutor;
4487
+ private createDbExecutor;
4448
4488
  /**
4449
4489
  * Create a query executor with optional cache integration.
4490
+ * Each call creates a fresh DatabaseExecutor so concurrent requests
4491
+ * never share mutable state.
4450
4492
  */
4451
4493
  private createQueryExecutor;
4452
4494
  /**
@@ -6565,7 +6565,7 @@ var Yt = class {
6565
6565
  //#endregion
6566
6566
  //#region src/server/executor.ts
6567
6567
  function Xt(e, t) {
6568
- if (process.env.DC_DEBUG) try {
6568
+ if (!(typeof process > "u" || !process.env?.DC_DEBUG)) try {
6569
6569
  let { sql: n, params: r } = t.toSQL();
6570
6570
  console.log(`\n[DC_DEBUG] ${e}`), console.log(n), r.length > 0 && console.log("params:", r), console.log();
6571
6571
  } catch {}
@@ -6581,11 +6581,23 @@ var Zt = class {
6581
6581
  cacheConfig;
6582
6582
  logicalPlanBuilder;
6583
6583
  planOptimiser;
6584
- constructor(e, t) {
6584
+ rlsSetup;
6585
+ constructor(e, t, n) {
6585
6586
  if (this.dbExecutor = e, this.databaseAdapter = e.databaseAdapter, !this.databaseAdapter) throw Error("DatabaseExecutor must have a databaseAdapter property");
6586
6587
  this.queryBuilder = new _t(this.databaseAdapter);
6587
- let n = new yt(), r = new bt(this.queryBuilder);
6588
- this.drizzlePlanBuilder = new Yt(this.queryBuilder, r, this.databaseAdapter), this.comparisonQueryBuilder = new kt(this.databaseAdapter), this.funnelQueryBuilder = new At(this.databaseAdapter), this.flowQueryBuilder = new jt(this.databaseAdapter), this.retentionQueryBuilder = new It(this.databaseAdapter), this.logicalPlanBuilder = new Lt(n), this.planOptimiser = new Rt(), this.cacheConfig = t;
6588
+ let r = new yt(), i = new bt(this.queryBuilder);
6589
+ this.drizzlePlanBuilder = new Yt(this.queryBuilder, i, this.databaseAdapter), this.comparisonQueryBuilder = new kt(this.databaseAdapter), this.funnelQueryBuilder = new At(this.databaseAdapter), this.flowQueryBuilder = new jt(this.databaseAdapter), this.retentionQueryBuilder = new It(this.databaseAdapter), this.logicalPlanBuilder = new Lt(r), this.planOptimiser = new Rt(), this.cacheConfig = t, this.rlsSetup = n;
6590
+ }
6591
+ async withRLSContext(e, t) {
6592
+ if (!this.rlsSetup) return t();
6593
+ let n = this.dbExecutor.db;
6594
+ if (!n.transaction) throw Error("rlsSetup requires a database driver that supports transactions (db.transaction)");
6595
+ let r = this.rlsSetup;
6596
+ return n.transaction(async (n) => {
6597
+ await r(n, e);
6598
+ let i = Object.create(this.dbExecutor);
6599
+ return i.db = n, this.dbExecutor = i, t();
6600
+ });
6589
6601
  }
6590
6602
  async execute(e, t, n, r) {
6591
6603
  try {
@@ -6625,7 +6637,7 @@ var Zt = class {
6625
6637
  } catch (e) {
6626
6638
  this.cacheConfig.onError?.(e, "get");
6627
6639
  }
6628
- return await this.executeQueryByModeWithCache(i, e, t, n, a);
6640
+ return await this.withRLSContext(n, () => this.executeQueryByModeWithCache(i, e, t, n, a));
6629
6641
  } catch (e) {
6630
6642
  if (e instanceof Error) {
6631
6643
  let t = e;
@@ -6825,8 +6837,8 @@ var Zt = class {
6825
6837
  for (let e of i) if (!a.has(e.name)) {
6826
6838
  a.add(e.name);
6827
6839
  try {
6828
- if (e.public) continue;
6829
- e.sql(t).where || console.warn(`[drizzle-cube] WARNING: Cube '${e.name}' has no security filtering. If this cube contains public data, add 'public: true' to suppress this warning. Otherwise, ensure sql() returns: { from: table, where: eq(table.orgId, ctx.securityContext.orgId) }`);
6840
+ if (e.public || this.rlsSetup) continue;
6841
+ e.sql(t).where || console.warn(`[drizzle-cube] WARNING: Cube '${e.name}' has no security filtering. If this cube contains public data, add 'public: true' to suppress this warning. Otherwise, ensure sql() returns: { from: table, where: eq(table.orgId, ctx.securityContext.orgId) }. For databases that support Row Level Security (e.g. PostgreSQL), you can configure rlsSetup to run session-level commands (SET LOCAL, SET ROLE) instead.`);
6830
6842
  } catch {}
6831
6843
  }
6832
6844
  }
@@ -6881,7 +6893,7 @@ var Zt = class {
6881
6893
  }
6882
6894
  async explainQuery(e, t, n, r) {
6883
6895
  let i = await this.dryRunSQL(e, t, n);
6884
- return this.dbExecutor.explainQuery(i.sql, i.params || [], r);
6896
+ return this.withRLSContext(n, () => this.dbExecutor.explainQuery(i.sql, i.params || [], r));
6885
6897
  }
6886
6898
  async dryRunSQL(e, t, n) {
6887
6899
  let r = this.resolveQueryMode(t);
@@ -11191,33 +11203,36 @@ async function hc(e, t, n) {
11191
11203
  //#region src/server/compiler.ts
11192
11204
  var gc = class e {
11193
11205
  cubes = /* @__PURE__ */ new Map();
11194
- dbExecutor;
11195
11206
  metadataCache;
11196
11207
  cacheConfig;
11208
+ rlsSetup;
11209
+ db;
11210
+ schema;
11211
+ engineType;
11197
11212
  constructor(e) {
11198
- e?.databaseExecutor ? this.dbExecutor = e.databaseExecutor : e?.drizzle && (this.dbExecutor = Ue(e.drizzle, e.schema, e.engineType)), this.cacheConfig = e?.cache;
11213
+ e?.databaseExecutor ? (this.db = e.databaseExecutor.db, this.schema = e.databaseExecutor.schema, this.engineType = e.databaseExecutor.getEngineType()) : e?.drizzle && (this.db = e.drizzle, this.schema = e.schema, this.engineType = e.engineType), this.cacheConfig = e?.cache, this.rlsSetup = e?.rlsSetup;
11199
11214
  }
11200
11215
  setDatabaseExecutor(e) {
11201
- this.dbExecutor = e;
11216
+ this.db = e.db, this.schema = e.schema, this.engineType = e.getEngineType();
11202
11217
  }
11203
11218
  getEngineType() {
11204
- return this.dbExecutor?.getEngineType();
11219
+ return this.engineType;
11205
11220
  }
11206
11221
  setDrizzle(e, t, n) {
11207
- this.dbExecutor = Ue(e, t, n);
11222
+ this.db = e, this.schema = t, this.engineType = n;
11208
11223
  }
11209
11224
  hasExecutor() {
11210
- return !!this.dbExecutor;
11225
+ return !!this.db;
11211
11226
  }
11212
- requireExecutor() {
11213
- if (!this.dbExecutor) throw Error("Database executor not configured");
11214
- return this.dbExecutor;
11227
+ createDbExecutor() {
11228
+ if (!this.db) throw Error("Database executor not configured");
11229
+ return Ue(this.db, this.schema, this.engineType);
11215
11230
  }
11216
11231
  createQueryExecutor(e = !1) {
11217
- return new Zt(this.requireExecutor(), e ? this.cacheConfig : void 0);
11232
+ return new Zt(this.createDbExecutor(), e ? this.cacheConfig : void 0, this.rlsSetup);
11218
11233
  }
11219
11234
  formatSqlResult(e) {
11220
- let t = this.requireExecutor().getEngineType();
11235
+ let t = this.getEngineType() ?? "postgres";
11221
11236
  return {
11222
11237
  sql: pc(e.sql, t),
11223
11238
  params: e.params
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "drizzle-cube",
3
- "version": "0.4.34",
3
+ "version": "0.4.36",
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",
@@ -266,7 +266,7 @@
266
266
  "@leonardovida-md/drizzle-neo-duckdb": "^1.2.2"
267
267
  },
268
268
  "devDependencies": {
269
- "@anthropic-ai/sdk": "^0.79.0",
269
+ "@anthropic-ai/sdk": "^0.80.0",
270
270
  "@eslint/eslintrc": "^3.3.1",
271
271
  "@eslint/js": "^10.0.0",
272
272
  "@fastify/cors": "^11.1.0",
@@ -317,7 +317,7 @@
317
317
  "globals": "^17.0.0",
318
318
  "hono": "^4.0.0",
319
319
  "html2canvas": "^1.4.1",
320
- "jsdom": "^28.0.0",
320
+ "jsdom": "^29.0.0",
321
321
  "modern-screenshot": "^4.6.7",
322
322
  "msw": "^2.12.7",
323
323
  "mysql2": "^3.14.3",