@take-out/scripts 0.0.28
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/LICENSE +21 -0
- package/package.json +27 -0
- package/src/bootstrap.ts +182 -0
- package/src/check-circular-deps.ts +113 -0
- package/src/clean.ts +15 -0
- package/src/dev-tunnel-if-exist.ts +166 -0
- package/src/dev-tunnel.ts +178 -0
- package/src/ensure-tunnel.ts +13 -0
- package/src/env-pull.ts +54 -0
- package/src/env-update.ts +126 -0
- package/src/exec-with-env.ts +57 -0
- package/src/helpers/check-port.ts +22 -0
- package/src/helpers/ensure-s3-bucket.ts +88 -0
- package/src/helpers/env-load.ts +26 -0
- package/src/helpers/get-docker-host.ts +37 -0
- package/src/helpers/get-test-env.ts +25 -0
- package/src/helpers/handleProcessExit.ts +254 -0
- package/src/helpers/run.ts +310 -0
- package/src/helpers/wait-for-port.ts +33 -0
- package/src/helpers/zero-get-version.ts +8 -0
- package/src/node-version-check.ts +49 -0
- package/src/release.ts +352 -0
- package/src/run.ts +358 -0
- package/src/sst-get-environment.ts +31 -0
- package/src/typescript.ts +16 -0
- package/src/update-deps.ts +336 -0
- package/src/wait-for-dev.ts +40 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
export function getEnvironment(resourceName: string) {
|
|
4
|
+
if (!resourceName) {
|
|
5
|
+
console.error(`No resouce name given:
|
|
6
|
+
|
|
7
|
+
bun scripts/get-environment.ts [resourceName]
|
|
8
|
+
`)
|
|
9
|
+
process.exit(1)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
console.info(`Getting environment for ${resourceName}...`)
|
|
13
|
+
const state = JSON.parse(
|
|
14
|
+
Bun.spawnSync(`bun sst state export --stage production`.split(' ')).stdout.toString()
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
const resource = state.latest.resources.find(
|
|
18
|
+
(x: any) => x.outputs?._dev?.title === resourceName
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
if (!resource) {
|
|
22
|
+
console.error(`Can't find resource ${resourceName}`)
|
|
23
|
+
process.exit(1)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return resource.outputs._dev.environment as Record<string, string>
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (import.meta.main) {
|
|
30
|
+
console.info(getEnvironment(process.argv[2] || ''))
|
|
31
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @description Run TypeScript compiler for type checking
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { run } from '@take-out/scripts/helpers/run'
|
|
8
|
+
|
|
9
|
+
const useTsgo = process.env.TSGO === '1'
|
|
10
|
+
const args = process.argv.slice(2)
|
|
11
|
+
|
|
12
|
+
if (useTsgo) {
|
|
13
|
+
await run(`bun tsgo --project ./tsconfig.json --noEmit --preserveWatchOutput ${args}`)
|
|
14
|
+
} else {
|
|
15
|
+
await run(`tsc --project ./tsconfig.json --noEmit --preserveWatchOutput ${args}`)
|
|
16
|
+
}
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @description Update dependencies across workspace packages
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { $ } from 'bun'
|
|
8
|
+
import { existsSync, readdirSync, readFileSync, rmSync } from 'node:fs'
|
|
9
|
+
import { join } from 'node:path'
|
|
10
|
+
|
|
11
|
+
let globalTag: string | undefined
|
|
12
|
+
const packagePatterns: string[] = []
|
|
13
|
+
|
|
14
|
+
const args = process.argv.slice(2)
|
|
15
|
+
|
|
16
|
+
for (const arg of args) {
|
|
17
|
+
if (arg.startsWith('--tag=')) {
|
|
18
|
+
const tagValue = arg.split('=')[1]
|
|
19
|
+
if (tagValue) {
|
|
20
|
+
globalTag = tagValue
|
|
21
|
+
} else {
|
|
22
|
+
console.error('Error: --tag option requires a value. Example: --tag=canary')
|
|
23
|
+
process.exit(1)
|
|
24
|
+
}
|
|
25
|
+
} else if (arg === '--tag') {
|
|
26
|
+
console.error('Error: --tag option requires a value and must use = syntax.')
|
|
27
|
+
console.error('Correct usage: --tag=canary')
|
|
28
|
+
console.error('Example: bun update-deps.ts --tag=canary react react-dom')
|
|
29
|
+
process.exit(1)
|
|
30
|
+
} else if (arg === '--canary') {
|
|
31
|
+
globalTag = 'canary'
|
|
32
|
+
} else {
|
|
33
|
+
packagePatterns.push(arg)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (packagePatterns.length === 0) {
|
|
38
|
+
console.error('Please provide at least one package pattern to update.')
|
|
39
|
+
console.error('Example: bun update-deps.ts @vxrn/* vxrn')
|
|
40
|
+
console.error('Or with a tag: bun update-deps.ts --tag=canary @vxrn/* vxrn')
|
|
41
|
+
process.exit(1)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface PackageJson {
|
|
45
|
+
dependencies?: Record<string, string>
|
|
46
|
+
devDependencies?: Record<string, string>
|
|
47
|
+
peerDependencies?: Record<string, string>
|
|
48
|
+
optionalDependencies?: Record<string, string>
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function findPackageJsonFiles(dir: string): string[] {
|
|
52
|
+
const results: string[] = []
|
|
53
|
+
|
|
54
|
+
if (existsSync(join(dir, 'package.json'))) {
|
|
55
|
+
results.push(join(dir, 'package.json'))
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Check if it's a monorepo with workspaces
|
|
59
|
+
try {
|
|
60
|
+
const packageJson = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf-8'))
|
|
61
|
+
if (packageJson.workspaces) {
|
|
62
|
+
let workspacePaths: string[] = []
|
|
63
|
+
|
|
64
|
+
if (Array.isArray(packageJson.workspaces)) {
|
|
65
|
+
workspacePaths = packageJson.workspaces
|
|
66
|
+
} else if (packageJson.workspaces.packages) {
|
|
67
|
+
workspacePaths = packageJson.workspaces.packages
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
for (const workspace of workspacePaths) {
|
|
71
|
+
const workspaceDir = workspace.replace(/\/\*$/, '')
|
|
72
|
+
if (existsSync(join(dir, workspaceDir))) {
|
|
73
|
+
const subdirs = readdirSync(join(dir, workspaceDir), { withFileTypes: true })
|
|
74
|
+
.filter((dirent) => dirent.isDirectory())
|
|
75
|
+
.map((dirent) => join(dir, workspaceDir, dirent.name))
|
|
76
|
+
|
|
77
|
+
for (const subdir of subdirs) {
|
|
78
|
+
if (existsSync(join(subdir, 'package.json'))) {
|
|
79
|
+
results.push(join(subdir, 'package.json'))
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
} catch (_error) {
|
|
86
|
+
// Ignore errors parsing package.json
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return results
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function extractDependencies(packageJsonPath: string): string[] {
|
|
93
|
+
try {
|
|
94
|
+
const content = readFileSync(packageJsonPath, 'utf-8')
|
|
95
|
+
const packageJson = JSON.parse(content) as PackageJson
|
|
96
|
+
|
|
97
|
+
const deps: string[] = []
|
|
98
|
+
|
|
99
|
+
const addNonWorkspaceDeps = (depsObject: Record<string, string> | undefined) => {
|
|
100
|
+
if (!depsObject) return
|
|
101
|
+
for (const [name, version] of Object.entries(depsObject)) {
|
|
102
|
+
// skip workspace dependencies
|
|
103
|
+
if (!version.startsWith('workspace:')) {
|
|
104
|
+
deps.push(name)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
addNonWorkspaceDeps(packageJson.dependencies)
|
|
110
|
+
addNonWorkspaceDeps(packageJson.devDependencies)
|
|
111
|
+
addNonWorkspaceDeps(packageJson.peerDependencies)
|
|
112
|
+
addNonWorkspaceDeps(packageJson.optionalDependencies)
|
|
113
|
+
|
|
114
|
+
return deps
|
|
115
|
+
} catch (error) {
|
|
116
|
+
console.error(`Error parsing ${packageJsonPath}:`, error)
|
|
117
|
+
return []
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function doesPackageMatchPattern(packageName: string, pattern: string): boolean {
|
|
122
|
+
if (pattern.includes('*')) {
|
|
123
|
+
const regex = new RegExp(`^${pattern.replace(/\*/g, '.*')}$`)
|
|
124
|
+
return regex.test(packageName)
|
|
125
|
+
}
|
|
126
|
+
return packageName === pattern
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function fetchPackageVersionFromTag(
|
|
130
|
+
packageName: string,
|
|
131
|
+
tag: string
|
|
132
|
+
): Promise<string | null> {
|
|
133
|
+
try {
|
|
134
|
+
console.info(`âł Lookup ${packageName}@${tag}...`)
|
|
135
|
+
// Use --json to ensure parseable output, even if it's just a string.
|
|
136
|
+
const result = await $`npm view ${packageName}@${tag} version --json`.text()
|
|
137
|
+
const versionData = JSON.parse(result.trim())
|
|
138
|
+
|
|
139
|
+
let version: string | undefined
|
|
140
|
+
if (Array.isArray(versionData)) {
|
|
141
|
+
if (versionData.length === 0) {
|
|
142
|
+
console.warn(`â No specific versions found for ${packageName}@${tag}.`)
|
|
143
|
+
return null
|
|
144
|
+
}
|
|
145
|
+
// If multiple versions, prefer the last one, as it's often the latest/highest precedent for a tag.
|
|
146
|
+
version = versionData[versionData.length - 1]
|
|
147
|
+
if (versionData.length > 1) {
|
|
148
|
+
console.info(
|
|
149
|
+
`âšď¸ Multiple versions found for ${packageName}@${tag}: [${versionData.join(', ')}]. Using: ${version}`
|
|
150
|
+
)
|
|
151
|
+
}
|
|
152
|
+
} else if (typeof versionData === 'string') {
|
|
153
|
+
version = versionData
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (typeof version === 'string' && version.trim() !== '') {
|
|
157
|
+
console.info(`â
Found ${packageName}@${tag}: ${version}`)
|
|
158
|
+
return version
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
console.warn(
|
|
162
|
+
`â Unexpected or empty version format for ${packageName}@${tag}: ${JSON.stringify(versionData)}`
|
|
163
|
+
)
|
|
164
|
+
return null
|
|
165
|
+
} catch (error: any) {
|
|
166
|
+
// Trim error message to avoid overly verbose logs from npm
|
|
167
|
+
const errorMessage = error.message?.split('\n')[0]
|
|
168
|
+
console.warn(
|
|
169
|
+
`â ď¸ Could not fetch version for ${packageName}@${tag}. Error: ${errorMessage}`
|
|
170
|
+
)
|
|
171
|
+
return null
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async function updatePackages(packagesToUpdate: string[], cwd: string) {
|
|
176
|
+
if (packagesToUpdate.length === 0) {
|
|
177
|
+
console.info('No packages to update after resolving versions.')
|
|
178
|
+
return
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
$.cwd(cwd)
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
rmSync(`node_modules/vite`, {
|
|
185
|
+
recursive: true,
|
|
186
|
+
force: true,
|
|
187
|
+
})
|
|
188
|
+
} catch (_e) {
|
|
189
|
+
// ignore if vite is not there
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (globalTag) {
|
|
193
|
+
// check which packages actually have the tag
|
|
194
|
+
console.info(`đ Checking which packages have tag '${globalTag}'...\n`)
|
|
195
|
+
const packagesWithTag: string[] = []
|
|
196
|
+
|
|
197
|
+
for (const pkg of packagesToUpdate) {
|
|
198
|
+
try {
|
|
199
|
+
await $`npm view ${pkg}@${globalTag} version --json`.quiet()
|
|
200
|
+
packagesWithTag.push(pkg)
|
|
201
|
+
console.info(` â ${pkg}@${globalTag} exists`)
|
|
202
|
+
} catch {
|
|
203
|
+
console.info(` â ${pkg}@${globalTag} not found, skipping`)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (packagesWithTag.length === 0) {
|
|
208
|
+
console.info(`\nâ ď¸ No packages found with tag '${globalTag}'`)
|
|
209
|
+
return
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
console.info(`
|
|
213
|
+
đŚ Updating ${packagesWithTag.length} package(s) with tag '${globalTag}' using --ignore-scripts...
|
|
214
|
+
`)
|
|
215
|
+
|
|
216
|
+
const packageNamesWithTags = packagesWithTag.map((pkg) => `${pkg}@${globalTag}`)
|
|
217
|
+
const addCommand = `bun add ${packageNamesWithTags.join(' ')} --ignore-scripts`
|
|
218
|
+
console.info(`\nđŞ Running: ${addCommand}\n`)
|
|
219
|
+
|
|
220
|
+
try {
|
|
221
|
+
await $`bun add ${packageNamesWithTags} --ignore-scripts`
|
|
222
|
+
console.info(
|
|
223
|
+
`â
Successfully updated all packages with tag '${globalTag}' (scripts ignored)`
|
|
224
|
+
)
|
|
225
|
+
} catch (error: any) {
|
|
226
|
+
const errorMessage = error.message?.split('\n')[0]
|
|
227
|
+
console.warn(`â ď¸ Failed to update packages. Error: ${errorMessage}`)
|
|
228
|
+
}
|
|
229
|
+
} else {
|
|
230
|
+
// Bulk update when not using tags
|
|
231
|
+
console.info(`
|
|
232
|
+
đŚ Bulk updating ${packagesToUpdate.length} package(s) using --latest --ignore-scripts...
|
|
233
|
+
`)
|
|
234
|
+
|
|
235
|
+
const updateCommand = `bun update ${packagesToUpdate.join(' ')} --latest --ignore-scripts`
|
|
236
|
+
console.info(`\nđŞ Running: ${updateCommand}\n`)
|
|
237
|
+
|
|
238
|
+
try {
|
|
239
|
+
await $`bun update ${packagesToUpdate} --latest --ignore-scripts`
|
|
240
|
+
console.info(`â
Successfully updated all packages (scripts ignored)`)
|
|
241
|
+
} catch (error: any) {
|
|
242
|
+
const errorMessage = error.message?.split('\n')[0]
|
|
243
|
+
console.warn(`â ď¸ Failed to update packages. Error: ${errorMessage}`)
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
console.info(
|
|
248
|
+
"\nâď¸ Running a final 'bun install' to process all changes and run lifecycle scripts..."
|
|
249
|
+
)
|
|
250
|
+
try {
|
|
251
|
+
await $`bun install`
|
|
252
|
+
console.info("â
Final 'bun install' completed successfully.")
|
|
253
|
+
} catch (error: any) {
|
|
254
|
+
const errorMessage = error.message?.split('\n')[0]
|
|
255
|
+
console.error(`đ¨ Final 'bun install' failed. Error: ${errorMessage}`)
|
|
256
|
+
console.error(
|
|
257
|
+
'Your dependencies might be in an inconsistent state. Please check manually.'
|
|
258
|
+
)
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
async function main() {
|
|
263
|
+
const rootDir = process.cwd()
|
|
264
|
+
const packageJsonFiles = findPackageJsonFiles(rootDir)
|
|
265
|
+
console.info(`Found ${packageJsonFiles.length} package.json files`)
|
|
266
|
+
|
|
267
|
+
// Get workspace package names to exclude from updates
|
|
268
|
+
const workspacePackageNames = new Set<string>()
|
|
269
|
+
for (const packageJsonPath of packageJsonFiles) {
|
|
270
|
+
// skip the root package.json when collecting workspace names
|
|
271
|
+
if (packageJsonPath === join(rootDir, 'package.json')) continue
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
const content = readFileSync(packageJsonPath, 'utf-8')
|
|
275
|
+
const packageJson = JSON.parse(content)
|
|
276
|
+
if (packageJson.name) {
|
|
277
|
+
workspacePackageNames.add(packageJson.name)
|
|
278
|
+
}
|
|
279
|
+
} catch (_error) {
|
|
280
|
+
// ignore errors
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
console.info(
|
|
285
|
+
`Found ${workspacePackageNames.size} workspace packages to exclude from updates`
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
const allDependencies = new Set<string>()
|
|
289
|
+
|
|
290
|
+
for (const packageJsonPath of packageJsonFiles) {
|
|
291
|
+
const deps = extractDependencies(packageJsonPath)
|
|
292
|
+
deps.forEach((dep) => allDependencies.add(dep))
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
console.info(`Found ${allDependencies.size} total dependencies`)
|
|
296
|
+
|
|
297
|
+
const matchingDependencies: string[] = []
|
|
298
|
+
for (const dep of allDependencies) {
|
|
299
|
+
// skip workspace packages - they should never be updated through bun update
|
|
300
|
+
if (workspacePackageNames.has(dep)) {
|
|
301
|
+
console.info(`⊠Skipping workspace package: ${dep}`)
|
|
302
|
+
continue
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
for (const pattern of packagePatterns) {
|
|
306
|
+
// packagePatterns from arg parsing
|
|
307
|
+
if (doesPackageMatchPattern(dep, pattern)) {
|
|
308
|
+
matchingDependencies.push(dep)
|
|
309
|
+
break
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
console.info(
|
|
315
|
+
`Found ${matchingDependencies.length} dependencies matching patterns: ${packagePatterns.join(', ')}`
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
if (matchingDependencies.length === 0) {
|
|
319
|
+
console.info('No matching packages found to update.')
|
|
320
|
+
return
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const packagesForBunUpdate: string[] = [...matchingDependencies]
|
|
324
|
+
|
|
325
|
+
if (globalTag) {
|
|
326
|
+
console.info(
|
|
327
|
+
`đˇď¸ Using tag '${globalTag}' for ${packagesForBunUpdate.length} package(s)`
|
|
328
|
+
)
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
await updatePackages(packagesForBunUpdate, rootDir)
|
|
332
|
+
|
|
333
|
+
console.info('\nđ Dependency update complete!')
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
await main()
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { sleep } from '@take-out/helpers'
|
|
4
|
+
|
|
5
|
+
const ONE_SERVER_URL = process.env.ONE_SERVER_URL || 'http://localhost:8081'
|
|
6
|
+
const CHECK_INTERVAL = 2000
|
|
7
|
+
|
|
8
|
+
async function checkServer(): Promise<boolean> {
|
|
9
|
+
try {
|
|
10
|
+
await fetch(ONE_SERVER_URL, {
|
|
11
|
+
signal: AbortSignal.timeout(5000),
|
|
12
|
+
}).then((res) => res.text())
|
|
13
|
+
// give it a couple seconds to build initial route
|
|
14
|
+
await sleep(2000)
|
|
15
|
+
return true
|
|
16
|
+
} catch (error) {
|
|
17
|
+
return false
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function waitForServer(): Promise<void> {
|
|
22
|
+
process.stdout.write(`Waiting for server at ${ONE_SERVER_URL}...\n`)
|
|
23
|
+
|
|
24
|
+
while (true) {
|
|
25
|
+
await new Promise((resolve) => setTimeout(resolve, CHECK_INTERVAL))
|
|
26
|
+
const isReady = await checkServer()
|
|
27
|
+
|
|
28
|
+
if (isReady) {
|
|
29
|
+
process.stdout.write(`â Server at ${ONE_SERVER_URL} is ready!\n`)
|
|
30
|
+
break
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
process.stdout.write(
|
|
34
|
+
`Waiting to start dev watch until after dev server (wait ${CHECK_INTERVAL / 1000}s)...\n`
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
await waitForServer()
|
|
40
|
+
process.exit(0)
|