@lumerahq/cli 0.23.0-dev.2 → 0.23.0-dev.3

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-7243WXIF.js").then((m) => m.plan(args.slice(1)));
229
+ await import("./resources-QCCLRDOL.js").then((m) => m.plan(args.slice(1)));
230
230
  break;
231
231
  case "apply":
232
- await import("./resources-7243WXIF.js").then((m) => m.apply(args.slice(1)));
232
+ await import("./resources-QCCLRDOL.js").then((m) => m.apply(args.slice(1)));
233
233
  break;
234
234
  case "pull":
235
- await import("./resources-7243WXIF.js").then((m) => m.pull(args.slice(1)));
235
+ await import("./resources-QCCLRDOL.js").then((m) => m.pull(args.slice(1)));
236
236
  break;
237
237
  case "destroy":
238
- await import("./resources-7243WXIF.js").then((m) => m.destroy(args.slice(1)));
238
+ await import("./resources-QCCLRDOL.js").then((m) => m.destroy(args.slice(1)));
239
239
  break;
240
240
  case "list":
241
- await import("./resources-7243WXIF.js").then((m) => m.list(args.slice(1)));
241
+ await import("./resources-QCCLRDOL.js").then((m) => m.list(args.slice(1)));
242
242
  break;
243
243
  case "show":
244
- await import("./resources-7243WXIF.js").then((m) => m.show(args.slice(1)));
244
+ await import("./resources-QCCLRDOL.js").then((m) => m.show(args.slice(1)));
245
245
  break;
246
246
  case "diff":
247
- await import("./resources-7243WXIF.js").then((m) => m.diff(args.slice(1)));
247
+ await import("./resources-QCCLRDOL.js").then((m) => m.diff(args.slice(1)));
248
248
  break;
249
249
  // Development
250
250
  case "dev":
@@ -31,7 +31,7 @@ import pc2 from "picocolors";
31
31
  import prompts from "prompts";
32
32
  import { execFileSync, execSync } from "child_process";
33
33
  import { existsSync as existsSync2, readdirSync as readdirSync2, readFileSync as readFileSync2, writeFileSync, mkdirSync } from "fs";
34
- import { join as join2, basename as basename2, resolve } from "path";
34
+ import { join as join2, resolve } from "path";
35
35
 
36
36
  // src/lib/lint/index.ts
37
37
  import { existsSync, readFileSync, readdirSync } from "fs";
@@ -124,9 +124,9 @@ var collectionSchemaRule = {
124
124
  const id = parsed.id;
125
125
  const name = parsed.name;
126
126
  const fields = parsed.fields;
127
- const audit = parsed.audit;
128
127
  const indexes = parsed.indexes;
129
128
  const search = parsed.search;
129
+ const audit = parsed.audit;
130
130
  const localFieldTypes = /* @__PURE__ */ new Map();
131
131
  if (Array.isArray(fields)) {
132
132
  for (const field of fields) {
@@ -164,15 +164,6 @@ var collectionSchemaRule = {
164
164
  if (typeof field.type !== "string" || field.type.trim() === "") {
165
165
  issues.push(error(target, `Field ${typeof field.name === "string" ? `"${field.name}"` : `at index ${i}`} is missing required string field "type".`));
166
166
  }
167
- const fieldLabel = typeof field.name === "string" ? `"${field.name}"` : `at index ${i}`;
168
- if (field.type === "select") {
169
- if (field.options !== void 0) {
170
- issues.push(error(target, `Select field ${fieldLabel} must define choices with top-level "values", not "options.values".`));
171
- }
172
- if (!Array.isArray(field.values) || field.values.length === 0 || !field.values.every((value) => typeof value === "string" && value.trim() !== "")) {
173
- issues.push(error(target, `Select field ${fieldLabel} must include a non-empty string array "values".`));
174
- }
175
- }
176
167
  }
177
168
  }
178
169
  if (audit !== void 0 && typeof audit !== "boolean") {
@@ -906,11 +897,6 @@ function stripNamespacePrefix(name, appName) {
906
897
  }
907
898
  return name;
908
899
  }
909
- function namespacedCollectionID(id, appName) {
910
- if (!appName) return id;
911
- const prefix = sanitizeSlugForCollectionName(appName) + NAMESPACE_SEPARATOR;
912
- return id.startsWith(prefix) ? id : prefix + id;
913
- }
914
900
  var AGENT_IDLE_REAP_TIMEOUT_MIN_SECONDS = 10;
915
901
  var AGENT_IDLE_REAP_TIMEOUT_MAX_SECONDS = 900;
916
902
  function buildCollectionIdMap(collections, appName) {
@@ -922,7 +908,6 @@ function buildCollectionIdMap(collections, appName) {
922
908
  for (const collection of collections) {
923
909
  add(collection.id, collection.id);
924
910
  add(collection.name, collection.id);
925
- add(stripNamespacePrefix(collection.id, appName), collection.id);
926
911
  const stripped = stripNamespacePrefix(collection.name, appName);
927
912
  add(stripped, collection.id);
928
913
  if (collection.name.includes(NAMESPACE_SEPARATOR)) {
@@ -1570,8 +1555,8 @@ function convertCollectionToApiFormat(local) {
1570
1555
  name: local.name,
1571
1556
  schema,
1572
1557
  indexes,
1573
- ...local.audit !== void 0 ? { audit: local.audit } : {},
1574
- search: local.search ?? null
1558
+ search: local.search ?? null,
1559
+ ...local.audit !== void 0 ? { audit: local.audit } : {}
1575
1560
  };
1576
1561
  }
1577
1562
  function mapFieldType(type) {
@@ -1579,8 +1564,8 @@ function mapFieldType(type) {
1579
1564
  text: "text",
1580
1565
  number: "number",
1581
1566
  bool: "bool",
1582
- email: "email",
1583
- url: "url",
1567
+ email: "text",
1568
+ url: "text",
1584
1569
  date: "date",
1585
1570
  select: "select",
1586
1571
  relation: "relation",
@@ -1601,7 +1586,7 @@ function normalizeConstraintValue(fieldType, value) {
1601
1586
  }
1602
1587
  return value;
1603
1588
  }
1604
- function fieldsDiffer(local, remote, appName) {
1589
+ function fieldsDiffer(local, remote) {
1605
1590
  if (mapFieldType(local.type) !== remote.type) return true;
1606
1591
  if ((local.required || false) !== (remote.required || false)) return true;
1607
1592
  const opts = remote.options || {};
@@ -1615,8 +1600,7 @@ function fieldsDiffer(local, remote, appName) {
1615
1600
  if (!localMultiple && remoteMaxSelect > 1) return true;
1616
1601
  }
1617
1602
  if (local.type === "relation") {
1618
- const remoteCollection = stripNamespacePrefix(opts.collectionId || "", appName);
1619
- if (local.collection && local.collection !== remoteCollection) return true;
1603
+ if (local.collection && local.collection !== opts.collectionId) return true;
1620
1604
  const localMultiple = local.multiple || false;
1621
1605
  const remoteMaxSelect = opts.maxSelect || 1;
1622
1606
  if (localMultiple && remoteMaxSelect <= 1) return true;
@@ -1683,22 +1667,22 @@ function normalizeCollectionSearch(search) {
1683
1667
  } : {}
1684
1668
  });
1685
1669
  }
1686
- async function planCollections(api, localCollections, appName) {
1670
+ async function planCollections(api, localCollections) {
1687
1671
  const changes = [];
1688
1672
  const remoteCollections = await api.listCollections();
1689
1673
  const remoteById = new Map(remoteCollections.map((c) => [c.id, c]));
1690
- const remoteByLocalName = new Map(remoteCollections.map((c) => [stripNamespacePrefix(c.name, appName), c]));
1691
1674
  for (const local of localCollections) {
1692
- const remote = remoteByLocalName.get(local.name) ?? remoteById.get(namespacedCollectionID(local.id, appName)) ?? (!appName ? remoteById.get(local.id) : void 0);
1675
+ const remote = remoteById.get(local.id);
1693
1676
  if (!remote) {
1694
- const details = [`${local.fields.length} fields`];
1695
- if (local.audit) details.push("record audit enabled");
1696
1677
  changes.push({
1697
1678
  type: "create",
1698
1679
  resource: "collection",
1699
1680
  id: local.id,
1700
1681
  name: local.name,
1701
- details: details.join(", "),
1682
+ details: [
1683
+ `${local.fields.length} fields`,
1684
+ ...local.audit !== void 0 ? [local.audit ? "audit enabled" : "audit disabled"] : []
1685
+ ].join(", "),
1702
1686
  fieldDetails: local.fields.map((f) => ({
1703
1687
  action: "+",
1704
1688
  name: f.name,
@@ -1718,7 +1702,7 @@ async function planCollections(api, localCollections, appName) {
1718
1702
  if (!remoteFieldNames.has(name)) continue;
1719
1703
  const localField = localFieldMap.get(name);
1720
1704
  const remoteField = remoteFieldMap.get(name);
1721
- if (fieldsDiffer(localField, remoteField, appName)) {
1705
+ if (fieldsDiffer(localField, remoteField)) {
1722
1706
  modified.push(name);
1723
1707
  }
1724
1708
  }
@@ -1732,7 +1716,7 @@ async function planCollections(api, localCollections, appName) {
1732
1716
  if (modified.length > 0) details.push(`~${modified.length} field${modified.length > 1 ? "s" : ""} (${modified.join(", ")})`);
1733
1717
  if (indexesChanged) details.push("indexes changed");
1734
1718
  if (searchChanged) details.push("search changed");
1735
- if (auditChanged) details.push(local.audit ? "record audit enabled" : "record audit disabled");
1719
+ if (auditChanged) details.push(local.audit ? "audit enabled" : "audit disabled");
1736
1720
  const fieldDetails = [];
1737
1721
  for (const name of added) {
1738
1722
  const f = localFieldMap.get(name);
@@ -2202,34 +2186,20 @@ async function applyApp(args) {
2202
2186
  const distDir = resolve(projectRoot, "dist");
2203
2187
  await deploy({ token, appName, appTitle, distDir, apiUrl });
2204
2188
  }
2205
- async function pullCollections(api, platformDir, filterName, appName) {
2189
+ async function pullCollections(api, platformDir, filterName, projectId) {
2206
2190
  const collectionsDir = join2(platformDir, "collections");
2207
2191
  mkdirSync(collectionsDir, { recursive: true });
2208
2192
  const collections = await api.listCollections();
2209
- const existingFiles = /* @__PURE__ */ new Map();
2210
- for (const file of readdirSync2(collectionsDir)) {
2211
- if (!file.endsWith(".json")) continue;
2212
- const filePath = join2(collectionsDir, file);
2213
- try {
2214
- const existing = JSON.parse(readFileSync2(filePath, "utf-8"));
2215
- if (typeof existing.id === "string") existingFiles.set(existing.id, filePath);
2216
- if (typeof existing.name === "string") existingFiles.set(existing.name, filePath);
2217
- } catch {
2218
- }
2219
- }
2220
2193
  for (const collection of collections) {
2221
2194
  if (collection.system || collection.managed) continue;
2222
- if (appName && collection.name.includes(NAMESPACE_SEPARATOR)) {
2223
- const prefix = collection.name.split(NAMESPACE_SEPARATOR)[0];
2224
- if (prefix !== sanitizeSlugForCollectionName(appName)) continue;
2225
- }
2226
- const localName = stripNamespacePrefix(collection.name, appName);
2227
- const localID = stripNamespacePrefix(collection.id, appName);
2228
- if (filterName && localName !== filterName && localID !== filterName && collection.name !== filterName && collection.id !== filterName) {
2195
+ if (projectId && collection.project_id !== projectId) continue;
2196
+ if (!projectId && collection.project_id) continue;
2197
+ const localName = collection.name;
2198
+ if (filterName && localName !== filterName && collection.name !== filterName && collection.id !== filterName) {
2229
2199
  continue;
2230
2200
  }
2231
2201
  const localFormat = {
2232
- id: localID,
2202
+ id: collection.id,
2233
2203
  name: localName,
2234
2204
  audit: collection.audit,
2235
2205
  fields: collection.schema.map((field) => {
@@ -2240,9 +2210,7 @@ async function pullCollections(api, platformDir, filterName, appName) {
2240
2210
  };
2241
2211
  if (field.options) {
2242
2212
  if (field.options.values) localField.values = field.options.values;
2243
- if (field.options.collectionId) {
2244
- localField.collection = stripNamespacePrefix(field.options.collectionId, appName);
2245
- }
2213
+ if (field.options.collectionId) localField.collection = field.options.collectionId;
2246
2214
  if (field.options.maxSelect && field.options.maxSelect > 1) localField.multiple = true;
2247
2215
  if (field.options.defaultCurrency) {
2248
2216
  localField.defaultCurrency = field.options.defaultCurrency;
@@ -2262,10 +2230,10 @@ async function pullCollections(api, platformDir, filterName, appName) {
2262
2230
  }).filter((idx) => idx !== null),
2263
2231
  search: collection.search
2264
2232
  };
2265
- const fileName = `${toSafeFilename(localName)}.json`;
2266
- const filePath = existingFiles.get(localFormat.id) || existingFiles.get(localFormat.name) || join2(collectionsDir, fileName);
2233
+ const fileName = toSafeFilename(localName);
2234
+ const filePath = join2(collectionsDir, `${fileName}.json`);
2267
2235
  writeFileSync(filePath, JSON.stringify(localFormat, null, 2) + "\n");
2268
- console.log(pc2.green(" \u2713"), `${localName} \u2192 collections/${basename2(filePath)}`);
2236
+ console.log(pc2.green(" \u2713"), `${localName} \u2192 collections/${fileName}.json`);
2269
2237
  }
2270
2238
  }
2271
2239
  async function pullAutomations(api, platformDir, filterName, projectId) {
@@ -2637,7 +2605,11 @@ async function listResources(api, platformDir, filterType, appName, projectId) {
2637
2605
  if (!filterType || filterType === "collections") {
2638
2606
  const localCollections = loadLocalCollections(platformDir);
2639
2607
  const remoteCollections = await api.listCollections();
2640
- const remoteByName = new Map(remoteCollections.filter((c) => !c.system && !c.managed).map((c) => [stripNamespacePrefix(c.name, appName), c]));
2608
+ const projectCollections = remoteCollections.filter((collection) => {
2609
+ if (collection.system || collection.managed) return false;
2610
+ return projectId ? collection.project_id === projectId : !collection.project_id;
2611
+ });
2612
+ const remoteByName = new Map(projectCollections.map((collection) => [collection.name, collection]));
2641
2613
  const localNames = new Set(localCollections.map((c) => c.name));
2642
2614
  for (const local of localCollections) {
2643
2615
  const remote = remoteByName.get(local.name);
@@ -2658,15 +2630,9 @@ async function listResources(api, platformDir, filterType, appName, projectId) {
2658
2630
  }
2659
2631
  }
2660
2632
  }
2661
- for (const remote of remoteCollections) {
2662
- if (remote.system || remote.managed) continue;
2663
- if (appName && remote.name.includes(NAMESPACE_SEPARATOR)) {
2664
- const prefix = remote.name.split(NAMESPACE_SEPARATOR)[0];
2665
- if (prefix !== sanitizeSlugForCollectionName(appName)) continue;
2666
- }
2667
- const stripped = stripNamespacePrefix(remote.name, appName);
2668
- if (!localNames.has(stripped)) {
2669
- results.push({ name: stripped, type: "collections", status: "remote-only" });
2633
+ for (const remote of projectCollections) {
2634
+ if (!localNames.has(remote.name)) {
2635
+ results.push({ name: remote.name, type: "collections", status: "remote-only" });
2670
2636
  }
2671
2637
  }
2672
2638
  }
@@ -2850,10 +2816,9 @@ async function destroyResources(api, platformDir, resourceType, resourceName, sk
2850
2816
  if (!resourceType || resourceType === "collections") {
2851
2817
  const localCollections = loadLocalCollections(platformDir, resourceName || void 0);
2852
2818
  const remoteCollections = await api.listCollections();
2853
- const remoteById = new Map(remoteCollections.map((c) => [c.id, c]));
2854
- const remoteByLocalName = new Map(remoteCollections.map((c) => [stripNamespacePrefix(c.name, appName), c]));
2819
+ const remoteByName = new Map(remoteCollections.map((c) => [c.name, c]));
2855
2820
  for (const local of localCollections) {
2856
- const remote = remoteByLocalName.get(local.name) ?? remoteById.get(namespacedCollectionID(local.id, appName)) ?? (!appName ? remoteById.get(local.id) : void 0);
2821
+ const remote = remoteByName.get(local.name);
2857
2822
  if (remote) {
2858
2823
  toDelete.push({ type: "collection", id: local.id, name: local.name, remoteId: remote.id });
2859
2824
  }
@@ -3056,9 +3021,7 @@ async function showResource(api, platformDir, resourceType, resourceName, appNam
3056
3021
  const localCollections = loadLocalCollections(platformDir, resourceName);
3057
3022
  const remoteCollections = await api.listCollections();
3058
3023
  const local = localCollections[0];
3059
- const remote = remoteCollections.find(
3060
- (collection) => stripNamespacePrefix(collection.name, appName) === resourceName || stripNamespacePrefix(collection.id, appName) === resourceName
3061
- );
3024
+ const remote = remoteCollections.find((c) => c.name === resourceName || c.id === resourceName);
3062
3025
  if (!local && !remote) {
3063
3026
  console.log(pc2.red(` Collection "${resourceName}" not found`));
3064
3027
  process.exit(1);
@@ -3289,7 +3252,7 @@ async function plan(args) {
3289
3252
  if (!type || type === "collections") {
3290
3253
  const localCollections = loadLocalCollections(platformDir, name || void 0);
3291
3254
  if (localCollections.length > 0) {
3292
- const changes = await planCollections(api, localCollections, appName);
3255
+ const changes = await planCollections(api, localCollections);
3293
3256
  allChanges.push(...changes);
3294
3257
  }
3295
3258
  }
@@ -3436,7 +3399,7 @@ async function apply(args) {
3436
3399
  const localHooks = !type || type === "hooks" ? loadLocalHooks(platformDir, name || void 0, appName) : [];
3437
3400
  const localAgents = !type || type === "agents" ? loadLocalAgents(platformDir, name || void 0, appName) : [];
3438
3401
  const localMailboxes = !type || type === "mailboxes" ? loadLocalMailboxes(platformDir, name || void 0) : [];
3439
- if (localCollections.length > 0) allChanges.push(...await planCollections(api, localCollections, appName));
3402
+ if (localCollections.length > 0) allChanges.push(...await planCollections(api, localCollections));
3440
3403
  if (localAutomations.length > 0) allChanges.push(...await planAutomations(api, localAutomations, projectId));
3441
3404
  if (localHooks.length > 0) allChanges.push(...await planHooks(api, localHooks, collections, projectId));
3442
3405
  if (localAgents.length > 0) allChanges.push(...await planAgents(api, localAgents, projectId));
@@ -3630,7 +3593,7 @@ async function pull(args) {
3630
3593
  console.log();
3631
3594
  if (!type || type === "collections") {
3632
3595
  console.log(pc2.bold(" Collections:"));
3633
- await pullCollections(api, platformDir, name || void 0, appName);
3596
+ await pullCollections(api, platformDir, name || void 0, projectId);
3634
3597
  console.log();
3635
3598
  if (!name) {
3636
3599
  console.log(pc2.bold(" Resource shares:"));
@@ -3961,9 +3924,9 @@ export {
3961
3924
  applyCollections,
3962
3925
  convertCollectionToApiFormat,
3963
3926
  destroy,
3964
- destroyResources,
3965
3927
  diff,
3966
3928
  list,
3929
+ loadLocalCollections,
3967
3930
  plan,
3968
3931
  planCollections,
3969
3932
  pull,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumerahq/cli",
3
- "version": "0.23.0-dev.2",
3
+ "version": "0.23.0-dev.3",
4
4
  "description": "CLI for building and deploying Lumera apps",
5
5
  "type": "module",
6
6
  "engines": {
@@ -24,7 +24,7 @@
24
24
  "check:ci": "biome check . && tsr generate && tsc --noEmit"
25
25
  },
26
26
  "dependencies": {
27
- "@lumerahq/ui": "^0.13.0",
27
+ "@lumerahq/ui": "^0.13.0-dev.2",
28
28
  "@tanstack/react-query": "^5.90.11",
29
29
  "@tanstack/react-router": "1.155.0",
30
30
  "clsx": "^2.1.1",