@lumerahq/cli 0.24.4 → 0.24.6

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
- try {
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 resolveGitSha(cwd) {
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
- return execSync("git rev-parse HEAD", {
65
- cwd,
66
- stdio: ["ignore", "pipe", "ignore"]
67
- }).toString().trim();
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(dirname(distDir));
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
- const gitSha = resolveGitSha(dirname(distDir));
128
- if (gitSha) formData.append("git_sha", gitSha);
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",
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  dev
3
- } from "./chunk-KBNM6R5X.js";
3
+ } from "./chunk-KC3VBP6R.js";
4
4
  import {
5
5
  syncDeps
6
6
  } from "./chunk-7ZTCXKII.js";
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-2PAJHJO7.js").then((m) => m.plan(args.slice(1)));
230
+ await import("./resources-R53XKJL2.js").then((m) => m.plan(args.slice(1)));
231
231
  break;
232
232
  case "apply":
233
- await import("./resources-2PAJHJO7.js").then((m) => m.apply(args.slice(1)));
233
+ await import("./resources-R53XKJL2.js").then((m) => m.apply(args.slice(1)));
234
234
  break;
235
235
  case "pull":
236
- await import("./resources-2PAJHJO7.js").then((m) => m.pull(args.slice(1)));
236
+ await import("./resources-R53XKJL2.js").then((m) => m.pull(args.slice(1)));
237
237
  break;
238
238
  case "destroy":
239
- await import("./resources-2PAJHJO7.js").then((m) => m.destroy(args.slice(1)));
239
+ await import("./resources-R53XKJL2.js").then((m) => m.destroy(args.slice(1)));
240
240
  break;
241
241
  case "list":
242
- await import("./resources-2PAJHJO7.js").then((m) => m.list(args.slice(1)));
242
+ await import("./resources-R53XKJL2.js").then((m) => m.list(args.slice(1)));
243
243
  break;
244
244
  case "show":
245
- await import("./resources-2PAJHJO7.js").then((m) => m.show(args.slice(1)));
245
+ await import("./resources-R53XKJL2.js").then((m) => m.show(args.slice(1)));
246
246
  break;
247
247
  case "diff":
248
- await import("./resources-2PAJHJO7.js").then((m) => m.diff(args.slice(1)));
248
+ await import("./resources-R53XKJL2.js").then((m) => m.diff(args.slice(1)));
249
249
  break;
250
250
  // Development
251
251
  case "dev":
252
- await import("./dev-N5CEEMFC.js").then((m) => m.dev(args.slice(1)));
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-KBNM6R5X.js";
3
+ } from "./chunk-KC3VBP6R.js";
4
4
  import {
5
5
  syncDeps
6
6
  } from "./chunk-7ZTCXKII.js";
@@ -1667,10 +1667,12 @@ function normalizeCollectionSearch(search) {
1667
1667
  } : {}
1668
1668
  });
1669
1669
  }
1670
- async function planCollections(api, localCollections, appName) {
1670
+ async function planCollections(api, localCollections, appName, projectId) {
1671
1671
  const changes = [];
1672
1672
  const remoteCollections = await api.listCollections();
1673
- const remoteById = new Map(remoteCollections.map((c) => [c.id, c]));
1673
+ const remoteById = new Map(
1674
+ remoteCollections.filter((collection) => !projectId || !collection.project_id || collection.project_id === projectId).map((collection) => [collection.id, collection])
1675
+ );
1674
1676
  for (const local of localCollections) {
1675
1677
  let remote = remoteById.get(local.id);
1676
1678
  if (!remote) {
@@ -1684,7 +1686,7 @@ async function planCollections(api, localCollections, appName) {
1684
1686
  break;
1685
1687
  }
1686
1688
  } catch (error3) {
1687
- if (!isApiErrorStatus(error3, 404)) throw error3;
1689
+ if (!isApiErrorStatus(error3, 404) && !isApiErrorStatus(error3, 403)) throw error3;
1688
1690
  }
1689
1691
  }
1690
1692
  }
@@ -3281,7 +3283,7 @@ async function plan(args) {
3281
3283
  if (!type || type === "collections") {
3282
3284
  const localCollections = loadLocalCollections(platformDir, name || void 0);
3283
3285
  if (localCollections.length > 0) {
3284
- const changes = await planCollections(api, localCollections, appName);
3286
+ const changes = await planCollections(api, localCollections, appName, projectId);
3285
3287
  allChanges.push(...changes);
3286
3288
  }
3287
3289
  }
@@ -3428,7 +3430,7 @@ async function apply(args) {
3428
3430
  const localHooks = !type || type === "hooks" ? loadLocalHooks(platformDir, name || void 0, appName) : [];
3429
3431
  const localAgents = !type || type === "agents" ? loadLocalAgents(platformDir, name || void 0, appName) : [];
3430
3432
  const localMailboxes = !type || type === "mailboxes" ? loadLocalMailboxes(platformDir, name || void 0) : [];
3431
- if (localCollections.length > 0) allChanges.push(...await planCollections(api, localCollections, appName));
3433
+ if (localCollections.length > 0) allChanges.push(...await planCollections(api, localCollections, appName, projectId));
3432
3434
  if (localAutomations.length > 0) allChanges.push(...await planAutomations(api, localAutomations, projectId));
3433
3435
  if (localHooks.length > 0) allChanges.push(...await planHooks(api, localHooks, collections, projectId));
3434
3436
  if (localAgents.length > 0) allChanges.push(...await planAgents(api, localAgents, projectId));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumerahq/cli",
3
- "version": "0.24.4",
3
+ "version": "0.24.6",
4
4
  "description": "CLI for building and deploying Lumera apps",
5
5
  "type": "module",
6
6
  "engines": {