@dyrected/core 2.9.0 → 2.10.1

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/server.cjs CHANGED
@@ -2318,11 +2318,12 @@ function sanitizeWhereClause(where, fields) {
2318
2318
  function walk(node) {
2319
2319
  const result = {};
2320
2320
  for (const [key, value] of Object.entries(node)) {
2321
- if (key === "AND" || key === "OR") {
2321
+ const upperKey = key.toUpperCase();
2322
+ if (upperKey === "AND" || upperKey === "OR") {
2322
2323
  if (Array.isArray(value)) {
2323
2324
  const processed = value.map((v) => walk(v)).filter((v) => Object.keys(v).length > 0);
2324
2325
  if (processed.length > 0) {
2325
- result[key] = processed;
2326
+ result[upperKey] = processed;
2326
2327
  }
2327
2328
  }
2328
2329
  continue;
@@ -3144,6 +3145,11 @@ function registerJexlHelpers(jexlInstance = import_jexl2.default) {
3144
3145
  try {
3145
3146
  jexlInstance.addBinaryOp("and", 20, (left, right) => Boolean(left && right));
3146
3147
  jexlInstance.addBinaryOp("or", 10, (left, right) => Boolean(left || right));
3148
+ jexlInstance.addBinaryOp("in", 30, (left, right) => {
3149
+ if (Array.isArray(right)) return right.includes(left);
3150
+ if (typeof right === "string") return right.includes(String(left ?? ""));
3151
+ return false;
3152
+ });
3147
3153
  } catch {
3148
3154
  }
3149
3155
  }
@@ -4036,6 +4042,17 @@ function validateUpload(file, config) {
4036
4042
  }
4037
4043
  return null;
4038
4044
  }
4045
+ function generateUniqueUploadFilename(filename) {
4046
+ const lastDotIndex = filename.lastIndexOf(".");
4047
+ const ext = lastDotIndex !== -1 ? filename.substring(lastDotIndex).toLowerCase() : "";
4048
+ const baseName = lastDotIndex !== -1 ? filename.substring(0, lastDotIndex) : filename;
4049
+ const sanitizedBase = baseName.toLowerCase().normalize("NFKD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "") || "file";
4050
+ if (/-\d{10,13}-[a-z0-9]{4,10}$/.test(sanitizedBase)) {
4051
+ return `${sanitizedBase}${ext}`;
4052
+ }
4053
+ const uniqueSuffix = `${Date.now()}-${Math.random().toString(36).substring(2, 8)}`;
4054
+ return `${sanitizedBase}-${uniqueSuffix}${ext}`;
4055
+ }
4039
4056
 
4040
4057
  // src/auth/jexl.ts
4041
4058
  var import_jexl5 = __toESM(require_Jexl(), 1);
@@ -5366,6 +5383,7 @@ var CollectionController = class {
5366
5383
  createdBy: user?.sub ?? null,
5367
5384
  updatedBy: user?.sub ?? null
5368
5385
  };
5386
+ data = DefaultsService.apply(this.collection.fields, data);
5369
5387
  if (this.collection.workflow) {
5370
5388
  data = initializeWorkflowDocument(data, this.collection.workflow);
5371
5389
  }
@@ -5487,8 +5505,9 @@ var CollectionController = class {
5487
5505
  const siteId = c.get("siteId");
5488
5506
  const workspaceId = c.get("workspaceId");
5489
5507
  const prefix = workspaceId ? `${workspaceId}/${siteId}` : siteId;
5508
+ const uniqueFilename = generateUniqueUploadFilename(file.name);
5490
5509
  const fileData = await storage.upload({
5491
- filename: file.name,
5510
+ filename: uniqueFilename,
5492
5511
  buffer,
5493
5512
  mimeType: file.type,
5494
5513
  prefix
@@ -6247,9 +6266,23 @@ var CollectionController = class {
6247
6266
  400
6248
6267
  );
6249
6268
  }
6269
+ let rawAggregates;
6270
+ let groupBy;
6271
+ if ("aggregates" in body && typeof body.aggregates === "object" && body.aggregates !== null && !Array.isArray(body.aggregates)) {
6272
+ rawAggregates = body.aggregates;
6273
+ if (typeof body.groupBy === "string" && body.groupBy.trim()) {
6274
+ groupBy = body.groupBy.trim();
6275
+ }
6276
+ } else {
6277
+ rawAggregates = body;
6278
+ const queryGroupBy = c.req.query("groupBy");
6279
+ if (typeof queryGroupBy === "string" && queryGroupBy.trim()) {
6280
+ groupBy = queryGroupBy.trim();
6281
+ }
6282
+ }
6250
6283
  const { sanitizeWhereClause: sanitizeWhereClause2 } = await Promise.resolve().then(() => (init_where_sanitizer(), where_sanitizer_exports));
6251
6284
  const sanitizedAggregates = {};
6252
- for (const [key, op] of Object.entries(body)) {
6285
+ for (const [key, op] of Object.entries(rawAggregates)) {
6253
6286
  if (!op || typeof op !== "object" || Array.isArray(op)) {
6254
6287
  return c.json(
6255
6288
  {
@@ -6274,7 +6307,8 @@ var CollectionController = class {
6274
6307
  }
6275
6308
  const result = await db.aggregate({
6276
6309
  collection: this.collection.slug,
6277
- aggregates: sanitizedAggregates
6310
+ aggregates: sanitizedAggregates,
6311
+ ...groupBy ? { groupBy } : {}
6278
6312
  });
6279
6313
  return c.json(result);
6280
6314
  }
@@ -6670,6 +6704,7 @@ var MediaController = class {
6670
6704
  const buffer = new Uint8Array(await file.arrayBuffer());
6671
6705
  const workspaceId = c.get("workspaceId");
6672
6706
  const prefix = workspaceId ? `${workspaceId}/${siteId}` : siteId || "default";
6707
+ const uniqueFilename = generateUniqueUploadFilename(file.name);
6673
6708
  let imageMetadata = {};
6674
6709
  let imageSizes = {};
6675
6710
  if (imageService && file.type.startsWith("image/")) {
@@ -6692,7 +6727,7 @@ var MediaController = class {
6692
6727
  }
6693
6728
  }
6694
6729
  const fileData = await storage.upload({
6695
- filename: file.name,
6730
+ filename: uniqueFilename,
6696
6731
  buffer,
6697
6732
  mimeType: file.type,
6698
6733
  prefix
@@ -6705,9 +6740,10 @@ var MediaController = class {
6705
6740
  };
6706
6741
  if (imageSizes) {
6707
6742
  for (const [sizeName, sizeData] of Object.entries(imageSizes)) {
6708
- const ext = file.name.split(".").pop();
6709
- const baseName = file.name.substring(0, file.name.lastIndexOf("."));
6710
- const sizeFilename = `${baseName}-${sizeName}.${ext}`;
6743
+ const lastDot = uniqueFilename.lastIndexOf(".");
6744
+ const ext = lastDot !== -1 ? uniqueFilename.substring(lastDot) : "";
6745
+ const baseName = lastDot !== -1 ? uniqueFilename.substring(0, lastDot) : uniqueFilename;
6746
+ const sizeFilename = `${baseName}-${sizeName}${ext}`;
6711
6747
  try {
6712
6748
  const sizeFileData = await storage.upload({
6713
6749
  filename: sizeFilename,
@@ -8959,39 +8995,94 @@ function generateOpenApi(config) {
8959
8995
  post: {
8960
8996
  tags: [collectionTag],
8961
8997
  summary: `Aggregate ${labels.plural}`,
8962
- description: `Compute statistical aggregations (count, sum, avg, min, max) across ${labels.plural}.`,
8998
+ description: `Compute statistical aggregations (count, countDistinct, distinct, sum, avg, min, max, groupBy) across ${labels.plural}.`,
8999
+ parameters: [
9000
+ {
9001
+ name: "groupBy",
9002
+ in: "query",
9003
+ description: "Optional field name to compute aggregates grouped by distinct values",
9004
+ required: false,
9005
+ schema: { type: "string" }
9006
+ }
9007
+ ],
8963
9008
  requestBody: {
8964
9009
  required: true,
8965
9010
  content: {
8966
9011
  "application/json": {
8967
9012
  schema: {
8968
- type: "object",
8969
- additionalProperties: {
8970
- type: "object",
8971
- properties: {
8972
- count: { type: "string", example: "*" },
8973
- sum: { type: "string", description: "Field to sum" },
8974
- avg: { type: "string", description: "Field to average" },
8975
- min: { type: "string", description: "Field for minimum" },
8976
- max: { type: "string", description: "Field for maximum" },
8977
- cast: {
8978
- type: "string",
8979
- enum: [
8980
- "number",
8981
- "integer",
8982
- "float",
8983
- "boolean",
8984
- "date",
8985
- "string"
8986
- ]
8987
- },
8988
- where: {
9013
+ oneOf: [
9014
+ {
9015
+ type: "object",
9016
+ description: "Flat aggregate operations dictionary",
9017
+ additionalProperties: {
8989
9018
  type: "object",
8990
- description: "Per-aggregate filter condition",
8991
- additionalProperties: true
9019
+ properties: {
9020
+ count: { type: "string", example: "*" },
9021
+ countDistinct: { type: "string", description: "Field to count unique non-null values" },
9022
+ distinct: { type: "string", description: "Field to extract unique non-null values" },
9023
+ sum: { type: "string", description: "Field to sum" },
9024
+ avg: { type: "string", description: "Field to average" },
9025
+ min: { type: "string", description: "Field for minimum" },
9026
+ max: { type: "string", description: "Field for maximum" },
9027
+ cast: {
9028
+ type: "string",
9029
+ enum: [
9030
+ "number",
9031
+ "integer",
9032
+ "float",
9033
+ "boolean",
9034
+ "date",
9035
+ "string"
9036
+ ]
9037
+ },
9038
+ where: {
9039
+ type: "object",
9040
+ description: "Per-aggregate filter condition",
9041
+ additionalProperties: true
9042
+ }
9043
+ }
8992
9044
  }
9045
+ },
9046
+ {
9047
+ type: "object",
9048
+ description: "Grouped aggregate payload with explicit groupBy property",
9049
+ properties: {
9050
+ groupBy: { type: "string", description: "Field name to group aggregates by" },
9051
+ aggregates: {
9052
+ type: "object",
9053
+ additionalProperties: {
9054
+ type: "object",
9055
+ properties: {
9056
+ count: { type: "string", example: "*" },
9057
+ countDistinct: { type: "string", description: "Field to count unique non-null values" },
9058
+ distinct: { type: "string", description: "Field to extract unique non-null values" },
9059
+ sum: { type: "string", description: "Field to sum" },
9060
+ avg: { type: "string", description: "Field to average" },
9061
+ min: { type: "string", description: "Field for minimum" },
9062
+ max: { type: "string", description: "Field for maximum" },
9063
+ cast: {
9064
+ type: "string",
9065
+ enum: [
9066
+ "number",
9067
+ "integer",
9068
+ "float",
9069
+ "boolean",
9070
+ "date",
9071
+ "string"
9072
+ ]
9073
+ },
9074
+ where: {
9075
+ type: "object",
9076
+ description: "Per-aggregate filter condition",
9077
+ additionalProperties: true
9078
+ }
9079
+ }
9080
+ }
9081
+ }
9082
+ },
9083
+ required: ["aggregates"]
8993
9084
  }
8994
- }
9085
+ ]
8995
9086
  }
8996
9087
  }
8997
9088
  }
@@ -9002,11 +9093,36 @@ function generateOpenApi(config) {
9002
9093
  content: {
9003
9094
  "application/json": {
9004
9095
  schema: {
9005
- type: "object",
9006
- additionalProperties: {
9007
- type: "number",
9008
- nullable: true
9009
- }
9096
+ oneOf: [
9097
+ {
9098
+ type: "object",
9099
+ description: "Flat aggregate results map",
9100
+ additionalProperties: {
9101
+ oneOf: [
9102
+ { type: "number", nullable: true },
9103
+ { type: "array", items: { type: "string" } }
9104
+ ]
9105
+ }
9106
+ },
9107
+ {
9108
+ type: "object",
9109
+ description: "Grouped aggregate results breakdown",
9110
+ properties: {
9111
+ groups: {
9112
+ type: "object",
9113
+ additionalProperties: {
9114
+ type: "object",
9115
+ additionalProperties: {
9116
+ oneOf: [
9117
+ { type: "number", nullable: true },
9118
+ { type: "array", items: { type: "string" } }
9119
+ ]
9120
+ }
9121
+ }
9122
+ }
9123
+ }
9124
+ }
9125
+ ]
9010
9126
  }
9011
9127
  }
9012
9128
  }
@@ -9753,6 +9869,9 @@ async function serializeViewForApi(view, serializeAccess) {
9753
9869
  columns: view.columns,
9754
9870
  sort: view.sort,
9755
9871
  metrics: view.metrics,
9872
+ features: view.features,
9873
+ actionOrder: view.actionOrder,
9874
+ components: view.components,
9756
9875
  actions: await Promise.all(
9757
9876
  (view.actions || []).map(async (action) => ({
9758
9877
  name: action.name,
@@ -9760,6 +9879,7 @@ async function serializeViewForApi(view, serializeAccess) {
9760
9879
  icon: action.icon,
9761
9880
  type: action.type ?? "row",
9762
9881
  confirm: action.confirm,
9882
+ submitLabel: action.submitLabel,
9763
9883
  fields: action.fields?.map(serializeFieldForApi),
9764
9884
  mutation: action.mutation,
9765
9885
  // Self-hosted handlers are intentionally omitted: they never leave the server.
@@ -9829,6 +9949,7 @@ function registerRoutes(app, config) {
9829
9949
  auth: !!col.auth,
9830
9950
  audit: !!col.audit,
9831
9951
  drafts: !!col.drafts,
9952
+ defaultView: col.defaultView ?? col.admin?.defaultView,
9832
9953
  views: await Promise.all((col.views || []).map((view) => serializeViewForApi(view, serializeAccess))),
9833
9954
  admin: col.admin,
9834
9955
  detail: serializeDetailForApi(col.detail),
package/dist/server.d.cts CHANGED
@@ -2,7 +2,7 @@ import * as hono_types from 'hono/types';
2
2
  import * as hono from 'hono';
3
3
  import { Context, Hono } from 'hono';
4
4
  import { Logger } from 'pino';
5
- import { D as DyrectedConfig, b2 as DyrectedObservabilityConfig, C as CollectionConfig, G as GlobalConfig } from './app-config-gEQJFvnN.cjs';
5
+ import { D as DyrectedConfig, b5 as DyrectedObservabilityConfig, C as CollectionConfig, G as GlobalConfig } from './app-config-BLC7WoyL.cjs';
6
6
  import { JWTPayload } from 'jose';
7
7
  import { Tracer, Counter, Attributes, Histogram, Span } from '@opentelemetry/api';
8
8
  import { PrometheusExporter } from '@opentelemetry/exporter-prometheus';
@@ -498,7 +498,7 @@ declare class CollectionController {
498
498
  }, 403, "json">) | (Response & hono.TypedResponse<{
499
499
  message: string;
500
500
  }, 400, "json">) | (Response & hono.TypedResponse<{
501
- [x: string]: number | null;
501
+ [x: string]: any;
502
502
  }, hono_utils_http_status.ContentfulStatusCode, "json">)>;
503
503
  }
504
504
 
package/dist/server.d.ts CHANGED
@@ -2,7 +2,7 @@ import * as hono_types from 'hono/types';
2
2
  import * as hono from 'hono';
3
3
  import { Context, Hono } from 'hono';
4
4
  import { Logger } from 'pino';
5
- import { D as DyrectedConfig, b2 as DyrectedObservabilityConfig, C as CollectionConfig, G as GlobalConfig } from './app-config-gEQJFvnN.js';
5
+ import { D as DyrectedConfig, b5 as DyrectedObservabilityConfig, C as CollectionConfig, G as GlobalConfig } from './app-config-BLC7WoyL.js';
6
6
  import { JWTPayload } from 'jose';
7
7
  import { Tracer, Counter, Attributes, Histogram, Span } from '@opentelemetry/api';
8
8
  import { PrometheusExporter } from '@opentelemetry/exporter-prometheus';
@@ -498,7 +498,7 @@ declare class CollectionController {
498
498
  }, 403, "json">) | (Response & hono.TypedResponse<{
499
499
  message: string;
500
500
  }, 400, "json">) | (Response & hono.TypedResponse<{
501
- [x: string]: number | null;
501
+ [x: string]: any;
502
502
  }, hono_utils_http_status.ContentfulStatusCode, "json">)>;
503
503
  }
504
504
 
package/dist/server.js CHANGED
@@ -30,7 +30,7 @@ import {
30
30
  touchAuthSession,
31
31
  transitionWorkflow,
32
32
  verifyCollectionToken
33
- } from "./chunk-XRIONGRY.js";
33
+ } from "./chunk-H7DVVW2P.js";
34
34
  import {
35
35
  attachRequestMetrics,
36
36
  bindObservabilityRuntime,
@@ -436,6 +436,17 @@ function validateUpload(file, config) {
436
436
  }
437
437
  return null;
438
438
  }
439
+ function generateUniqueUploadFilename(filename) {
440
+ const lastDotIndex = filename.lastIndexOf(".");
441
+ const ext = lastDotIndex !== -1 ? filename.substring(lastDotIndex).toLowerCase() : "";
442
+ const baseName = lastDotIndex !== -1 ? filename.substring(0, lastDotIndex) : filename;
443
+ const sanitizedBase = baseName.toLowerCase().normalize("NFKD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "") || "file";
444
+ if (/-\d{10,13}-[a-z0-9]{4,10}$/.test(sanitizedBase)) {
445
+ return `${sanitizedBase}${ext}`;
446
+ }
447
+ const uniqueSuffix = `${Date.now()}-${Math.random().toString(36).substring(2, 8)}`;
448
+ return `${sanitizedBase}-${uniqueSuffix}${ext}`;
449
+ }
439
450
 
440
451
  // src/auth/jexl.ts
441
452
  var import_jexl2 = __toESM(require_Jexl(), 1);
@@ -1021,7 +1032,7 @@ var CollectionController = class {
1021
1032
  if (this.collection.admin?.filterable === false) {
1022
1033
  where = void 0;
1023
1034
  } else {
1024
- const { sanitizeWhereClause } = await import("./where-sanitizer-3MNFMYA2.js");
1035
+ const { sanitizeWhereClause } = await import("./where-sanitizer-47QPJQ6O.js");
1025
1036
  where = sanitizeWhereClause(where, this.collection.fields);
1026
1037
  if (Object.keys(where).length === 0) {
1027
1038
  where = void 0;
@@ -1319,6 +1330,7 @@ var CollectionController = class {
1319
1330
  createdBy: user?.sub ?? null,
1320
1331
  updatedBy: user?.sub ?? null
1321
1332
  };
1333
+ data = DefaultsService.apply(this.collection.fields, data);
1322
1334
  if (this.collection.workflow) {
1323
1335
  data = initializeWorkflowDocument(data, this.collection.workflow);
1324
1336
  }
@@ -1440,8 +1452,9 @@ var CollectionController = class {
1440
1452
  const siteId = c.get("siteId");
1441
1453
  const workspaceId = c.get("workspaceId");
1442
1454
  const prefix = workspaceId ? `${workspaceId}/${siteId}` : siteId;
1455
+ const uniqueFilename = generateUniqueUploadFilename(file.name);
1443
1456
  const fileData = await storage.upload({
1444
- filename: file.name,
1457
+ filename: uniqueFilename,
1445
1458
  buffer,
1446
1459
  mimeType: file.type,
1447
1460
  prefix
@@ -2200,9 +2213,23 @@ var CollectionController = class {
2200
2213
  400
2201
2214
  );
2202
2215
  }
2203
- const { sanitizeWhereClause } = await import("./where-sanitizer-3MNFMYA2.js");
2216
+ let rawAggregates;
2217
+ let groupBy;
2218
+ if ("aggregates" in body && typeof body.aggregates === "object" && body.aggregates !== null && !Array.isArray(body.aggregates)) {
2219
+ rawAggregates = body.aggregates;
2220
+ if (typeof body.groupBy === "string" && body.groupBy.trim()) {
2221
+ groupBy = body.groupBy.trim();
2222
+ }
2223
+ } else {
2224
+ rawAggregates = body;
2225
+ const queryGroupBy = c.req.query("groupBy");
2226
+ if (typeof queryGroupBy === "string" && queryGroupBy.trim()) {
2227
+ groupBy = queryGroupBy.trim();
2228
+ }
2229
+ }
2230
+ const { sanitizeWhereClause } = await import("./where-sanitizer-47QPJQ6O.js");
2204
2231
  const sanitizedAggregates = {};
2205
- for (const [key, op] of Object.entries(body)) {
2232
+ for (const [key, op] of Object.entries(rawAggregates)) {
2206
2233
  if (!op || typeof op !== "object" || Array.isArray(op)) {
2207
2234
  return c.json(
2208
2235
  {
@@ -2227,7 +2254,8 @@ var CollectionController = class {
2227
2254
  }
2228
2255
  const result = await db.aggregate({
2229
2256
  collection: this.collection.slug,
2230
- aggregates: sanitizedAggregates
2257
+ aggregates: sanitizedAggregates,
2258
+ ...groupBy ? { groupBy } : {}
2231
2259
  });
2232
2260
  return c.json(result);
2233
2261
  }
@@ -2509,6 +2537,7 @@ var MediaController = class {
2509
2537
  const buffer = new Uint8Array(await file.arrayBuffer());
2510
2538
  const workspaceId = c.get("workspaceId");
2511
2539
  const prefix = workspaceId ? `${workspaceId}/${siteId}` : siteId || "default";
2540
+ const uniqueFilename = generateUniqueUploadFilename(file.name);
2512
2541
  let imageMetadata = {};
2513
2542
  let imageSizes = {};
2514
2543
  if (imageService && file.type.startsWith("image/")) {
@@ -2531,7 +2560,7 @@ var MediaController = class {
2531
2560
  }
2532
2561
  }
2533
2562
  const fileData = await storage.upload({
2534
- filename: file.name,
2563
+ filename: uniqueFilename,
2535
2564
  buffer,
2536
2565
  mimeType: file.type,
2537
2566
  prefix
@@ -2544,9 +2573,10 @@ var MediaController = class {
2544
2573
  };
2545
2574
  if (imageSizes) {
2546
2575
  for (const [sizeName, sizeData] of Object.entries(imageSizes)) {
2547
- const ext = file.name.split(".").pop();
2548
- const baseName = file.name.substring(0, file.name.lastIndexOf("."));
2549
- const sizeFilename = `${baseName}-${sizeName}.${ext}`;
2576
+ const lastDot = uniqueFilename.lastIndexOf(".");
2577
+ const ext = lastDot !== -1 ? uniqueFilename.substring(lastDot) : "";
2578
+ const baseName = lastDot !== -1 ? uniqueFilename.substring(0, lastDot) : uniqueFilename;
2579
+ const sizeFilename = `${baseName}-${sizeName}${ext}`;
2550
2580
  try {
2551
2581
  const sizeFileData = await storage.upload({
2552
2582
  filename: sizeFilename,
@@ -4564,6 +4594,9 @@ async function serializeViewForApi(view, serializeAccess) {
4564
4594
  columns: view.columns,
4565
4595
  sort: view.sort,
4566
4596
  metrics: view.metrics,
4597
+ features: view.features,
4598
+ actionOrder: view.actionOrder,
4599
+ components: view.components,
4567
4600
  actions: await Promise.all(
4568
4601
  (view.actions || []).map(async (action) => ({
4569
4602
  name: action.name,
@@ -4571,6 +4604,7 @@ async function serializeViewForApi(view, serializeAccess) {
4571
4604
  icon: action.icon,
4572
4605
  type: action.type ?? "row",
4573
4606
  confirm: action.confirm,
4607
+ submitLabel: action.submitLabel,
4574
4608
  fields: action.fields?.map(serializeFieldForApi),
4575
4609
  mutation: action.mutation,
4576
4610
  // Self-hosted handlers are intentionally omitted: they never leave the server.
@@ -4640,6 +4674,7 @@ function registerRoutes(app, config) {
4640
4674
  auth: !!col.auth,
4641
4675
  audit: !!col.audit,
4642
4676
  drafts: !!col.drafts,
4677
+ defaultView: col.defaultView ?? col.admin?.defaultView,
4643
4678
  views: await Promise.all((col.views || []).map((view) => serializeViewForApi(view, serializeAccess))),
4644
4679
  admin: col.admin,
4645
4680
  detail: serializeDetailForApi(col.detail),
@@ -28,11 +28,12 @@ function sanitizeWhereClause(where, fields) {
28
28
  function walk(node) {
29
29
  const result = {};
30
30
  for (const [key, value] of Object.entries(node)) {
31
- if (key === "AND" || key === "OR") {
31
+ const upperKey = key.toUpperCase();
32
+ if (upperKey === "AND" || upperKey === "OR") {
32
33
  if (Array.isArray(value)) {
33
34
  const processed = value.map((v) => walk(v)).filter((v) => Object.keys(v).length > 0);
34
35
  if (processed.length > 0) {
35
- result[key] = processed;
36
+ result[upperKey] = processed;
36
37
  }
37
38
  }
38
39
  continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dyrected/core",
3
- "version": "2.9.0",
3
+ "version": "2.10.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",