@lumerahq/cli 0.24.3 → 0.24.5
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.
|
@@ -24,21 +24,14 @@ function formatTimestampVersion(date = /* @__PURE__ */ new Date()) {
|
|
|
24
24
|
pad(date.getUTCSeconds())
|
|
25
25
|
].join("") + "Z";
|
|
26
26
|
}
|
|
27
|
-
function resolveVersion(cwd) {
|
|
27
|
+
function resolveVersion(cwd, gitRelease = resolveGitReleaseState(cwd)) {
|
|
28
28
|
const pkgPath = resolve(cwd, "package.json");
|
|
29
29
|
try {
|
|
30
30
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
31
31
|
if (pkg?.version && pkg.version !== "0.0.0") return String(pkg.version);
|
|
32
32
|
} catch {
|
|
33
33
|
}
|
|
34
|
-
|
|
35
|
-
const sha = execSync("git rev-parse --short HEAD", {
|
|
36
|
-
cwd,
|
|
37
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
38
|
-
}).toString().trim();
|
|
39
|
-
if (sha) return sha;
|
|
40
|
-
} catch {
|
|
41
|
-
}
|
|
34
|
+
if (gitRelease.sha) return gitRelease.sha.slice(0, 7);
|
|
42
35
|
return formatTimestampVersion();
|
|
43
36
|
}
|
|
44
37
|
function resolveUIVersion(cwd) {
|
|
@@ -59,14 +52,30 @@ function resolveUIVersion(cwd) {
|
|
|
59
52
|
return "";
|
|
60
53
|
}
|
|
61
54
|
}
|
|
62
|
-
function
|
|
55
|
+
function assertDeployableGitRelease(gitRelease) {
|
|
56
|
+
if (gitRelease.sha && gitRelease.dirty) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
"Deploy requires a clean Git working tree so the published app matches its recorded commit. Commit or stash changes, then run lumera apply again."
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function resolveGitReleaseState(cwd) {
|
|
63
63
|
try {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
const lines = execSync(
|
|
65
|
+
"git status --porcelain=v2 --branch --untracked-files=normal",
|
|
66
|
+
{
|
|
67
|
+
cwd,
|
|
68
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
69
|
+
}
|
|
70
|
+
).toString().trim().split("\n");
|
|
71
|
+
const oidLine = lines.find((line) => line.startsWith("# branch.oid "));
|
|
72
|
+
const oid = oidLine?.slice("# branch.oid ".length).trim() ?? "";
|
|
73
|
+
return {
|
|
74
|
+
sha: oid === "(initial)" ? "" : oid,
|
|
75
|
+
dirty: lines.some((line) => line !== "" && !line.startsWith("# "))
|
|
76
|
+
};
|
|
68
77
|
} catch {
|
|
69
|
-
return "";
|
|
78
|
+
return { sha: "", dirty: false };
|
|
70
79
|
}
|
|
71
80
|
}
|
|
72
81
|
async function createTarball(distDir) {
|
|
@@ -114,19 +123,21 @@ async function deploy(options) {
|
|
|
114
123
|
if (!existsSync(distDir)) {
|
|
115
124
|
throw new Error(`dist directory not found: ${distDir}`);
|
|
116
125
|
}
|
|
126
|
+
const projectDir = dirname(distDir);
|
|
127
|
+
const gitRelease = resolveGitReleaseState(projectDir);
|
|
128
|
+
assertDeployableGitRelease(gitRelease);
|
|
117
129
|
console.log(pc.dim("Ensuring app record..."));
|
|
118
130
|
await ensureAppRecord(apiUrl, token, appName, appTitle, accessLevel);
|
|
119
131
|
console.log(pc.cyan(`Deploying ${appTitle}...`));
|
|
120
|
-
const version = options.version || process.env.LUMERA_APP_VERSION?.trim() || resolveVersion(
|
|
132
|
+
const version = options.version || process.env.LUMERA_APP_VERSION?.trim() || resolveVersion(projectDir, gitRelease);
|
|
121
133
|
console.log(pc.dim(`Version: ${version}`));
|
|
122
134
|
const tarball = await createTarball(distDir);
|
|
123
135
|
console.log(pc.dim(`Package: ${(tarball.length / 1024).toFixed(1)} KB`));
|
|
124
136
|
const formData = new FormData();
|
|
125
137
|
formData.append("tarball", new Blob([new Uint8Array(tarball)]), "dist.tar.gz");
|
|
126
138
|
formData.append("version", version);
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const uiVersion = resolveUIVersion(dirname(distDir));
|
|
139
|
+
if (gitRelease.sha) formData.append("git_sha", gitRelease.sha);
|
|
140
|
+
const uiVersion = resolveUIVersion(projectDir);
|
|
130
141
|
if (uiVersion) formData.append("ui_version", uiVersion);
|
|
131
142
|
const res = await fetchWithRetry(`${apiUrl}/custom-apps/${appName}/deploy`, {
|
|
132
143
|
method: "POST",
|
package/dist/index.js
CHANGED
|
@@ -227,29 +227,29 @@ async function main() {
|
|
|
227
227
|
switch (command) {
|
|
228
228
|
// Resource commands
|
|
229
229
|
case "plan":
|
|
230
|
-
await import("./resources-
|
|
230
|
+
await import("./resources-XQHHIQYV.js").then((m) => m.plan(args.slice(1)));
|
|
231
231
|
break;
|
|
232
232
|
case "apply":
|
|
233
|
-
await import("./resources-
|
|
233
|
+
await import("./resources-XQHHIQYV.js").then((m) => m.apply(args.slice(1)));
|
|
234
234
|
break;
|
|
235
235
|
case "pull":
|
|
236
|
-
await import("./resources-
|
|
236
|
+
await import("./resources-XQHHIQYV.js").then((m) => m.pull(args.slice(1)));
|
|
237
237
|
break;
|
|
238
238
|
case "destroy":
|
|
239
|
-
await import("./resources-
|
|
239
|
+
await import("./resources-XQHHIQYV.js").then((m) => m.destroy(args.slice(1)));
|
|
240
240
|
break;
|
|
241
241
|
case "list":
|
|
242
|
-
await import("./resources-
|
|
242
|
+
await import("./resources-XQHHIQYV.js").then((m) => m.list(args.slice(1)));
|
|
243
243
|
break;
|
|
244
244
|
case "show":
|
|
245
|
-
await import("./resources-
|
|
245
|
+
await import("./resources-XQHHIQYV.js").then((m) => m.show(args.slice(1)));
|
|
246
246
|
break;
|
|
247
247
|
case "diff":
|
|
248
|
-
await import("./resources-
|
|
248
|
+
await import("./resources-XQHHIQYV.js").then((m) => m.diff(args.slice(1)));
|
|
249
249
|
break;
|
|
250
250
|
// Development
|
|
251
251
|
case "dev":
|
|
252
|
-
await import("./dev-
|
|
252
|
+
await import("./dev-OJEV76DA.js").then((m) => m.dev(args.slice(1)));
|
|
253
253
|
break;
|
|
254
254
|
case "run":
|
|
255
255
|
await import("./run-WHVUVIYB.js").then((m) => m.run(args.slice(1)));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
deploy
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-KC3VBP6R.js";
|
|
4
4
|
import {
|
|
5
5
|
syncDeps
|
|
6
6
|
} from "./chunk-7ZTCXKII.js";
|
|
@@ -183,6 +183,11 @@ var collectionSchemaRule = {
|
|
|
183
183
|
}
|
|
184
184
|
if (!Array.isArray(index.fields) || !index.fields.every((field) => typeof field === "string" && field.trim() !== "")) {
|
|
185
185
|
issues.push(error(target, `Index at index ${i} must include a non-empty string array "fields".`));
|
|
186
|
+
} else if (index.fields.length === 1 && index.fields[0].trim().toLowerCase() === "updated" && index.unique !== true) {
|
|
187
|
+
issues.push(error(
|
|
188
|
+
target,
|
|
189
|
+
`Index at index ${i} exactly duplicates Lumera's managed non-unique "updated" index. Remove the redundant declaration.`
|
|
190
|
+
));
|
|
186
191
|
}
|
|
187
192
|
}
|
|
188
193
|
}
|
|
@@ -898,6 +903,14 @@ function stripNamespacePrefix(name, appName) {
|
|
|
898
903
|
}
|
|
899
904
|
return name;
|
|
900
905
|
}
|
|
906
|
+
function buildIndexSql(local, idx, appName) {
|
|
907
|
+
const fields = idx.fields.join(", ");
|
|
908
|
+
const unique = idx.unique ? "UNIQUE " : "";
|
|
909
|
+
const physicalId = appName ? sanitizeSlugForCollectionName(appName) + NAMESPACE_SEPARATOR + local.id : local.id;
|
|
910
|
+
const indexTypeTag = idx.unique ? "u" : "n";
|
|
911
|
+
const indexName = `idx_${physicalId}_${indexTypeTag}_${idx.fields.join("_")}`;
|
|
912
|
+
return `CREATE ${unique}INDEX ${indexName} ON ${local.name} (${fields})`;
|
|
913
|
+
}
|
|
901
914
|
var AGENT_IDLE_REAP_TIMEOUT_MIN_SECONDS = 10;
|
|
902
915
|
var AGENT_IDLE_REAP_TIMEOUT_MAX_SECONDS = 900;
|
|
903
916
|
function buildCollectionIdMap(collections, appName) {
|
|
@@ -1516,7 +1529,7 @@ function loadLocalHooks(platformDir, filterName, appName) {
|
|
|
1516
1529
|
}
|
|
1517
1530
|
return hooks;
|
|
1518
1531
|
}
|
|
1519
|
-
function convertCollectionToApiFormat(local) {
|
|
1532
|
+
function convertCollectionToApiFormat(local, appName) {
|
|
1520
1533
|
const schema = local.fields.map((field) => {
|
|
1521
1534
|
const apiField = {
|
|
1522
1535
|
name: field.name,
|
|
@@ -1545,12 +1558,7 @@ function convertCollectionToApiFormat(local) {
|
|
|
1545
1558
|
}
|
|
1546
1559
|
return apiField;
|
|
1547
1560
|
});
|
|
1548
|
-
const indexes = local.indexes?.map((idx) =>
|
|
1549
|
-
const fields = idx.fields.join(", ");
|
|
1550
|
-
const unique = idx.unique ? "UNIQUE " : "";
|
|
1551
|
-
const indexName = `idx_${local.id}_${idx.fields.join("_")}`;
|
|
1552
|
-
return `CREATE ${unique}INDEX ${indexName} ON ${local.name} (${fields})`;
|
|
1553
|
-
});
|
|
1561
|
+
const indexes = local.indexes?.map((idx) => buildIndexSql(local, idx, appName));
|
|
1554
1562
|
return {
|
|
1555
1563
|
id: local.id,
|
|
1556
1564
|
name: local.name,
|
|
@@ -1623,24 +1631,15 @@ function fieldsDiffer(local, remote) {
|
|
|
1623
1631
|
if (localMax !== remoteMax) return true;
|
|
1624
1632
|
return false;
|
|
1625
1633
|
}
|
|
1626
|
-
function localIndexesToSql(local) {
|
|
1634
|
+
function localIndexesToSql(local, appName) {
|
|
1627
1635
|
if (!local.indexes || local.indexes.length === 0) return [];
|
|
1628
|
-
return local.indexes.map((idx) =>
|
|
1629
|
-
const fields = idx.fields.join(", ");
|
|
1630
|
-
const unique = idx.unique ? "UNIQUE " : "";
|
|
1631
|
-
const indexName = `idx_${local.id}_${idx.fields.join("_")}`;
|
|
1632
|
-
return `CREATE ${unique}INDEX ${indexName} ON ${local.name} (${fields})`;
|
|
1633
|
-
}).sort();
|
|
1636
|
+
return local.indexes.map((idx) => buildIndexSql(local, idx, appName)).sort();
|
|
1634
1637
|
}
|
|
1635
1638
|
function normalizeRemoteIndexes(remoteIndexes) {
|
|
1636
|
-
return remoteIndexes.
|
|
1637
|
-
const lower = idx.toLowerCase();
|
|
1638
|
-
if (lower.includes("external_id") || lower.includes("updated")) return false;
|
|
1639
|
-
return true;
|
|
1640
|
-
}).sort();
|
|
1639
|
+
return [...remoteIndexes].sort();
|
|
1641
1640
|
}
|
|
1642
|
-
function indexesDiffer(local, remoteIndexes) {
|
|
1643
|
-
const localSql = localIndexesToSql(local);
|
|
1641
|
+
function indexesDiffer(local, remoteIndexes, appName) {
|
|
1642
|
+
const localSql = localIndexesToSql(local, appName);
|
|
1644
1643
|
const remoteSql = normalizeRemoteIndexes(remoteIndexes);
|
|
1645
1644
|
if (localSql.length !== remoteSql.length) return true;
|
|
1646
1645
|
for (let i = 0; i < localSql.length; i++) {
|
|
@@ -1668,7 +1667,7 @@ function normalizeCollectionSearch(search) {
|
|
|
1668
1667
|
} : {}
|
|
1669
1668
|
});
|
|
1670
1669
|
}
|
|
1671
|
-
async function planCollections(api, localCollections) {
|
|
1670
|
+
async function planCollections(api, localCollections, appName) {
|
|
1672
1671
|
const changes = [];
|
|
1673
1672
|
const remoteCollections = await api.listCollections();
|
|
1674
1673
|
const remoteById = new Map(remoteCollections.map((c) => [c.id, c]));
|
|
@@ -1722,7 +1721,7 @@ async function planCollections(api, localCollections) {
|
|
|
1722
1721
|
modified.push(name);
|
|
1723
1722
|
}
|
|
1724
1723
|
}
|
|
1725
|
-
const indexesChanged = indexesDiffer(local, remote.indexes || []);
|
|
1724
|
+
const indexesChanged = indexesDiffer(local, remote.indexes || [], appName);
|
|
1726
1725
|
const searchChanged = normalizeCollectionSearch(local.search) !== normalizeCollectionSearch(remote.search);
|
|
1727
1726
|
const auditChanged = local.audit !== void 0 && local.audit !== remote.audit;
|
|
1728
1727
|
if (added.length > 0 || removed.length > 0 || modified.length > 0 || indexesChanged || searchChanged || auditChanged) {
|
|
@@ -1992,7 +1991,7 @@ async function planHooks(api, localHooks, collections, projectId) {
|
|
|
1992
1991
|
}
|
|
1993
1992
|
return changes;
|
|
1994
1993
|
}
|
|
1995
|
-
async function applyCollections(api, localCollections) {
|
|
1994
|
+
async function applyCollections(api, localCollections, appName) {
|
|
1996
1995
|
let errors = 0;
|
|
1997
1996
|
const hasRelations = localCollections.some((c) => c.fields.some((f) => f.type === "relation"));
|
|
1998
1997
|
if (hasRelations) {
|
|
@@ -2009,7 +2008,7 @@ async function applyCollections(api, localCollections) {
|
|
|
2009
2008
|
}
|
|
2010
2009
|
for (const local of localCollections) {
|
|
2011
2010
|
if (pass1Failed.has(local.name)) continue;
|
|
2012
|
-
const apiFormat = convertCollectionToApiFormat(local);
|
|
2011
|
+
const apiFormat = convertCollectionToApiFormat(local, appName);
|
|
2013
2012
|
try {
|
|
2014
2013
|
await api.ensureCollection(local.name, apiFormat);
|
|
2015
2014
|
console.log(pc2.green(" \u2713"), `${local.name} (schema)`);
|
|
@@ -2020,7 +2019,7 @@ async function applyCollections(api, localCollections) {
|
|
|
2020
2019
|
}
|
|
2021
2020
|
} else {
|
|
2022
2021
|
for (const local of localCollections) {
|
|
2023
|
-
const apiFormat = convertCollectionToApiFormat(local);
|
|
2022
|
+
const apiFormat = convertCollectionToApiFormat(local, appName);
|
|
2024
2023
|
try {
|
|
2025
2024
|
await api.ensureCollection(local.name, apiFormat);
|
|
2026
2025
|
console.log(pc2.green(" \u2713"), `${local.name}`);
|
|
@@ -3282,7 +3281,7 @@ async function plan(args) {
|
|
|
3282
3281
|
if (!type || type === "collections") {
|
|
3283
3282
|
const localCollections = loadLocalCollections(platformDir, name || void 0);
|
|
3284
3283
|
if (localCollections.length > 0) {
|
|
3285
|
-
const changes = await planCollections(api, localCollections);
|
|
3284
|
+
const changes = await planCollections(api, localCollections, appName);
|
|
3286
3285
|
allChanges.push(...changes);
|
|
3287
3286
|
}
|
|
3288
3287
|
}
|
|
@@ -3429,7 +3428,7 @@ async function apply(args) {
|
|
|
3429
3428
|
const localHooks = !type || type === "hooks" ? loadLocalHooks(platformDir, name || void 0, appName) : [];
|
|
3430
3429
|
const localAgents = !type || type === "agents" ? loadLocalAgents(platformDir, name || void 0, appName) : [];
|
|
3431
3430
|
const localMailboxes = !type || type === "mailboxes" ? loadLocalMailboxes(platformDir, name || void 0) : [];
|
|
3432
|
-
if (localCollections.length > 0) allChanges.push(...await planCollections(api, localCollections));
|
|
3431
|
+
if (localCollections.length > 0) allChanges.push(...await planCollections(api, localCollections, appName));
|
|
3433
3432
|
if (localAutomations.length > 0) allChanges.push(...await planAutomations(api, localAutomations, projectId));
|
|
3434
3433
|
if (localHooks.length > 0) allChanges.push(...await planHooks(api, localHooks, collections, projectId));
|
|
3435
3434
|
if (localAgents.length > 0) allChanges.push(...await planAgents(api, localAgents, projectId));
|
|
@@ -3504,7 +3503,7 @@ async function apply(args) {
|
|
|
3504
3503
|
let totalSkipped = 0;
|
|
3505
3504
|
if (localCollections.length > 0) {
|
|
3506
3505
|
console.log(pc2.bold(" Collections:"));
|
|
3507
|
-
totalErrors += await applyCollections(api, localCollections);
|
|
3506
|
+
totalErrors += await applyCollections(api, localCollections, appName);
|
|
3508
3507
|
console.log();
|
|
3509
3508
|
}
|
|
3510
3509
|
try {
|