@take-out/scripts 0.0.97 → 0.0.99
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/package.json +2 -2
- package/src/build-initial.ts +9 -12
- package/src/cmd.ts +2 -2
- package/src/dev-tunnel.ts +11 -10
- package/src/env-pull.ts +4 -3
- package/src/env-update.ts +16 -13
- package/src/helpers/env-load.ts +2 -2
- package/src/helpers/get-test-env.ts +2 -5
- package/src/helpers/multipass.ts +2 -2
- package/src/helpers/process-compose-env.ts +3 -3
- package/src/helpers/uncloud-deploy.ts +5 -6
- package/src/helpers/uncloud.ts +7 -7
- package/src/helpers/zero-get-version.ts +2 -2
- package/src/node-version-check.ts +4 -3
- package/src/run.ts +4 -4
- package/src/up.ts +20 -22
- package/src/update-changelog.ts +4 -3
- package/src/update-local-env.ts +42 -54
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@take-out/scripts",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.99",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./src/run.ts",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@clack/prompts": "^0.8.2",
|
|
32
|
-
"@take-out/helpers": "0.0.
|
|
32
|
+
"@take-out/helpers": "0.0.99",
|
|
33
33
|
"picocolors": "^1.1.1"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
package/src/build-initial.ts
CHANGED
|
@@ -4,13 +4,10 @@ import { cmd } from './cmd'
|
|
|
4
4
|
|
|
5
5
|
await cmd`bootstrap project workspace and build initial packages`.run(
|
|
6
6
|
async ({ $, fs, path }) => {
|
|
7
|
-
const
|
|
8
|
-
const { exists } = fs
|
|
9
|
-
|
|
10
|
-
const hasPackages = await exists(`./packages`)
|
|
7
|
+
const hasPackages = fs.existsSync(`./packages`)
|
|
11
8
|
|
|
12
9
|
// only run once
|
|
13
|
-
if (!(
|
|
10
|
+
if (!fs.existsSync(`./node_modules/.bin/tko`)) {
|
|
14
11
|
if (hasPackages) {
|
|
15
12
|
symlinkBins()
|
|
16
13
|
}
|
|
@@ -19,8 +16,8 @@ await cmd`bootstrap project workspace and build initial packages`.run(
|
|
|
19
16
|
// check if critical packages are built
|
|
20
17
|
if (hasPackages) {
|
|
21
18
|
const needsBuild =
|
|
22
|
-
!(
|
|
23
|
-
!(
|
|
19
|
+
!fs.existsSync(`./packages/helpers/dist`) ||
|
|
20
|
+
!fs.existsSync(`./packages/cli/dist/esm`)
|
|
24
21
|
|
|
25
22
|
if (needsBuild) {
|
|
26
23
|
// build helpers first as other packages depend on it
|
|
@@ -37,7 +34,7 @@ await cmd`bootstrap project workspace and build initial packages`.run(
|
|
|
37
34
|
function checkAndShowWelcome(cwd: string = process.cwd()): void {
|
|
38
35
|
try {
|
|
39
36
|
const packagePath = path.join(cwd, 'package.json')
|
|
40
|
-
const pkg = JSON.parse(readFileSync(packagePath, 'utf-8'))
|
|
37
|
+
const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf-8'))
|
|
41
38
|
|
|
42
39
|
if (pkg.takeout?.onboarded === false) {
|
|
43
40
|
console.info()
|
|
@@ -70,8 +67,8 @@ await cmd`bootstrap project workspace and build initial packages`.run(
|
|
|
70
67
|
|
|
71
68
|
const binDir = path.join(process.cwd(), 'node_modules', '.bin')
|
|
72
69
|
|
|
73
|
-
if (!existsSync(binDir)) {
|
|
74
|
-
mkdirSync(binDir, { recursive: true })
|
|
70
|
+
if (!fs.existsSync(binDir)) {
|
|
71
|
+
fs.mkdirSync(binDir, { recursive: true })
|
|
75
72
|
}
|
|
76
73
|
|
|
77
74
|
for (const pkg of packagesWithCLI) {
|
|
@@ -86,12 +83,12 @@ await cmd`bootstrap project workspace and build initial packages`.run(
|
|
|
86
83
|
}
|
|
87
84
|
|
|
88
85
|
function symlinkTo(source: string, target: string): void {
|
|
89
|
-
if (existsSync(target)) {
|
|
86
|
+
if (fs.existsSync(target)) {
|
|
90
87
|
console.info(`✓ Symlink already exists: ${target}`)
|
|
91
88
|
return
|
|
92
89
|
}
|
|
93
90
|
|
|
94
|
-
symlinkSync(source, target)
|
|
91
|
+
fs.symlinkSync(source, target)
|
|
95
92
|
console.info(`→ Created symlink: ${source} ⇢ ${target}`)
|
|
96
93
|
}
|
|
97
94
|
}
|
package/src/cmd.ts
CHANGED
|
@@ -5,7 +5,7 @@ type CmdContext = {
|
|
|
5
5
|
colors: typeof import('picocolors')
|
|
6
6
|
prompt: typeof import('@clack/prompts')
|
|
7
7
|
run: typeof import('./helpers/run').run
|
|
8
|
-
fs: typeof import('node:fs
|
|
8
|
+
fs: typeof import('node:fs')
|
|
9
9
|
path: typeof import('node:path')
|
|
10
10
|
os: typeof import('node:os')
|
|
11
11
|
}
|
|
@@ -56,7 +56,7 @@ function createCmd(description: string) {
|
|
|
56
56
|
import(`@clack/prompts`),
|
|
57
57
|
import(`./helpers/run`),
|
|
58
58
|
import(`./helpers/args`),
|
|
59
|
-
import(`node:fs
|
|
59
|
+
import(`node:fs`),
|
|
60
60
|
import(`node:path`),
|
|
61
61
|
import(`node:os`),
|
|
62
62
|
])
|
package/src/dev-tunnel.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
+
import fs from 'node:fs'
|
|
4
|
+
|
|
3
5
|
import { cmd } from './cmd'
|
|
4
6
|
|
|
5
7
|
await cmd`set up cloudflare dev tunnel for local development`
|
|
6
8
|
.args('--port number')
|
|
7
9
|
.run(async ({ args, run, os, path }) => {
|
|
8
|
-
const { existsSync, mkdirSync, readFileSync, writeFileSync } = await import('node:fs')
|
|
9
10
|
const { handleProcessExit } = await import('./helpers/handleProcessExit')
|
|
10
11
|
|
|
11
12
|
handleProcessExit()
|
|
@@ -30,7 +31,7 @@ await cmd`set up cloudflare dev tunnel for local development`
|
|
|
30
31
|
|
|
31
32
|
async function ensureAuthenticated(): Promise<boolean> {
|
|
32
33
|
const certPath = path.join(os.homedir(), '.cloudflared', 'cert.pem')
|
|
33
|
-
if (existsSync(certPath)) {
|
|
34
|
+
if (fs.existsSync(certPath)) {
|
|
34
35
|
return true
|
|
35
36
|
}
|
|
36
37
|
|
|
@@ -44,12 +45,12 @@ await cmd`set up cloudflare dev tunnel for local development`
|
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
async function getOrCreateTunnel(): Promise<string | null> {
|
|
47
|
-
if (!existsSync(TUNNEL_CONFIG_DIR)) {
|
|
48
|
-
mkdirSync(TUNNEL_CONFIG_DIR, { recursive: true })
|
|
48
|
+
if (!fs.existsSync(TUNNEL_CONFIG_DIR)) {
|
|
49
|
+
fs.mkdirSync(TUNNEL_CONFIG_DIR, { recursive: true })
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
if (existsSync(TUNNEL_ID_FILE)) {
|
|
52
|
-
const tunnelId = readFileSync(TUNNEL_ID_FILE, 'utf-8').trim()
|
|
52
|
+
if (fs.existsSync(TUNNEL_ID_FILE)) {
|
|
53
|
+
const tunnelId = fs.readFileSync(TUNNEL_ID_FILE, 'utf-8').trim()
|
|
53
54
|
return tunnelId
|
|
54
55
|
}
|
|
55
56
|
|
|
@@ -70,7 +71,7 @@ await cmd`set up cloudflare dev tunnel for local development`
|
|
|
70
71
|
const tunnelId = match1?.[1] || match2?.[1] || match3?.[1]
|
|
71
72
|
|
|
72
73
|
if (tunnelId) {
|
|
73
|
-
writeFileSync(TUNNEL_ID_FILE, tunnelId)
|
|
74
|
+
fs.writeFileSync(TUNNEL_ID_FILE, tunnelId)
|
|
74
75
|
return tunnelId
|
|
75
76
|
}
|
|
76
77
|
|
|
@@ -87,7 +88,7 @@ await cmd`set up cloudflare dev tunnel for local development`
|
|
|
87
88
|
const tunnels = JSON.parse(stdout)
|
|
88
89
|
if (tunnels.length > 0) {
|
|
89
90
|
const tunnelId = tunnels[0].id
|
|
90
|
-
writeFileSync(TUNNEL_ID_FILE, tunnelId)
|
|
91
|
+
fs.writeFileSync(TUNNEL_ID_FILE, tunnelId)
|
|
91
92
|
return tunnelId
|
|
92
93
|
}
|
|
93
94
|
} catch (e) {
|
|
@@ -125,7 +126,7 @@ await cmd`set up cloudflare dev tunnel for local development`
|
|
|
125
126
|
|
|
126
127
|
// save the expected url immediately so it's available right away
|
|
127
128
|
const expectedUrl = `https://${tunnelId}.cfargotunnel.com`
|
|
128
|
-
writeFileSync(path.join(TUNNEL_CONFIG_DIR, 'tunnel-url.txt'), expectedUrl)
|
|
129
|
+
fs.writeFileSync(path.join(TUNNEL_CONFIG_DIR, 'tunnel-url.txt'), expectedUrl)
|
|
129
130
|
console.info(`\n🌐 Tunnel URL: ${expectedUrl}`)
|
|
130
131
|
|
|
131
132
|
// get the public url in the background
|
|
@@ -142,7 +143,7 @@ await cmd`set up cloudflare dev tunnel for local development`
|
|
|
142
143
|
try {
|
|
143
144
|
const info = JSON.parse(stdout)
|
|
144
145
|
const hostname = info.hostname || `${tunnelId}.cfargotunnel.com`
|
|
145
|
-
writeFileSync(
|
|
146
|
+
fs.writeFileSync(
|
|
146
147
|
path.join(TUNNEL_CONFIG_DIR, 'tunnel-url.txt'),
|
|
147
148
|
`https://${hostname}`
|
|
148
149
|
)
|
package/src/env-pull.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
+
import fs from 'node:fs'
|
|
4
|
+
|
|
3
5
|
import { cmd } from './cmd'
|
|
4
6
|
|
|
5
7
|
await cmd`pull environment variables from SST production`.run(async ({ path }) => {
|
|
6
|
-
const { existsSync, writeFileSync } = await import('node:fs')
|
|
7
8
|
const { getEnvironment } = await import('./sst-get-environment')
|
|
8
9
|
|
|
9
10
|
const rootDir = process.cwd()
|
|
10
11
|
|
|
11
12
|
const envFilePath = path.join(rootDir, '.env.production')
|
|
12
|
-
if (existsSync(envFilePath)) {
|
|
13
|
+
if (fs.existsSync(envFilePath)) {
|
|
13
14
|
console.error(
|
|
14
15
|
'❌ Error: .env.production already exists. Please remove or rename it first.'
|
|
15
16
|
)
|
|
@@ -45,7 +46,7 @@ await cmd`pull environment variables from SST production`.run(async ({ path }) =
|
|
|
45
46
|
process.exit(1)
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
writeFileSync(envFilePath, envFileContent)
|
|
49
|
+
fs.writeFileSync(envFilePath, envFileContent)
|
|
49
50
|
|
|
50
51
|
console.info(
|
|
51
52
|
`✅ Success! ${foundCount} environment variables written to .env.production`
|
package/src/env-update.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
+
import fs from 'node:fs'
|
|
4
|
+
|
|
3
5
|
import { cmd } from './cmd'
|
|
4
6
|
|
|
5
7
|
await cmd`sync environment variables from package.json to CI and server configs`.run(
|
|
6
8
|
async () => {
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
const packageJson = JSON.parse(readFileSync('package.json', 'utf-8'))
|
|
9
|
+
const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf-8'))
|
|
10
10
|
const envVars = packageJson.env as Record<string, boolean | string>
|
|
11
11
|
|
|
12
12
|
if (!envVars || Array.isArray(envVars) || typeof envVars !== 'object') {
|
|
@@ -36,7 +36,7 @@ await cmd`sync environment variables from package.json to CI and server configs`
|
|
|
36
36
|
|
|
37
37
|
function updateDeployYml() {
|
|
38
38
|
const deployYmlPath = '.github/workflows/ci.yml'
|
|
39
|
-
let deployYml = readFileSync(deployYmlPath, 'utf-8')
|
|
39
|
+
let deployYml = fs.readFileSync(deployYmlPath, 'utf-8')
|
|
40
40
|
|
|
41
41
|
if (!deployYml.includes(yamlStartMarker) || !deployYml.includes(yamlEndMarker)) {
|
|
42
42
|
throw new Error(`Markers not found in ${deployYmlPath}`)
|
|
@@ -49,7 +49,7 @@ await cmd`sync environment variables from package.json to CI and server configs`
|
|
|
49
49
|
|
|
50
50
|
const newDeployYml = replaceYamlSection(deployYml, envSection, { indent })
|
|
51
51
|
|
|
52
|
-
writeFileSync(deployYmlPath, newDeployYml, 'utf-8')
|
|
52
|
+
fs.writeFileSync(deployYmlPath, newDeployYml, 'utf-8')
|
|
53
53
|
console.info('✅ Updated Github workflow')
|
|
54
54
|
}
|
|
55
55
|
|
|
@@ -60,7 +60,7 @@ await cmd`sync environment variables from package.json to CI and server configs`
|
|
|
60
60
|
|
|
61
61
|
for (const p of candidates) {
|
|
62
62
|
try {
|
|
63
|
-
envServer = readFileSync(p, 'utf-8')
|
|
63
|
+
envServer = fs.readFileSync(p, 'utf-8')
|
|
64
64
|
envServerPath = p
|
|
65
65
|
break
|
|
66
66
|
} catch {}
|
|
@@ -75,10 +75,13 @@ await cmd`sync environment variables from package.json to CI and server configs`
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
const envExports = Object.entries(envVars)
|
|
78
|
-
.map(
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
.map(([key, value]) => {
|
|
79
|
+
// $dep: values have no compile-time default — resolved into .env at runtime
|
|
80
|
+
if (typeof value === 'string' && value.startsWith('$dep:')) {
|
|
81
|
+
return `export const ${key} = ensureEnv('${key}')`
|
|
82
|
+
}
|
|
83
|
+
return `export const ${key} = ensureEnv('${key}'${typeof value === 'string' ? `, ${JSON.stringify(value)}` : ''})`
|
|
84
|
+
})
|
|
82
85
|
.join('\n')
|
|
83
86
|
|
|
84
87
|
const newEnvServer = envServer.replace(
|
|
@@ -86,7 +89,7 @@ await cmd`sync environment variables from package.json to CI and server configs`
|
|
|
86
89
|
`${jsStartMarker}\n${envExports}\n${jsEndMarker}`
|
|
87
90
|
)
|
|
88
91
|
|
|
89
|
-
writeFileSync(envServerPath, newEnvServer, 'utf-8')
|
|
92
|
+
fs.writeFileSync(envServerPath, newEnvServer, 'utf-8')
|
|
90
93
|
console.info('✅ Updated server env')
|
|
91
94
|
}
|
|
92
95
|
|
|
@@ -95,7 +98,7 @@ await cmd`sync environment variables from package.json to CI and server configs`
|
|
|
95
98
|
|
|
96
99
|
let dockerCompose = ''
|
|
97
100
|
try {
|
|
98
|
-
dockerCompose = readFileSync(dockerComposePath, 'utf-8')
|
|
101
|
+
dockerCompose = fs.readFileSync(dockerComposePath, 'utf-8')
|
|
99
102
|
} catch (_error) {
|
|
100
103
|
// file doesn't exist, skip
|
|
101
104
|
return
|
|
@@ -128,7 +131,7 @@ await cmd`sync environment variables from package.json to CI and server configs`
|
|
|
128
131
|
|
|
129
132
|
const newDockerCompose = replaceYamlSection(dockerCompose, envLines, { indent })
|
|
130
133
|
|
|
131
|
-
writeFileSync(dockerComposePath, newDockerCompose, 'utf-8')
|
|
134
|
+
fs.writeFileSync(dockerComposePath, newDockerCompose, 'utf-8')
|
|
132
135
|
console.info('✅ Updated docker-compose.yml')
|
|
133
136
|
}
|
|
134
137
|
|
package/src/helpers/env-load.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import fs from 'node:fs'
|
|
2
2
|
import { join } from 'node:path'
|
|
3
3
|
|
|
4
4
|
import { loadEnv as vxrnLoadEnv } from 'vxrn/loadEnv'
|
|
@@ -31,7 +31,7 @@ function resolveEnvServerPath(): string {
|
|
|
31
31
|
const candidates = ['src/constants/env-server.ts', 'src/server/env-server.ts']
|
|
32
32
|
for (const candidate of candidates) {
|
|
33
33
|
const full = join(process.cwd(), candidate)
|
|
34
|
-
if (existsSync(full)) {
|
|
34
|
+
if (fs.existsSync(full)) {
|
|
35
35
|
return full
|
|
36
36
|
}
|
|
37
37
|
}
|
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
import
|
|
1
|
+
import fs from 'node:fs'
|
|
2
2
|
import { join } from 'node:path'
|
|
3
3
|
|
|
4
4
|
import { loadEnv } from './env-load'
|
|
5
5
|
import { getDockerHost } from './get-docker-host'
|
|
6
|
-
import { getZeroVersion } from './zero-get-version'
|
|
7
6
|
|
|
8
7
|
export async function getTestEnv() {
|
|
9
|
-
const zeroVersion = getZeroVersion()
|
|
10
8
|
const dockerHost = getDockerHost()
|
|
11
9
|
const devEnv = await loadEnv('development')
|
|
12
10
|
const envPath =
|
|
13
11
|
['src/constants/env-server', 'src/server/env-server']
|
|
14
12
|
.map((p) => join(process.cwd(), p))
|
|
15
|
-
.find((p) => existsSync(p + '.ts')) ||
|
|
13
|
+
.find((p) => fs.existsSync(p + '.ts')) ||
|
|
16
14
|
join(process.cwd(), 'src/constants/env-server')
|
|
17
15
|
const serverEnvFallback = await import(envPath)
|
|
18
16
|
|
|
@@ -31,7 +29,6 @@ export async function getTestEnv() {
|
|
|
31
29
|
ZERO_LOG_LEVEL: 'warn',
|
|
32
30
|
}),
|
|
33
31
|
DO_NOT_TRACK: '1',
|
|
34
|
-
ZERO_VERSION: zeroVersion,
|
|
35
32
|
ZERO_MUTATE_URL: `http://${dockerHost}:${appPort}/api/zero/push`,
|
|
36
33
|
ZERO_QUERY_URL: `http://${dockerHost}:${appPort}/api/zero/pull`,
|
|
37
34
|
ZERO_UPSTREAM_DB: `${dockerDbBase}/postgres`,
|
package/src/helpers/multipass.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import fs from 'node:fs'
|
|
2
2
|
|
|
3
3
|
import { sleep } from '@take-out/helpers'
|
|
4
4
|
|
|
@@ -66,7 +66,7 @@ packages:
|
|
|
66
66
|
`
|
|
67
67
|
|
|
68
68
|
const cloudInitPath = `${process.cwd()}/.cloud-init.yml`
|
|
69
|
-
writeFileSync(cloudInitPath, cloudInit)
|
|
69
|
+
fs.writeFileSync(cloudInitPath, cloudInit)
|
|
70
70
|
|
|
71
71
|
try {
|
|
72
72
|
await run(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import fs from 'node:fs'
|
|
2
2
|
|
|
3
3
|
// make values safe for yaml map syntax (KEY: value)
|
|
4
4
|
// handles multi-line values, special chars that break yaml parsing
|
|
@@ -30,7 +30,7 @@ export function processComposeEnv(
|
|
|
30
30
|
outputFile: string,
|
|
31
31
|
envVars: Record<string, string | undefined>
|
|
32
32
|
): void {
|
|
33
|
-
let content = readFileSync(composeFile, 'utf-8')
|
|
33
|
+
let content = fs.readFileSync(composeFile, 'utf-8')
|
|
34
34
|
|
|
35
35
|
// replace all ${VAR:-default} patterns with actual env values
|
|
36
36
|
content = content.replace(
|
|
@@ -52,6 +52,6 @@ export function processComposeEnv(
|
|
|
52
52
|
return value ? yamlSafe(value) : _match
|
|
53
53
|
})
|
|
54
54
|
|
|
55
|
-
writeFileSync(outputFile, content)
|
|
55
|
+
fs.writeFileSync(outputFile, content)
|
|
56
56
|
console.info(`✅ processed compose file: ${outputFile}`)
|
|
57
57
|
}
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
* generic uncloud deployment helpers for ci/cd
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import { mkdir, writeFile } from 'node:fs/promises'
|
|
5
|
+
import fs from 'node:fs'
|
|
7
6
|
import { homedir } from 'node:os'
|
|
8
7
|
import { join } from 'node:path'
|
|
9
8
|
|
|
@@ -91,7 +90,7 @@ export async function setupSSHKey() {
|
|
|
91
90
|
const sshKeyValue = process.env.DEPLOY_SSH_KEY
|
|
92
91
|
|
|
93
92
|
// check if it's a path to an existing file (local usage) or key content (CI usage)
|
|
94
|
-
if (existsSync(sshKeyValue)) {
|
|
93
|
+
if (fs.existsSync(sshKeyValue)) {
|
|
95
94
|
console.info(` using ssh key from: ${sshKeyValue}`)
|
|
96
95
|
return
|
|
97
96
|
}
|
|
@@ -101,8 +100,8 @@ export async function setupSSHKey() {
|
|
|
101
100
|
const sshDir = join(homedir(), '.ssh')
|
|
102
101
|
const keyPath = join(sshDir, 'uncloud_deploy')
|
|
103
102
|
|
|
104
|
-
if (!existsSync(sshDir)) {
|
|
105
|
-
await mkdir(sshDir, { recursive: true })
|
|
103
|
+
if (!fs.existsSync(sshDir)) {
|
|
104
|
+
await fs.promises.mkdir(sshDir, { recursive: true })
|
|
106
105
|
}
|
|
107
106
|
|
|
108
107
|
// decode base64-encoded keys (github secrets often store keys as base64)
|
|
@@ -120,7 +119,7 @@ export async function setupSSHKey() {
|
|
|
120
119
|
keyContent += '\n'
|
|
121
120
|
}
|
|
122
121
|
|
|
123
|
-
await writeFile(keyPath, keyContent, { mode: 0o600 })
|
|
122
|
+
await fs.promises.writeFile(keyPath, keyContent, { mode: 0o600 })
|
|
124
123
|
|
|
125
124
|
// add host to known_hosts
|
|
126
125
|
if (process.env.DEPLOY_HOST) {
|
package/src/helpers/uncloud.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import fs from 'node:fs'
|
|
2
2
|
import { homedir } from 'node:os'
|
|
3
3
|
import { join } from 'node:path'
|
|
4
4
|
|
|
@@ -27,13 +27,13 @@ function ensureUncloudContext(host: string, sshKey: string, contextName: string)
|
|
|
27
27
|
const configDir = join(homedir(), '.config', 'uncloud')
|
|
28
28
|
const configPath = join(configDir, 'config.yaml')
|
|
29
29
|
|
|
30
|
-
if (!existsSync(configDir)) {
|
|
31
|
-
mkdirSync(configDir, { recursive: true })
|
|
30
|
+
if (!fs.existsSync(configDir)) {
|
|
31
|
+
fs.mkdirSync(configDir, { recursive: true })
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
// check if config already has context pointing to correct host
|
|
35
|
-
if (existsSync(configPath)) {
|
|
36
|
-
const existing = readFileSync(configPath, 'utf-8')
|
|
35
|
+
if (fs.existsSync(configPath)) {
|
|
36
|
+
const existing = fs.readFileSync(configPath, 'utf-8')
|
|
37
37
|
const hostname = host.split('@')[1]
|
|
38
38
|
if (hostname && existing.includes(`${contextName}:`) && existing.includes(hostname)) {
|
|
39
39
|
console.info(`✅ uncloud config already has ${contextName} context for ${host}`)
|
|
@@ -43,7 +43,7 @@ function ensureUncloudContext(host: string, sshKey: string, contextName: string)
|
|
|
43
43
|
|
|
44
44
|
// only create config if it doesn't exist - don't overwrite existing config
|
|
45
45
|
// which may have other contexts
|
|
46
|
-
if (!existsSync(configPath)) {
|
|
46
|
+
if (!fs.existsSync(configPath)) {
|
|
47
47
|
const config = `current_context: ${contextName}
|
|
48
48
|
contexts:
|
|
49
49
|
${contextName}:
|
|
@@ -51,7 +51,7 @@ contexts:
|
|
|
51
51
|
- ssh: ${host}
|
|
52
52
|
ssh_key_file: ${sshKey}
|
|
53
53
|
`
|
|
54
|
-
writeFileSync(configPath, config)
|
|
54
|
+
fs.writeFileSync(configPath, config)
|
|
55
55
|
console.info(`✅ created uncloud config at ${configPath}`)
|
|
56
56
|
} else {
|
|
57
57
|
console.info(`✅ using existing uncloud config (context: ${contextName})`)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import fs from 'node:fs'
|
|
2
2
|
import { join } from 'node:path'
|
|
3
3
|
|
|
4
4
|
export function getZeroVersion() {
|
|
5
5
|
const packageJsonPath = join(process.cwd(), 'package.json')
|
|
6
|
-
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'))
|
|
6
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'))
|
|
7
7
|
return packageJson.dependencies?.['@rocicorp/zero']?.replace(/^[\^~]/, '')
|
|
8
8
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
+
import fs from 'node:fs'
|
|
4
|
+
|
|
3
5
|
import { cmd } from './cmd'
|
|
4
6
|
|
|
5
7
|
function getCurrentNodeVersion() {
|
|
@@ -7,12 +9,11 @@ function getCurrentNodeVersion() {
|
|
|
7
9
|
}
|
|
8
10
|
|
|
9
11
|
async function getRequiredNodeVersion() {
|
|
10
|
-
const fs = await import('node:fs/promises')
|
|
11
12
|
const path = await import('node:path')
|
|
12
13
|
|
|
13
14
|
// try .node-version file first
|
|
14
15
|
try {
|
|
15
|
-
const nodeVersionContent = await fs.readFile(
|
|
16
|
+
const nodeVersionContent = await fs.promises.readFile(
|
|
16
17
|
path.join(process.cwd(), '.node-version'),
|
|
17
18
|
'utf-8'
|
|
18
19
|
)
|
|
@@ -22,7 +23,7 @@ async function getRequiredNodeVersion() {
|
|
|
22
23
|
// fallback to package.json engines.node
|
|
23
24
|
try {
|
|
24
25
|
const packageJson = JSON.parse(
|
|
25
|
-
await fs.readFile(path.join(process.cwd(), 'package.json'), 'utf-8')
|
|
26
|
+
await fs.promises.readFile(path.join(process.cwd(), 'package.json'), 'utf-8')
|
|
26
27
|
)
|
|
27
28
|
return packageJson?.engines?.node ? `v${packageJson.engines.node}` : null
|
|
28
29
|
} catch {
|
package/src/run.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { spawn } from 'node:child_process'
|
|
8
|
-
import
|
|
8
|
+
import fs from 'node:fs'
|
|
9
9
|
import { join, relative, resolve } from 'node:path'
|
|
10
10
|
|
|
11
11
|
import { handleProcessExit } from '@take-out/scripts/helpers/handleProcessExit'
|
|
@@ -101,7 +101,7 @@ if (runCommands.length === 0) {
|
|
|
101
101
|
async function readPackageJson(directoryPath: string) {
|
|
102
102
|
try {
|
|
103
103
|
const packageJsonPath = join(directoryPath, 'package.json')
|
|
104
|
-
const content = await fs.readFile(packageJsonPath, 'utf8')
|
|
104
|
+
const content = await fs.promises.readFile(packageJsonPath, 'utf8')
|
|
105
105
|
return JSON.parse(content)
|
|
106
106
|
} catch (_) {
|
|
107
107
|
return null
|
|
@@ -124,7 +124,7 @@ async function getWorkspacePatterns(): Promise<string[]> {
|
|
|
124
124
|
|
|
125
125
|
async function hasPackageJson(path: string): Promise<boolean> {
|
|
126
126
|
try {
|
|
127
|
-
await fs.access(join(path, 'package.json'))
|
|
127
|
+
await fs.promises.access(join(path, 'package.json'))
|
|
128
128
|
return true
|
|
129
129
|
} catch {
|
|
130
130
|
return false
|
|
@@ -135,7 +135,7 @@ async function findPackageJsonDirs(basePath: string, maxDepth = 3): Promise<stri
|
|
|
135
135
|
if (maxDepth <= 0) return []
|
|
136
136
|
|
|
137
137
|
try {
|
|
138
|
-
const entries = await fs.readdir(basePath, { withFileTypes: true })
|
|
138
|
+
const entries = await fs.promises.readdir(basePath, { withFileTypes: true })
|
|
139
139
|
const results: string[] = []
|
|
140
140
|
|
|
141
141
|
if (await hasPackageJson(basePath)) {
|
package/src/up.ts
CHANGED
|
@@ -12,9 +12,6 @@ interface PackageJson {
|
|
|
12
12
|
await cmd`upgrade packages by name or pattern`
|
|
13
13
|
.args('--tag string --canary boolean --rc boolean')
|
|
14
14
|
.run(async ({ args, $, path, fs }) => {
|
|
15
|
-
const { existsSync, readdirSync, readFileSync, writeFileSync, rmSync } =
|
|
16
|
-
await import('node:fs')
|
|
17
|
-
|
|
18
15
|
let globalTag: string | undefined = args.tag
|
|
19
16
|
if (args.canary) globalTag = 'canary'
|
|
20
17
|
if (args.rc) globalTag = 'rc'
|
|
@@ -22,7 +19,7 @@ await cmd`upgrade packages by name or pattern`
|
|
|
22
19
|
const packagePatterns: string[] = []
|
|
23
20
|
const rootDir = process.cwd()
|
|
24
21
|
const rootPackageJson = JSON.parse(
|
|
25
|
-
readFileSync(path.join(rootDir, 'package.json'), 'utf-8')
|
|
22
|
+
fs.readFileSync(path.join(rootDir, 'package.json'), 'utf-8')
|
|
26
23
|
)
|
|
27
24
|
const upgradeSets: Record<string, string[]> = rootPackageJson.upgradeSets || {}
|
|
28
25
|
|
|
@@ -54,14 +51,14 @@ await cmd`upgrade packages by name or pattern`
|
|
|
54
51
|
function findPackageJsonFiles(dir: string): string[] {
|
|
55
52
|
const results: string[] = []
|
|
56
53
|
|
|
57
|
-
if (existsSync(path.join(dir, 'package.json'))) {
|
|
54
|
+
if (fs.existsSync(path.join(dir, 'package.json'))) {
|
|
58
55
|
results.push(path.join(dir, 'package.json'))
|
|
59
56
|
}
|
|
60
57
|
|
|
61
58
|
// check if it's a monorepo with workspaces
|
|
62
59
|
try {
|
|
63
60
|
const packageJson = JSON.parse(
|
|
64
|
-
readFileSync(path.join(dir, 'package.json'), 'utf-8')
|
|
61
|
+
fs.readFileSync(path.join(dir, 'package.json'), 'utf-8')
|
|
65
62
|
)
|
|
66
63
|
if (packageJson.workspaces) {
|
|
67
64
|
let workspacePaths: string[] = []
|
|
@@ -81,15 +78,15 @@ await cmd`upgrade packages by name or pattern`
|
|
|
81
78
|
const baseDir = normalizedWorkspace.split('**')[0]!.replace(/\/$/, '')
|
|
82
79
|
const basePath = path.join(dir, baseDir)
|
|
83
80
|
|
|
84
|
-
if (existsSync(basePath)) {
|
|
81
|
+
if (fs.existsSync(basePath)) {
|
|
85
82
|
const findPackages = (searchDir: string) => {
|
|
86
83
|
try {
|
|
87
|
-
const entries = readdirSync(searchDir, { withFileTypes: true })
|
|
84
|
+
const entries = fs.readdirSync(searchDir, { withFileTypes: true })
|
|
88
85
|
for (const entry of entries) {
|
|
89
86
|
if (entry.isDirectory() && entry.name !== 'node_modules') {
|
|
90
87
|
const subPath = path.join(searchDir, entry.name)
|
|
91
88
|
const pkgPath = path.join(subPath, 'package.json')
|
|
92
|
-
if (existsSync(pkgPath)) {
|
|
89
|
+
if (fs.existsSync(pkgPath)) {
|
|
93
90
|
results.push(pkgPath)
|
|
94
91
|
}
|
|
95
92
|
// recurse into subdirectories
|
|
@@ -105,15 +102,16 @@ await cmd`upgrade packages by name or pattern`
|
|
|
105
102
|
} else if (normalizedWorkspace.includes('*')) {
|
|
106
103
|
// simple glob pattern like "packages/*"
|
|
107
104
|
const workspaceDir = normalizedWorkspace.replace(/\/\*$/, '')
|
|
108
|
-
if (existsSync(path.join(dir, workspaceDir))) {
|
|
109
|
-
const subdirs =
|
|
110
|
-
|
|
111
|
-
|
|
105
|
+
if (fs.existsSync(path.join(dir, workspaceDir))) {
|
|
106
|
+
const subdirs = fs
|
|
107
|
+
.readdirSync(path.join(dir, workspaceDir), {
|
|
108
|
+
withFileTypes: true,
|
|
109
|
+
})
|
|
112
110
|
.filter((dirent) => dirent.isDirectory())
|
|
113
111
|
.map((dirent) => path.join(dir, workspaceDir, dirent.name))
|
|
114
112
|
|
|
115
113
|
for (const subdir of subdirs) {
|
|
116
|
-
if (existsSync(path.join(subdir, 'package.json'))) {
|
|
114
|
+
if (fs.existsSync(path.join(subdir, 'package.json'))) {
|
|
117
115
|
results.push(path.join(subdir, 'package.json'))
|
|
118
116
|
}
|
|
119
117
|
}
|
|
@@ -121,7 +119,7 @@ await cmd`upgrade packages by name or pattern`
|
|
|
121
119
|
} else {
|
|
122
120
|
// exact path like "code/tamagui.dev" or "./code/sandbox"
|
|
123
121
|
const pkgPath = path.join(dir, normalizedWorkspace, 'package.json')
|
|
124
|
-
if (existsSync(pkgPath)) {
|
|
122
|
+
if (fs.existsSync(pkgPath)) {
|
|
125
123
|
results.push(pkgPath)
|
|
126
124
|
}
|
|
127
125
|
}
|
|
@@ -136,7 +134,7 @@ await cmd`upgrade packages by name or pattern`
|
|
|
136
134
|
|
|
137
135
|
function extractDependencies(packageJsonPath: string): string[] {
|
|
138
136
|
try {
|
|
139
|
-
const content = readFileSync(packageJsonPath, 'utf-8')
|
|
137
|
+
const content = fs.readFileSync(packageJsonPath, 'utf-8')
|
|
140
138
|
const packageJson = JSON.parse(content) as PackageJson
|
|
141
139
|
|
|
142
140
|
const deps: string[] = []
|
|
@@ -176,7 +174,7 @@ await cmd`upgrade packages by name or pattern`
|
|
|
176
174
|
packagesToUpdate: string[],
|
|
177
175
|
versionMap: Map<string, string>
|
|
178
176
|
): number {
|
|
179
|
-
const content = readFileSync(packageJsonPath, 'utf-8')
|
|
177
|
+
const content = fs.readFileSync(packageJsonPath, 'utf-8')
|
|
180
178
|
const packageJson = JSON.parse(content) as PackageJson
|
|
181
179
|
let updatedCount = 0
|
|
182
180
|
|
|
@@ -214,7 +212,7 @@ await cmd`upgrade packages by name or pattern`
|
|
|
214
212
|
updateDeps(packageJson.optionalDependencies)
|
|
215
213
|
|
|
216
214
|
if (updatedCount > 0) {
|
|
217
|
-
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n')
|
|
215
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n')
|
|
218
216
|
}
|
|
219
217
|
|
|
220
218
|
return updatedCount
|
|
@@ -226,7 +224,7 @@ await cmd`upgrade packages by name or pattern`
|
|
|
226
224
|
packageJsonFiles: string[]
|
|
227
225
|
) {
|
|
228
226
|
try {
|
|
229
|
-
rmSync(`node_modules/vite`, {
|
|
227
|
+
fs.rmSync(`node_modules/vite`, {
|
|
230
228
|
recursive: true,
|
|
231
229
|
force: true,
|
|
232
230
|
})
|
|
@@ -338,7 +336,7 @@ await cmd`upgrade packages by name or pattern`
|
|
|
338
336
|
if (packageJsonPath === path.join(rootDir, 'package.json')) continue
|
|
339
337
|
|
|
340
338
|
try {
|
|
341
|
-
const content = readFileSync(packageJsonPath, 'utf-8')
|
|
339
|
+
const content = fs.readFileSync(packageJsonPath, 'utf-8')
|
|
342
340
|
const packageJson = JSON.parse(content)
|
|
343
341
|
if (packageJson.name) {
|
|
344
342
|
workspacePackageNames.add(packageJson.name)
|
|
@@ -405,7 +403,7 @@ await cmd`upgrade packages by name or pattern`
|
|
|
405
403
|
})
|
|
406
404
|
|
|
407
405
|
// insert placeholder so updatePackageJsonVersions can set the real version
|
|
408
|
-
const rootPkg = JSON.parse(readFileSync(rootPkgPath, 'utf-8'))
|
|
406
|
+
const rootPkg = JSON.parse(fs.readFileSync(rootPkgPath, 'utf-8'))
|
|
409
407
|
if (!rootPkg.dependencies) {
|
|
410
408
|
rootPkg.dependencies = {}
|
|
411
409
|
}
|
|
@@ -414,7 +412,7 @@ await cmd`upgrade packages by name or pattern`
|
|
|
414
412
|
rootPkg.dependencies[pkg] = '*'
|
|
415
413
|
}
|
|
416
414
|
}
|
|
417
|
-
writeFileSync(rootPkgPath, JSON.stringify(rootPkg, null, 2) + '\n')
|
|
415
|
+
fs.writeFileSync(rootPkgPath, JSON.stringify(rootPkg, null, 2) + '\n')
|
|
418
416
|
} else {
|
|
419
417
|
console.info(
|
|
420
418
|
`Found ${allMatchingDeps.size} dependencies matching patterns: ${packagePatterns.join(', ')}`
|
package/src/update-changelog.ts
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
+
import fs from 'node:fs'
|
|
4
|
+
|
|
3
5
|
import { cmd } from './cmd'
|
|
4
6
|
|
|
5
7
|
await cmd`update changelog with recent git commits`.run(async ({ path }) => {
|
|
6
8
|
const { execSync } = await import('node:child_process')
|
|
7
|
-
const { existsSync, readFileSync } = await import('node:fs')
|
|
8
9
|
|
|
9
10
|
const CHANGELOG_PATH = path.join(process.cwd(), 'src/features/site/docs/changelog.mdx')
|
|
10
11
|
|
|
11
12
|
function getLastSha(): string | null {
|
|
12
|
-
if (!existsSync(CHANGELOG_PATH)) return null
|
|
13
|
+
if (!fs.existsSync(CHANGELOG_PATH)) return null
|
|
13
14
|
|
|
14
15
|
try {
|
|
15
|
-
const content = readFileSync(CHANGELOG_PATH, 'utf-8')
|
|
16
|
+
const content = fs.readFileSync(CHANGELOG_PATH, 'utf-8')
|
|
16
17
|
const match = content.match(/\{\/\* last updated: ([a-f0-9]+) \*\/\}/)
|
|
17
18
|
return match?.[1] || null
|
|
18
19
|
} catch {
|
package/src/update-local-env.ts
CHANGED
|
@@ -1,18 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
+
import fs from 'node:fs'
|
|
4
|
+
|
|
3
5
|
import { cmd } from './cmd'
|
|
4
6
|
|
|
5
7
|
await cmd`sync auto-generated env vars to local .env file`.run(async ({ path }) => {
|
|
6
|
-
const {
|
|
7
|
-
existsSync,
|
|
8
|
-
readFileSync,
|
|
9
|
-
writeFileSync,
|
|
10
|
-
copyFileSync,
|
|
11
|
-
renameSync,
|
|
12
|
-
unlinkSync,
|
|
13
|
-
} = await import('node:fs')
|
|
14
|
-
const { getZeroVersion } = await import('./helpers/zero-get-version')
|
|
15
|
-
|
|
16
8
|
// skip in CI environments
|
|
17
9
|
if (process.env.CI === 'true') {
|
|
18
10
|
console.info('Skipping bootstrap in CI environment')
|
|
@@ -20,7 +12,6 @@ await cmd`sync auto-generated env vars to local .env file`.run(async ({ path })
|
|
|
20
12
|
}
|
|
21
13
|
|
|
22
14
|
const ENV_PATH = path.join(process.cwd(), '.env')
|
|
23
|
-
const ENV_TEMPLATE_PATH = path.join(process.cwd(), '.env.template')
|
|
24
15
|
const ENV_BACKUP_PATH = path.join(process.cwd(), '.env.backup')
|
|
25
16
|
const ENV_TEMP_PATH = path.join(process.cwd(), '.env.tmp')
|
|
26
17
|
|
|
@@ -28,56 +19,53 @@ await cmd`sync auto-generated env vars to local .env file`.run(async ({ path })
|
|
|
28
19
|
const BEGIN_MARKER = '# ---- BEGIN AUTO-GENERATED (DO NOT EDIT) ----'
|
|
29
20
|
const END_MARKER = '# ---- END AUTO-GENERATED ----'
|
|
30
21
|
|
|
31
|
-
function createEnvFromTemplate(): boolean {
|
|
32
|
-
if (!existsSync(ENV_TEMPLATE_PATH)) {
|
|
33
|
-
console.info('No .env.template found, skipping .env creation')
|
|
34
|
-
return false
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
try {
|
|
38
|
-
copyFileSync(ENV_TEMPLATE_PATH, ENV_PATH)
|
|
39
|
-
console.info('Created .env from .env.template')
|
|
40
|
-
return true
|
|
41
|
-
} catch (error) {
|
|
42
|
-
console.error('Failed to create .env from .env.template:', error)
|
|
43
|
-
return false
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
22
|
function getAutoGeneratedContent(): string {
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
23
|
+
const packageJsonPath = path.join(process.cwd(), 'package.json')
|
|
24
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'))
|
|
25
|
+
const envVars = packageJson.env as Record<string, boolean | string>
|
|
26
|
+
|
|
27
|
+
if (!envVars || typeof envVars !== 'object') {
|
|
28
|
+
console.warn('No env section found in package.json')
|
|
51
29
|
return ''
|
|
52
30
|
}
|
|
53
31
|
|
|
54
|
-
const lines = [
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
32
|
+
const lines: string[] = [BEGIN_MARKER, `# Generated at: ${new Date().toISOString()}`]
|
|
33
|
+
|
|
34
|
+
for (const [key, value] of Object.entries(envVars)) {
|
|
35
|
+
if (typeof value === 'string' && value.startsWith('$dep:')) {
|
|
36
|
+
// resolve version from dependency
|
|
37
|
+
const depName = value.slice('$dep:'.length)
|
|
38
|
+
const version = packageJson.dependencies?.[depName]?.replace(/^[\^~]/, '')
|
|
39
|
+
if (version) {
|
|
40
|
+
lines.push(`${key}=${version}`)
|
|
41
|
+
} else {
|
|
42
|
+
console.warn(`Could not resolve dependency version for ${depName}`)
|
|
43
|
+
}
|
|
44
|
+
} else if (typeof value === 'string' && value !== '') {
|
|
45
|
+
// non-empty string default
|
|
46
|
+
lines.push(`${key}=${value}`)
|
|
47
|
+
}
|
|
48
|
+
// skip true (required, no default) and "" (no meaningful default)
|
|
49
|
+
}
|
|
60
50
|
|
|
51
|
+
lines.push(END_MARKER)
|
|
61
52
|
return lines.join('\n')
|
|
62
53
|
}
|
|
63
54
|
|
|
64
55
|
function updateEnvFile(): void {
|
|
65
56
|
// ensure .env exists
|
|
66
|
-
if (!existsSync(ENV_PATH)) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
writeFileSync(ENV_PATH, '')
|
|
70
|
-
console.info('Created empty .env file')
|
|
71
|
-
}
|
|
57
|
+
if (!fs.existsSync(ENV_PATH)) {
|
|
58
|
+
fs.writeFileSync(ENV_PATH, '')
|
|
59
|
+
console.info('Created empty .env file')
|
|
72
60
|
}
|
|
73
61
|
|
|
74
62
|
try {
|
|
75
63
|
// create backup
|
|
76
|
-
if (existsSync(ENV_PATH)) {
|
|
77
|
-
copyFileSync(ENV_PATH, ENV_BACKUP_PATH)
|
|
64
|
+
if (fs.existsSync(ENV_PATH)) {
|
|
65
|
+
fs.copyFileSync(ENV_PATH, ENV_BACKUP_PATH)
|
|
78
66
|
}
|
|
79
67
|
|
|
80
|
-
const currentContent = readFileSync(ENV_PATH, 'utf-8')
|
|
68
|
+
const currentContent = fs.readFileSync(ENV_PATH, 'utf-8')
|
|
81
69
|
|
|
82
70
|
const beginIndex = currentContent.indexOf(BEGIN_MARKER)
|
|
83
71
|
const endIndex = currentContent.indexOf(END_MARKER)
|
|
@@ -107,20 +95,20 @@ await cmd`sync auto-generated env vars to local .env file`.run(async ({ path })
|
|
|
107
95
|
}
|
|
108
96
|
|
|
109
97
|
// write to temp file first (atomic operation)
|
|
110
|
-
writeFileSync(ENV_TEMP_PATH, newContent)
|
|
98
|
+
fs.writeFileSync(ENV_TEMP_PATH, newContent)
|
|
111
99
|
|
|
112
100
|
// validate temp file
|
|
113
|
-
const tempContent = readFileSync(ENV_TEMP_PATH, 'utf-8')
|
|
101
|
+
const tempContent = fs.readFileSync(ENV_TEMP_PATH, 'utf-8')
|
|
114
102
|
if (!tempContent.includes(BEGIN_MARKER) || !tempContent.includes(END_MARKER)) {
|
|
115
103
|
throw new Error('Generated content validation failed')
|
|
116
104
|
}
|
|
117
105
|
|
|
118
106
|
// atomic replace
|
|
119
|
-
renameSync(ENV_TEMP_PATH, ENV_PATH)
|
|
107
|
+
fs.renameSync(ENV_TEMP_PATH, ENV_PATH)
|
|
120
108
|
|
|
121
|
-
if (existsSync(ENV_BACKUP_PATH)) {
|
|
109
|
+
if (fs.existsSync(ENV_BACKUP_PATH)) {
|
|
122
110
|
try {
|
|
123
|
-
unlinkSync(ENV_BACKUP_PATH)
|
|
111
|
+
fs.unlinkSync(ENV_BACKUP_PATH)
|
|
124
112
|
} catch {
|
|
125
113
|
// ignore cleanup errors
|
|
126
114
|
}
|
|
@@ -131,9 +119,9 @@ await cmd`sync auto-generated env vars to local .env file`.run(async ({ path })
|
|
|
131
119
|
console.error('Failed to update .env file:', error)
|
|
132
120
|
|
|
133
121
|
// attempt to restore backup
|
|
134
|
-
if (existsSync(ENV_BACKUP_PATH)) {
|
|
122
|
+
if (fs.existsSync(ENV_BACKUP_PATH)) {
|
|
135
123
|
try {
|
|
136
|
-
copyFileSync(ENV_BACKUP_PATH, ENV_PATH)
|
|
124
|
+
fs.copyFileSync(ENV_BACKUP_PATH, ENV_PATH)
|
|
137
125
|
console.info('Restored .env from backup')
|
|
138
126
|
} catch (restoreError) {
|
|
139
127
|
console.error('Failed to restore backup:', restoreError)
|
|
@@ -141,9 +129,9 @@ await cmd`sync auto-generated env vars to local .env file`.run(async ({ path })
|
|
|
141
129
|
}
|
|
142
130
|
|
|
143
131
|
// clean up temp file
|
|
144
|
-
if (existsSync(ENV_TEMP_PATH)) {
|
|
132
|
+
if (fs.existsSync(ENV_TEMP_PATH)) {
|
|
145
133
|
try {
|
|
146
|
-
unlinkSync(ENV_TEMP_PATH)
|
|
134
|
+
fs.unlinkSync(ENV_TEMP_PATH)
|
|
147
135
|
} catch {
|
|
148
136
|
// ignore cleanup errors
|
|
149
137
|
}
|