@lumerahq/cli 0.24.0 → 0.24.2-dev.0

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/index.js CHANGED
@@ -226,25 +226,25 @@ async function main() {
226
226
  switch (command) {
227
227
  // Resource commands
228
228
  case "plan":
229
- await import("./resources-CGMBV3T6.js").then((m) => m.plan(args.slice(1)));
229
+ await import("./resources-7VQAR6F4.js").then((m) => m.plan(args.slice(1)));
230
230
  break;
231
231
  case "apply":
232
- await import("./resources-CGMBV3T6.js").then((m) => m.apply(args.slice(1)));
232
+ await import("./resources-7VQAR6F4.js").then((m) => m.apply(args.slice(1)));
233
233
  break;
234
234
  case "pull":
235
- await import("./resources-CGMBV3T6.js").then((m) => m.pull(args.slice(1)));
235
+ await import("./resources-7VQAR6F4.js").then((m) => m.pull(args.slice(1)));
236
236
  break;
237
237
  case "destroy":
238
- await import("./resources-CGMBV3T6.js").then((m) => m.destroy(args.slice(1)));
238
+ await import("./resources-7VQAR6F4.js").then((m) => m.destroy(args.slice(1)));
239
239
  break;
240
240
  case "list":
241
- await import("./resources-CGMBV3T6.js").then((m) => m.list(args.slice(1)));
241
+ await import("./resources-7VQAR6F4.js").then((m) => m.list(args.slice(1)));
242
242
  break;
243
243
  case "show":
244
- await import("./resources-CGMBV3T6.js").then((m) => m.show(args.slice(1)));
244
+ await import("./resources-7VQAR6F4.js").then((m) => m.show(args.slice(1)));
245
245
  break;
246
246
  case "diff":
247
- await import("./resources-CGMBV3T6.js").then((m) => m.diff(args.slice(1)));
247
+ await import("./resources-7VQAR6F4.js").then((m) => m.diff(args.slice(1)));
248
248
  break;
249
249
  // Development
250
250
  case "dev":
@@ -182,6 +182,14 @@ var collectionSchemaRule = {
182
182
  }
183
183
  if (!Array.isArray(index.fields) || !index.fields.every((field) => typeof field === "string" && field.trim() !== "")) {
184
184
  issues.push(error(target, `Index at index ${i} must include a non-empty string array "fields".`));
185
+ } else if (index.fields.length === 1) {
186
+ const fieldName = index.fields[0].trim().toLowerCase();
187
+ if (fieldName === "updated" || fieldName === "external_id") {
188
+ issues.push(error(
189
+ target,
190
+ `Index at index ${i} declares system field "${fieldName}" by itself; Lumera already manages that index. Remove the redundant declaration.`
191
+ ));
192
+ }
185
193
  }
186
194
  }
187
195
  }
@@ -897,6 +905,13 @@ function stripNamespacePrefix(name, appName) {
897
905
  }
898
906
  return name;
899
907
  }
908
+ function buildIndexSql(local, idx, appName) {
909
+ const fields = idx.fields.join(", ");
910
+ const unique = idx.unique ? "UNIQUE " : "";
911
+ const physicalId = appName ? sanitizeSlugForCollectionName(appName) + NAMESPACE_SEPARATOR + local.id : local.id;
912
+ const indexName = `idx_${physicalId}_${idx.fields.join("_")}`;
913
+ return `CREATE ${unique}INDEX ${indexName} ON ${local.name} (${fields})`;
914
+ }
900
915
  var AGENT_IDLE_REAP_TIMEOUT_MIN_SECONDS = 10;
901
916
  var AGENT_IDLE_REAP_TIMEOUT_MAX_SECONDS = 900;
902
917
  function buildCollectionIdMap(collections, appName) {
@@ -1515,7 +1530,7 @@ function loadLocalHooks(platformDir, filterName, appName) {
1515
1530
  }
1516
1531
  return hooks;
1517
1532
  }
1518
- function convertCollectionToApiFormat(local) {
1533
+ function convertCollectionToApiFormat(local, appName) {
1519
1534
  const schema = local.fields.map((field) => {
1520
1535
  const apiField = {
1521
1536
  name: field.name,
@@ -1544,12 +1559,7 @@ function convertCollectionToApiFormat(local) {
1544
1559
  }
1545
1560
  return apiField;
1546
1561
  });
1547
- const indexes = local.indexes?.map((idx) => {
1548
- const fields = idx.fields.join(", ");
1549
- const unique = idx.unique ? "UNIQUE " : "";
1550
- const indexName = `idx_${local.id}_${idx.fields.join("_")}`;
1551
- return `CREATE ${unique}INDEX ${indexName} ON ${local.name} (${fields})`;
1552
- });
1562
+ const indexes = local.indexes?.map((idx) => buildIndexSql(local, idx, appName));
1553
1563
  return {
1554
1564
  id: local.id,
1555
1565
  name: local.name,
@@ -1622,24 +1632,15 @@ function fieldsDiffer(local, remote) {
1622
1632
  if (localMax !== remoteMax) return true;
1623
1633
  return false;
1624
1634
  }
1625
- function localIndexesToSql(local) {
1635
+ function localIndexesToSql(local, appName) {
1626
1636
  if (!local.indexes || local.indexes.length === 0) return [];
1627
- return local.indexes.map((idx) => {
1628
- const fields = idx.fields.join(", ");
1629
- const unique = idx.unique ? "UNIQUE " : "";
1630
- const indexName = `idx_${local.id}_${idx.fields.join("_")}`;
1631
- return `CREATE ${unique}INDEX ${indexName} ON ${local.name} (${fields})`;
1632
- }).sort();
1637
+ return local.indexes.map((idx) => buildIndexSql(local, idx, appName)).sort();
1633
1638
  }
1634
1639
  function normalizeRemoteIndexes(remoteIndexes) {
1635
- return remoteIndexes.filter((idx) => {
1636
- const lower = idx.toLowerCase();
1637
- if (lower.includes("external_id") || lower.includes("updated")) return false;
1638
- return true;
1639
- }).sort();
1640
+ return [...remoteIndexes].sort();
1640
1641
  }
1641
- function indexesDiffer(local, remoteIndexes) {
1642
- const localSql = localIndexesToSql(local);
1642
+ function indexesDiffer(local, remoteIndexes, appName) {
1643
+ const localSql = localIndexesToSql(local, appName);
1643
1644
  const remoteSql = normalizeRemoteIndexes(remoteIndexes);
1644
1645
  if (localSql.length !== remoteSql.length) return true;
1645
1646
  for (let i = 0; i < localSql.length; i++) {
@@ -1667,7 +1668,7 @@ function normalizeCollectionSearch(search) {
1667
1668
  } : {}
1668
1669
  });
1669
1670
  }
1670
- async function planCollections(api, localCollections) {
1671
+ async function planCollections(api, localCollections, appName) {
1671
1672
  const changes = [];
1672
1673
  const remoteCollections = await api.listCollections();
1673
1674
  const remoteById = new Map(remoteCollections.map((c) => [c.id, c]));
@@ -1706,7 +1707,7 @@ async function planCollections(api, localCollections) {
1706
1707
  modified.push(name);
1707
1708
  }
1708
1709
  }
1709
- const indexesChanged = indexesDiffer(local, remote.indexes || []);
1710
+ const indexesChanged = indexesDiffer(local, remote.indexes || [], appName);
1710
1711
  const searchChanged = normalizeCollectionSearch(local.search) !== normalizeCollectionSearch(remote.search);
1711
1712
  const auditChanged = local.audit !== void 0 && local.audit !== remote.audit;
1712
1713
  if (added.length > 0 || removed.length > 0 || modified.length > 0 || indexesChanged || searchChanged || auditChanged) {
@@ -1975,7 +1976,7 @@ async function planHooks(api, localHooks, collections, projectId) {
1975
1976
  }
1976
1977
  return changes;
1977
1978
  }
1978
- async function applyCollections(api, localCollections) {
1979
+ async function applyCollections(api, localCollections, appName) {
1979
1980
  let errors = 0;
1980
1981
  const hasRelations = localCollections.some((c) => c.fields.some((f) => f.type === "relation"));
1981
1982
  if (hasRelations) {
@@ -1992,7 +1993,7 @@ async function applyCollections(api, localCollections) {
1992
1993
  }
1993
1994
  for (const local of localCollections) {
1994
1995
  if (pass1Failed.has(local.name)) continue;
1995
- const apiFormat = convertCollectionToApiFormat(local);
1996
+ const apiFormat = convertCollectionToApiFormat(local, appName);
1996
1997
  try {
1997
1998
  await api.ensureCollection(local.name, apiFormat);
1998
1999
  console.log(pc2.green(" \u2713"), `${local.name} (schema)`);
@@ -2003,7 +2004,7 @@ async function applyCollections(api, localCollections) {
2003
2004
  }
2004
2005
  } else {
2005
2006
  for (const local of localCollections) {
2006
- const apiFormat = convertCollectionToApiFormat(local);
2007
+ const apiFormat = convertCollectionToApiFormat(local, appName);
2007
2008
  try {
2008
2009
  await api.ensureCollection(local.name, apiFormat);
2009
2010
  console.log(pc2.green(" \u2713"), `${local.name}`);
@@ -3265,7 +3266,7 @@ async function plan(args) {
3265
3266
  if (!type || type === "collections") {
3266
3267
  const localCollections = loadLocalCollections(platformDir, name || void 0);
3267
3268
  if (localCollections.length > 0) {
3268
- const changes = await planCollections(api, localCollections);
3269
+ const changes = await planCollections(api, localCollections, appName);
3269
3270
  allChanges.push(...changes);
3270
3271
  }
3271
3272
  }
@@ -3412,7 +3413,7 @@ async function apply(args) {
3412
3413
  const localHooks = !type || type === "hooks" ? loadLocalHooks(platformDir, name || void 0, appName) : [];
3413
3414
  const localAgents = !type || type === "agents" ? loadLocalAgents(platformDir, name || void 0, appName) : [];
3414
3415
  const localMailboxes = !type || type === "mailboxes" ? loadLocalMailboxes(platformDir, name || void 0) : [];
3415
- if (localCollections.length > 0) allChanges.push(...await planCollections(api, localCollections));
3416
+ if (localCollections.length > 0) allChanges.push(...await planCollections(api, localCollections, appName));
3416
3417
  if (localAutomations.length > 0) allChanges.push(...await planAutomations(api, localAutomations, projectId));
3417
3418
  if (localHooks.length > 0) allChanges.push(...await planHooks(api, localHooks, collections, projectId));
3418
3419
  if (localAgents.length > 0) allChanges.push(...await planAgents(api, localAgents, projectId));
@@ -3487,7 +3488,7 @@ async function apply(args) {
3487
3488
  let totalSkipped = 0;
3488
3489
  if (localCollections.length > 0) {
3489
3490
  console.log(pc2.bold(" Collections:"));
3490
- totalErrors += await applyCollections(api, localCollections);
3491
+ totalErrors += await applyCollections(api, localCollections, appName);
3491
3492
  console.log();
3492
3493
  }
3493
3494
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumerahq/cli",
3
- "version": "0.24.0",
3
+ "version": "0.24.2-dev.0",
4
4
  "description": "CLI for building and deploying Lumera apps",
5
5
  "type": "module",
6
6
  "engines": {
@@ -12,8 +12,8 @@ importers:
12
12
  .:
13
13
  dependencies:
14
14
  '@lumerahq/ui':
15
- specifier: ^0.10.0
16
- version: 0.10.0(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
15
+ specifier: ^0.14.0
16
+ version: 0.14.0(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
17
17
  '@tanstack/react-query':
18
18
  specifier: ^5.90.11
19
19
  version: 5.101.0(react@19.2.7)
@@ -457,8 +457,8 @@ packages:
457
457
  '@jridgewell/trace-mapping@0.3.31':
458
458
  resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
459
459
 
460
- '@lumerahq/ui@0.10.0':
461
- resolution: {integrity: sha512-dWz7J9jXJBtHiAy7SFWWWhsoLOQ8TXVu7/FWvkW3wIkeTWRUdDreIaYIrOhpnvkH+PrTafiLGybSGrLQP+knSw==}
460
+ '@lumerahq/ui@0.14.0':
461
+ resolution: {integrity: sha512-zV3HaeNkUJwieStWVf44UJzb+BDES+Dhjr5DfBxqCcc2mlKPm19TjWCjett6GfweFe9NhSgoIOk1txUm76B/GA==}
462
462
  peerDependencies:
463
463
  react: ^18.0.0 || ^19.0.0
464
464
  react-dom: ^18.0.0 || ^19.0.0
@@ -2311,7 +2311,7 @@ snapshots:
2311
2311
  '@jridgewell/resolve-uri': 3.1.2
2312
2312
  '@jridgewell/sourcemap-codec': 1.5.5
2313
2313
 
2314
- '@lumerahq/ui@0.10.0(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)':
2314
+ '@lumerahq/ui@0.14.0(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)':
2315
2315
  dependencies:
2316
2316
  '@base-ui/react': 1.5.0(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
2317
2317
  '@tanstack/react-query': 5.101.0(react@19.2.7)