@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-
|
|
229
|
+
await import("./resources-QCCLRDOL.js").then((m) => m.plan(args.slice(1)));
|
|
230
230
|
break;
|
|
231
231
|
case "apply":
|
|
232
|
-
await import("./resources-
|
|
232
|
+
await import("./resources-QCCLRDOL.js").then((m) => m.apply(args.slice(1)));
|
|
233
233
|
break;
|
|
234
234
|
case "pull":
|
|
235
|
-
await import("./resources-
|
|
235
|
+
await import("./resources-QCCLRDOL.js").then((m) => m.pull(args.slice(1)));
|
|
236
236
|
break;
|
|
237
237
|
case "destroy":
|
|
238
|
-
await import("./resources-
|
|
238
|
+
await import("./resources-QCCLRDOL.js").then((m) => m.destroy(args.slice(1)));
|
|
239
239
|
break;
|
|
240
240
|
case "list":
|
|
241
|
-
await import("./resources-
|
|
241
|
+
await import("./resources-QCCLRDOL.js").then((m) => m.list(args.slice(1)));
|
|
242
242
|
break;
|
|
243
243
|
case "show":
|
|
244
|
-
await import("./resources-
|
|
244
|
+
await import("./resources-QCCLRDOL.js").then((m) => m.show(args.slice(1)));
|
|
245
245
|
break;
|
|
246
246
|
case "diff":
|
|
247
|
-
await import("./resources-
|
|
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,
|
|
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
|
-
|
|
1574
|
-
|
|
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: "
|
|
1583
|
-
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
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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:
|
|
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
|
|
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 ? "
|
|
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,
|
|
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 (
|
|
2223
|
-
|
|
2224
|
-
|
|
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:
|
|
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 =
|
|
2266
|
-
const filePath =
|
|
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/${
|
|
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
|
|
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
|
|
2662
|
-
if (
|
|
2663
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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,
|
|
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