@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.
@@ -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)
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "baseUrl": ".",
5
+ "outDir": "./dist"
6
+ },
7
+ "include": ["./src/**/*"],
8
+ "exclude": ["**/test", "**/__tests__", "dist", "node_modules"]
9
+ }