bod-cli 0.5.4 → 0.5.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.
package/dist/cli.js CHANGED
@@ -18976,7 +18976,77 @@ async function uploadDeploy(client, appId, branch) {
18976
18976
  console.log(source_default.dim(`Including siblings: ${siblingPaths.join(", ")}`));
18977
18977
  console.log(source_default.dim(`Packing source (excluding: ${allExcludes.join(", ")})...`));
18978
18978
  const tmpFile = `${Bun.env.TMPDIR || "/tmp"}/bod-deploy-${Date.now()}.tar.gz`;
18979
- const tar = Bun.spawnSync(["tar", "cz", ...excludeFlags, "-f", tmpFile, ".", ...siblingPaths], { stderr: "pipe" });
18979
+ const env3 = { ...process.env, COPYFILE_DISABLE: "1" };
18980
+ const fs = __require("fs");
18981
+ const { resolve, basename, join: join3 } = __require("path");
18982
+ const siblingMap = new Map;
18983
+ const siblingArgs = [];
18984
+ for (const sp of siblingPaths) {
18985
+ const abs = resolve(sp);
18986
+ const name = basename(abs);
18987
+ siblingMap.set(sp, name);
18988
+ siblingArgs.push("-C", abs.slice(0, abs.lastIndexOf("/")), name);
18989
+ }
18990
+ const rewritten = [];
18991
+ const rewritePkg = (pkgPath) => {
18992
+ if (!fs.existsSync(pkgPath))
18993
+ return;
18994
+ const original = fs.readFileSync(pkgPath, "utf8");
18995
+ let content = original;
18996
+ for (const [rel, name] of siblingMap) {
18997
+ content = content.replace(new RegExp(`"file:[^"]*${name}"`, "g"), `"file:./${name}"`);
18998
+ }
18999
+ if (content !== original) {
19000
+ rewritten.push({ path: pkgPath, original });
19001
+ fs.writeFileSync(pkgPath, content);
19002
+ }
19003
+ };
19004
+ rewritePkg(join3(process.cwd(), "package.json"));
19005
+ try {
19006
+ const rootPkg = JSON.parse(fs.readFileSync(join3(process.cwd(), "package.json"), "utf8"));
19007
+ for (const pattern of rootPkg.workspaces ?? []) {
19008
+ const base = join3(process.cwd(), pattern.replace(/\/?\*$/, ""));
19009
+ if (!fs.existsSync(base))
19010
+ continue;
19011
+ for (const sub of fs.readdirSync(base)) {
19012
+ rewritePkg(join3(base, sub, "package.json"));
19013
+ }
19014
+ }
19015
+ } catch {}
19016
+ const includedSiblings = new Set([...siblingMap.values()]);
19017
+ for (const sp of siblingPaths) {
19018
+ const abs = resolve(sp);
19019
+ const sibPkgPath = join3(abs, "package.json");
19020
+ if (!fs.existsSync(sibPkgPath))
19021
+ continue;
19022
+ const original = fs.readFileSync(sibPkgPath, "utf8");
19023
+ const sibPkg = JSON.parse(original);
19024
+ let changed = false;
19025
+ for (const field of ["dependencies", "devDependencies"]) {
19026
+ if (!sibPkg[field])
19027
+ continue;
19028
+ for (const [name, ver] of Object.entries(sibPkg[field])) {
19029
+ if (!ver.startsWith("file:") || !ver.includes(".."))
19030
+ continue;
19031
+ const depName = basename(resolve(abs, ver.slice(5)));
19032
+ if (!includedSiblings.has(depName)) {
19033
+ sibPkg[field][name] = "*";
19034
+ changed = true;
19035
+ }
19036
+ }
19037
+ }
19038
+ if (changed) {
19039
+ rewritten.push({ path: sibPkgPath, original });
19040
+ fs.writeFileSync(sibPkgPath, JSON.stringify(sibPkg, null, 2) + `
19041
+ `);
19042
+ }
19043
+ }
19044
+ const tar = Bun.spawnSync(["tar", "czh", ...excludeFlags, "-f", tmpFile, ".", ...siblingArgs], {
19045
+ stderr: "pipe",
19046
+ env: env3
19047
+ });
19048
+ for (const { path, original } of rewritten)
19049
+ fs.writeFileSync(path, original);
18980
19050
  if (tar.exitCode !== 0) {
18981
19051
  const errText = tar.stderr.toString();
18982
19052
  throw new Error(`tar failed: ${errText}`);
@@ -19047,6 +19117,14 @@ async function pollDeploy(client, appId, since, instanceCaps, localConfig) {
19047
19117
  } else {
19048
19118
  displayUrl = `https://${host}`;
19049
19119
  }
19120
+ if (!isPreview) {
19121
+ try {
19122
+ const domains = await client.get(`/apps/${appId}/domains`);
19123
+ const verified = domains?.find((d2) => d2.status === "active" || d2.verified);
19124
+ if (verified)
19125
+ displayUrl = `https://${verified.domain}`;
19126
+ } catch {}
19127
+ }
19050
19128
  console.log(` → ${displayUrl}`);
19051
19129
  if (isPreview)
19052
19130
  console.log(source_default.yellow(` ⚠ Preview deployment (branch: ${latest.branch})`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bod-cli",
3
- "version": "0.5.4",
3
+ "version": "0.5.5",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "bod": "./dist/cli.js"
@@ -29,7 +29,83 @@ async function uploadDeploy(client: BodClient, appId: string, branch: string) {
29
29
 
30
30
  console.log(chalk.dim(`Packing source (excluding: ${allExcludes.join(', ')})...`))
31
31
  const tmpFile = `${Bun.env.TMPDIR || '/tmp'}/bod-deploy-${Date.now()}.tar.gz`
32
- const tar = Bun.spawnSync(['tar', 'cz', ...excludeFlags, '-f', tmpFile, '.', ...siblingPaths], { stderr: 'pipe' })
32
+ const env = { ...process.env, COPYFILE_DISABLE: '1' } // suppress macOS ._ resource forks
33
+ const fs = require('fs')
34
+ const { resolve, basename, join } = require('path')
35
+
36
+ // Siblings use `../` relative paths which GNU tar on the server rejects.
37
+ // Strategy: pack siblings at root level (no `..`), rewrite file:../X → file:./X in package.jsons.
38
+ const siblingMap = new Map<string, string>() // originalRelPath → basename
39
+ const siblingArgs: string[] = []
40
+ for (const sp of siblingPaths) {
41
+ const abs = resolve(sp)
42
+ const name = basename(abs)
43
+ siblingMap.set(sp, name)
44
+ siblingArgs.push('-C', abs.slice(0, abs.lastIndexOf('/')), name)
45
+ }
46
+
47
+ // Rewrite file:.. deps in package.json files so the server finds siblings at ./
48
+ const rewritten: { path: string; original: string }[] = []
49
+ const rewritePkg = (pkgPath: string) => {
50
+ if (!fs.existsSync(pkgPath)) return
51
+ const original = fs.readFileSync(pkgPath, 'utf8')
52
+ let content = original
53
+ for (const [rel, name] of siblingMap) {
54
+ // Rewrite file:../X to file:./X (X is the sibling basename)
55
+ content = content.replace(new RegExp(`"file:[^"]*${name}"`, 'g'), `"file:./${name}"`)
56
+ }
57
+ if (content !== original) {
58
+ rewritten.push({ path: pkgPath, original })
59
+ fs.writeFileSync(pkgPath, content)
60
+ }
61
+ }
62
+
63
+ // Rewrite root + workspace package.jsons (file:../X → file:./X for included siblings)
64
+ rewritePkg(join(process.cwd(), 'package.json'))
65
+ try {
66
+ const rootPkg = JSON.parse(fs.readFileSync(join(process.cwd(), 'package.json'), 'utf8'))
67
+ for (const pattern of rootPkg.workspaces ?? []) {
68
+ const base = join(process.cwd(), pattern.replace(/\/?\*$/, ''))
69
+ if (!fs.existsSync(base)) continue
70
+ for (const sub of fs.readdirSync(base)) {
71
+ rewritePkg(join(base, sub, 'package.json'))
72
+ }
73
+ }
74
+ } catch {}
75
+
76
+ // Rewrite sibling package.jsons: file:.. deps that aren't included become "*" (npm fallback)
77
+ const includedSiblings = new Set([...siblingMap.values()])
78
+ for (const sp of siblingPaths) {
79
+ const abs = resolve(sp)
80
+ const sibPkgPath = join(abs, 'package.json')
81
+ if (!fs.existsSync(sibPkgPath)) continue
82
+ const original = fs.readFileSync(sibPkgPath, 'utf8')
83
+ const sibPkg = JSON.parse(original)
84
+ let changed = false
85
+ for (const field of ['dependencies', 'devDependencies']) {
86
+ if (!sibPkg[field]) continue
87
+ for (const [name, ver] of Object.entries(sibPkg[field]) as [string, string][]) {
88
+ if (!ver.startsWith('file:') || !ver.includes('..')) continue
89
+ const depName = basename(resolve(abs, ver.slice(5)))
90
+ if (!includedSiblings.has(depName)) {
91
+ sibPkg[field][name] = '*'
92
+ changed = true
93
+ }
94
+ }
95
+ }
96
+ if (changed) {
97
+ rewritten.push({ path: sibPkgPath, original })
98
+ fs.writeFileSync(sibPkgPath, JSON.stringify(sibPkg, null, 2) + '\n')
99
+ }
100
+ }
101
+
102
+ const tar = Bun.spawnSync(['tar', 'czh', ...excludeFlags, '-f', tmpFile, '.', ...siblingArgs], {
103
+ stderr: 'pipe',
104
+ env,
105
+ })
106
+
107
+ // Restore original package.json files
108
+ for (const { path, original } of rewritten) fs.writeFileSync(path, original)
33
109
  if (tar.exitCode !== 0) {
34
110
  const errText = tar.stderr.toString()
35
111
  throw new Error(`tar failed: ${errText}`)
@@ -112,6 +188,16 @@ async function pollDeploy(client: BodClient, appId: string, since: number, insta
112
188
  } else {
113
189
  displayUrl = `https://${host}`
114
190
  }
191
+
192
+ // Show custom domain if configured (production branch only)
193
+ if (!isPreview) {
194
+ try {
195
+ const domains = await client.get<any[]>(`/apps/${appId}/domains`)
196
+ const verified = domains?.find((d: any) => d.status === 'active' || d.verified)
197
+ if (verified) displayUrl = `https://${verified.domain}`
198
+ } catch {}
199
+ }
200
+
115
201
  console.log(` → ${displayUrl}`)
116
202
  if (isPreview) console.log(chalk.yellow(` ⚠ Preview deployment (branch: ${latest.branch})`))
117
203
  }