@take-out/cli 0.0.39

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.
Files changed (331) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +274 -0
  3. package/cli.mjs +3 -0
  4. package/dist/cjs/cli.cjs +71 -0
  5. package/dist/cjs/cli.js +70 -0
  6. package/dist/cjs/cli.js.map +6 -0
  7. package/dist/cjs/cli.native.js +79 -0
  8. package/dist/cjs/cli.native.js.map +6 -0
  9. package/dist/cjs/commands/changed.cjs +212 -0
  10. package/dist/cjs/commands/changed.js +214 -0
  11. package/dist/cjs/commands/changed.js.map +6 -0
  12. package/dist/cjs/commands/changed.native.js +289 -0
  13. package/dist/cjs/commands/changed.native.js.map +6 -0
  14. package/dist/cjs/commands/docs.cjs +388 -0
  15. package/dist/cjs/commands/docs.js +313 -0
  16. package/dist/cjs/commands/docs.js.map +6 -0
  17. package/dist/cjs/commands/docs.native.js +476 -0
  18. package/dist/cjs/commands/docs.native.js.map +6 -0
  19. package/dist/cjs/commands/env-setup.cjs +90 -0
  20. package/dist/cjs/commands/env-setup.js +78 -0
  21. package/dist/cjs/commands/env-setup.js.map +6 -0
  22. package/dist/cjs/commands/env-setup.native.js +85 -0
  23. package/dist/cjs/commands/env-setup.native.js.map +6 -0
  24. package/dist/cjs/commands/onboard.cjs +479 -0
  25. package/dist/cjs/commands/onboard.js +631 -0
  26. package/dist/cjs/commands/onboard.js.map +6 -0
  27. package/dist/cjs/commands/onboard.native.js +608 -0
  28. package/dist/cjs/commands/onboard.native.js.map +6 -0
  29. package/dist/cjs/commands/run.cjs +148 -0
  30. package/dist/cjs/commands/run.js +116 -0
  31. package/dist/cjs/commands/run.js.map +6 -0
  32. package/dist/cjs/commands/run.native.js +140 -0
  33. package/dist/cjs/commands/run.native.js.map +6 -0
  34. package/dist/cjs/commands/script.cjs +379 -0
  35. package/dist/cjs/commands/script.js +339 -0
  36. package/dist/cjs/commands/script.js.map +6 -0
  37. package/dist/cjs/commands/script.native.js +449 -0
  38. package/dist/cjs/commands/script.native.js.map +6 -0
  39. package/dist/cjs/commands/sync.cjs +190 -0
  40. package/dist/cjs/commands/sync.js +168 -0
  41. package/dist/cjs/commands/sync.js.map +6 -0
  42. package/dist/cjs/commands/sync.native.js +211 -0
  43. package/dist/cjs/commands/sync.native.js.map +6 -0
  44. package/dist/cjs/constants/ascii.cjs +36 -0
  45. package/dist/cjs/constants/ascii.js +30 -0
  46. package/dist/cjs/constants/ascii.js.map +6 -0
  47. package/dist/cjs/constants/ascii.native.js +36 -0
  48. package/dist/cjs/constants/ascii.native.js.map +6 -0
  49. package/dist/cjs/index.cjs +64 -0
  50. package/dist/cjs/index.js +55 -0
  51. package/dist/cjs/index.js.map +6 -0
  52. package/dist/cjs/index.native.js +94 -0
  53. package/dist/cjs/index.native.js.map +6 -0
  54. package/dist/cjs/types.cjs +16 -0
  55. package/dist/cjs/types.js +14 -0
  56. package/dist/cjs/types.js.map +6 -0
  57. package/dist/cjs/types.native.js +15 -0
  58. package/dist/cjs/types.native.js.map +6 -0
  59. package/dist/cjs/utils/env-categories.cjs +272 -0
  60. package/dist/cjs/utils/env-categories.js +296 -0
  61. package/dist/cjs/utils/env-categories.js.map +6 -0
  62. package/dist/cjs/utils/env-categories.native.js +317 -0
  63. package/dist/cjs/utils/env-categories.native.js.map +6 -0
  64. package/dist/cjs/utils/env-setup.cjs +181 -0
  65. package/dist/cjs/utils/env-setup.js +190 -0
  66. package/dist/cjs/utils/env-setup.js.map +6 -0
  67. package/dist/cjs/utils/env-setup.native.js +264 -0
  68. package/dist/cjs/utils/env-setup.native.js.map +6 -0
  69. package/dist/cjs/utils/env.cjs +118 -0
  70. package/dist/cjs/utils/env.js +97 -0
  71. package/dist/cjs/utils/env.js.map +6 -0
  72. package/dist/cjs/utils/env.native.js +128 -0
  73. package/dist/cjs/utils/env.native.js.map +6 -0
  74. package/dist/cjs/utils/files.cjs +215 -0
  75. package/dist/cjs/utils/files.js +164 -0
  76. package/dist/cjs/utils/files.js.map +6 -0
  77. package/dist/cjs/utils/files.native.js +266 -0
  78. package/dist/cjs/utils/files.native.js.map +6 -0
  79. package/dist/cjs/utils/parallel-runner.cjs +99 -0
  80. package/dist/cjs/utils/parallel-runner.js +84 -0
  81. package/dist/cjs/utils/parallel-runner.js.map +6 -0
  82. package/dist/cjs/utils/parallel-runner.native.js +123 -0
  83. package/dist/cjs/utils/parallel-runner.native.js.map +6 -0
  84. package/dist/cjs/utils/ports.cjs +101 -0
  85. package/dist/cjs/utils/ports.js +81 -0
  86. package/dist/cjs/utils/ports.js.map +6 -0
  87. package/dist/cjs/utils/ports.native.js +130 -0
  88. package/dist/cjs/utils/ports.native.js.map +6 -0
  89. package/dist/cjs/utils/prerequisites.cjs +119 -0
  90. package/dist/cjs/utils/prerequisites.js +107 -0
  91. package/dist/cjs/utils/prerequisites.js.map +6 -0
  92. package/dist/cjs/utils/prerequisites.native.js +127 -0
  93. package/dist/cjs/utils/prerequisites.native.js.map +6 -0
  94. package/dist/cjs/utils/prompts.cjs +161 -0
  95. package/dist/cjs/utils/prompts.js +162 -0
  96. package/dist/cjs/utils/prompts.js.map +6 -0
  97. package/dist/cjs/utils/prompts.native.js +179 -0
  98. package/dist/cjs/utils/prompts.native.js.map +6 -0
  99. package/dist/cjs/utils/script-listing.cjs +113 -0
  100. package/dist/cjs/utils/script-listing.js +108 -0
  101. package/dist/cjs/utils/script-listing.js.map +6 -0
  102. package/dist/cjs/utils/script-listing.native.js +174 -0
  103. package/dist/cjs/utils/script-listing.native.js.map +6 -0
  104. package/dist/cjs/utils/sync.cjs +85 -0
  105. package/dist/cjs/utils/sync.js +70 -0
  106. package/dist/cjs/utils/sync.js.map +6 -0
  107. package/dist/cjs/utils/sync.native.js +84 -0
  108. package/dist/cjs/utils/sync.native.js.map +6 -0
  109. package/dist/cjs/utils/welcome.cjs +50 -0
  110. package/dist/cjs/utils/welcome.js +42 -0
  111. package/dist/cjs/utils/welcome.js.map +6 -0
  112. package/dist/cjs/utils/welcome.native.js +47 -0
  113. package/dist/cjs/utils/welcome.native.js.map +6 -0
  114. package/dist/esm/cli.js +79 -0
  115. package/dist/esm/cli.js.map +6 -0
  116. package/dist/esm/cli.mjs +71 -0
  117. package/dist/esm/cli.mjs.map +1 -0
  118. package/dist/esm/cli.native.js +69 -0
  119. package/dist/esm/cli.native.js.map +1 -0
  120. package/dist/esm/commands/changed.js +194 -0
  121. package/dist/esm/commands/changed.js.map +6 -0
  122. package/dist/esm/commands/changed.mjs +178 -0
  123. package/dist/esm/commands/changed.mjs.map +1 -0
  124. package/dist/esm/commands/changed.native.js +273 -0
  125. package/dist/esm/commands/changed.native.js.map +1 -0
  126. package/dist/esm/commands/docs.js +306 -0
  127. package/dist/esm/commands/docs.js.map +6 -0
  128. package/dist/esm/commands/docs.mjs +353 -0
  129. package/dist/esm/commands/docs.mjs.map +1 -0
  130. package/dist/esm/commands/docs.native.js +516 -0
  131. package/dist/esm/commands/docs.native.js.map +1 -0
  132. package/dist/esm/commands/env-setup.js +56 -0
  133. package/dist/esm/commands/env-setup.js.map +6 -0
  134. package/dist/esm/commands/env-setup.mjs +56 -0
  135. package/dist/esm/commands/env-setup.mjs.map +1 -0
  136. package/dist/esm/commands/env-setup.native.js +59 -0
  137. package/dist/esm/commands/env-setup.native.js.map +1 -0
  138. package/dist/esm/commands/onboard.js +645 -0
  139. package/dist/esm/commands/onboard.js.map +6 -0
  140. package/dist/esm/commands/onboard.mjs +445 -0
  141. package/dist/esm/commands/onboard.mjs.map +1 -0
  142. package/dist/esm/commands/onboard.native.js +584 -0
  143. package/dist/esm/commands/onboard.native.js.map +1 -0
  144. package/dist/esm/commands/run.js +95 -0
  145. package/dist/esm/commands/run.js.map +6 -0
  146. package/dist/esm/commands/run.mjs +114 -0
  147. package/dist/esm/commands/run.mjs.map +1 -0
  148. package/dist/esm/commands/run.native.js +133 -0
  149. package/dist/esm/commands/run.native.js.map +1 -0
  150. package/dist/esm/commands/script.js +338 -0
  151. package/dist/esm/commands/script.js.map +6 -0
  152. package/dist/esm/commands/script.mjs +336 -0
  153. package/dist/esm/commands/script.mjs.map +1 -0
  154. package/dist/esm/commands/script.native.js +445 -0
  155. package/dist/esm/commands/script.native.js.map +1 -0
  156. package/dist/esm/commands/sync.js +158 -0
  157. package/dist/esm/commands/sync.js.map +6 -0
  158. package/dist/esm/commands/sync.mjs +155 -0
  159. package/dist/esm/commands/sync.mjs.map +1 -0
  160. package/dist/esm/commands/sync.native.js +173 -0
  161. package/dist/esm/commands/sync.native.js.map +1 -0
  162. package/dist/esm/constants/ascii.js +14 -0
  163. package/dist/esm/constants/ascii.js.map +6 -0
  164. package/dist/esm/constants/ascii.mjs +12 -0
  165. package/dist/esm/constants/ascii.mjs.map +1 -0
  166. package/dist/esm/constants/ascii.native.js +12 -0
  167. package/dist/esm/constants/ascii.native.js.map +1 -0
  168. package/dist/esm/index.js +83 -0
  169. package/dist/esm/index.js.map +6 -0
  170. package/dist/esm/index.mjs +7 -0
  171. package/dist/esm/index.mjs.map +1 -0
  172. package/dist/esm/index.native.js +7 -0
  173. package/dist/esm/index.native.js.map +1 -0
  174. package/dist/esm/types.js +1 -0
  175. package/dist/esm/types.js.map +6 -0
  176. package/dist/esm/types.mjs +2 -0
  177. package/dist/esm/types.mjs.map +1 -0
  178. package/dist/esm/types.native.js +2 -0
  179. package/dist/esm/types.native.js.map +1 -0
  180. package/dist/esm/utils/env-categories.js +272 -0
  181. package/dist/esm/utils/env-categories.js.map +6 -0
  182. package/dist/esm/utils/env-categories.mjs +233 -0
  183. package/dist/esm/utils/env-categories.mjs.map +1 -0
  184. package/dist/esm/utils/env-categories.native.js +246 -0
  185. package/dist/esm/utils/env-categories.native.js.map +1 -0
  186. package/dist/esm/utils/env-setup.js +173 -0
  187. package/dist/esm/utils/env-setup.js.map +6 -0
  188. package/dist/esm/utils/env-setup.mjs +146 -0
  189. package/dist/esm/utils/env-setup.mjs.map +1 -0
  190. package/dist/esm/utils/env-setup.native.js +243 -0
  191. package/dist/esm/utils/env-setup.native.js.map +1 -0
  192. package/dist/esm/utils/env.js +83 -0
  193. package/dist/esm/utils/env.js.map +6 -0
  194. package/dist/esm/utils/env.mjs +90 -0
  195. package/dist/esm/utils/env.mjs.map +1 -0
  196. package/dist/esm/utils/env.native.js +99 -0
  197. package/dist/esm/utils/env.native.js.map +1 -0
  198. package/dist/esm/utils/files.js +150 -0
  199. package/dist/esm/utils/files.js.map +6 -0
  200. package/dist/esm/utils/files.mjs +187 -0
  201. package/dist/esm/utils/files.mjs.map +1 -0
  202. package/dist/esm/utils/files.native.js +247 -0
  203. package/dist/esm/utils/files.native.js.map +1 -0
  204. package/dist/esm/utils/parallel-runner.js +69 -0
  205. package/dist/esm/utils/parallel-runner.js.map +6 -0
  206. package/dist/esm/utils/parallel-runner.mjs +76 -0
  207. package/dist/esm/utils/parallel-runner.mjs.map +1 -0
  208. package/dist/esm/utils/parallel-runner.native.js +109 -0
  209. package/dist/esm/utils/parallel-runner.native.js.map +1 -0
  210. package/dist/esm/utils/ports.js +65 -0
  211. package/dist/esm/utils/ports.js.map +6 -0
  212. package/dist/esm/utils/ports.mjs +74 -0
  213. package/dist/esm/utils/ports.mjs.map +1 -0
  214. package/dist/esm/utils/ports.native.js +93 -0
  215. package/dist/esm/utils/ports.native.js.map +1 -0
  216. package/dist/esm/utils/prerequisites.js +91 -0
  217. package/dist/esm/utils/prerequisites.js.map +6 -0
  218. package/dist/esm/utils/prerequisites.mjs +91 -0
  219. package/dist/esm/utils/prerequisites.mjs.map +1 -0
  220. package/dist/esm/utils/prerequisites.native.js +97 -0
  221. package/dist/esm/utils/prerequisites.native.js.map +1 -0
  222. package/dist/esm/utils/prompts.js +139 -0
  223. package/dist/esm/utils/prompts.js.map +6 -0
  224. package/dist/esm/utils/prompts.mjs +112 -0
  225. package/dist/esm/utils/prompts.mjs.map +1 -0
  226. package/dist/esm/utils/prompts.native.js +115 -0
  227. package/dist/esm/utils/prompts.native.js.map +1 -0
  228. package/dist/esm/utils/script-listing.js +91 -0
  229. package/dist/esm/utils/script-listing.js.map +6 -0
  230. package/dist/esm/utils/script-listing.mjs +76 -0
  231. package/dist/esm/utils/script-listing.mjs.map +1 -0
  232. package/dist/esm/utils/script-listing.native.js +151 -0
  233. package/dist/esm/utils/script-listing.native.js.map +1 -0
  234. package/dist/esm/utils/sync.js +50 -0
  235. package/dist/esm/utils/sync.js.map +6 -0
  236. package/dist/esm/utils/sync.mjs +48 -0
  237. package/dist/esm/utils/sync.mjs.map +1 -0
  238. package/dist/esm/utils/sync.native.js +53 -0
  239. package/dist/esm/utils/sync.native.js.map +1 -0
  240. package/dist/esm/utils/welcome.js +21 -0
  241. package/dist/esm/utils/welcome.js.map +6 -0
  242. package/dist/esm/utils/welcome.mjs +15 -0
  243. package/dist/esm/utils/welcome.mjs.map +1 -0
  244. package/dist/esm/utils/welcome.native.js +18 -0
  245. package/dist/esm/utils/welcome.native.js.map +1 -0
  246. package/docs/aggregates.md +579 -0
  247. package/docs/cloudflare-dev-tunnel.md +41 -0
  248. package/docs/database.md +203 -0
  249. package/docs/docs.md +8 -0
  250. package/docs/emitters.md +562 -0
  251. package/docs/hot-updater.md +223 -0
  252. package/docs/native-hot-update.md +252 -0
  253. package/docs/one-components.md +234 -0
  254. package/docs/one-hooks.md +570 -0
  255. package/docs/one-routes.md +660 -0
  256. package/docs/package-json.md +115 -0
  257. package/docs/react-native-navigation-flow.md +184 -0
  258. package/docs/scripts.md +147 -0
  259. package/docs/sync-prompt.md +208 -0
  260. package/docs/tamagui.md +478 -0
  261. package/docs/testing-integration.md +564 -0
  262. package/docs/triggers.md +450 -0
  263. package/docs/zero.md +719 -0
  264. package/package.json +76 -0
  265. package/scripts/seed.ts +209 -0
  266. package/src/cli.ts +147 -0
  267. package/src/commands/changed.ts +313 -0
  268. package/src/commands/docs.ts +582 -0
  269. package/src/commands/env-setup.ts +69 -0
  270. package/src/commands/onboard.ts +1391 -0
  271. package/src/commands/run.ts +173 -0
  272. package/src/commands/script.ts +587 -0
  273. package/src/commands/sync.ts +305 -0
  274. package/src/constants/ascii.ts +17 -0
  275. package/src/index.ts +63 -0
  276. package/src/types.ts +59 -0
  277. package/src/utils/env-categories.ts +245 -0
  278. package/src/utils/env-setup.ts +338 -0
  279. package/src/utils/env.ts +127 -0
  280. package/src/utils/files.ts +302 -0
  281. package/src/utils/parallel-runner.ts +129 -0
  282. package/src/utils/ports.ts +77 -0
  283. package/src/utils/prerequisites.ts +137 -0
  284. package/src/utils/prompts.ts +197 -0
  285. package/src/utils/script-listing.ts +214 -0
  286. package/src/utils/sync.ts +101 -0
  287. package/src/withOpSqliteStatic.cjs +51 -0
  288. package/types/cli.d.ts +7 -0
  289. package/types/cli.d.ts.map +1 -0
  290. package/types/commands/changed.d.ts +14 -0
  291. package/types/commands/changed.d.ts.map +1 -0
  292. package/types/commands/docs.d.ts +5 -0
  293. package/types/commands/docs.d.ts.map +1 -0
  294. package/types/commands/env-setup.d.ts +25 -0
  295. package/types/commands/env-setup.d.ts.map +1 -0
  296. package/types/commands/onboard.d.ts +16 -0
  297. package/types/commands/onboard.d.ts.map +1 -0
  298. package/types/commands/run.d.ts +8 -0
  299. package/types/commands/run.d.ts.map +1 -0
  300. package/types/commands/script.d.ts +28 -0
  301. package/types/commands/script.d.ts.map +1 -0
  302. package/types/commands/sync.d.ts +5 -0
  303. package/types/commands/sync.d.ts.map +1 -0
  304. package/types/constants/ascii.d.ts +6 -0
  305. package/types/constants/ascii.d.ts.map +1 -0
  306. package/types/index.d.ts +12 -0
  307. package/types/index.d.ts.map +1 -0
  308. package/types/types.d.ts +54 -0
  309. package/types/types.d.ts.map +1 -0
  310. package/types/utils/env-categories.d.ts +8 -0
  311. package/types/utils/env-categories.d.ts.map +1 -0
  312. package/types/utils/env-setup.d.ts +10 -0
  313. package/types/utils/env-setup.d.ts.map +1 -0
  314. package/types/utils/env.d.ts +19 -0
  315. package/types/utils/env.d.ts.map +1 -0
  316. package/types/utils/files.d.ts +47 -0
  317. package/types/utils/files.d.ts.map +1 -0
  318. package/types/utils/parallel-runner.d.ts +15 -0
  319. package/types/utils/parallel-runner.d.ts.map +1 -0
  320. package/types/utils/ports.d.ts +16 -0
  321. package/types/utils/ports.d.ts.map +1 -0
  322. package/types/utils/prerequisites.d.ts +11 -0
  323. package/types/utils/prerequisites.d.ts.map +1 -0
  324. package/types/utils/prompts.d.ts +30 -0
  325. package/types/utils/prompts.d.ts.map +1 -0
  326. package/types/utils/script-listing.d.ts +7 -0
  327. package/types/utils/script-listing.d.ts.map +1 -0
  328. package/types/utils/sync.d.ts +16 -0
  329. package/types/utils/sync.d.ts.map +1 -0
  330. package/types/utils/welcome.d.ts +6 -0
  331. package/types/utils/welcome.d.ts.map +1 -0
@@ -0,0 +1,338 @@
1
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs'
2
+ import { resolve } from 'node:path'
3
+
4
+ import * as clack from '@clack/prompts'
5
+ import pc from 'picocolors'
6
+
7
+ import { updateEnvVariable, readEnvVariable, envFileExists, copyEnvFile } from './env'
8
+ import {
9
+ envCategories,
10
+ getRequiredCategories,
11
+ getOptionalCategories,
12
+ } from './env-categories'
13
+
14
+ import type { EnvCategory, EnvVariable } from '../types'
15
+
16
+ interface SetupOptions {
17
+ skipOptional?: boolean
18
+ envFile?: string
19
+ onlyCategory?: string
20
+ interactive?: boolean
21
+ }
22
+
23
+ export async function setupProductionEnv(
24
+ cwd: string,
25
+ options: SetupOptions = {}
26
+ ): Promise<boolean> {
27
+ const envFile = options.envFile || '.env.production'
28
+ const fullPath = resolve(cwd, envFile)
29
+
30
+ // set up interrupt handler
31
+ const cleanup = () => {
32
+ console.info('\n' + pc.yellow('Setup interrupted. You can resume anytime with:'))
33
+ console.info(pc.cyan(' bun takeout env:setup'))
34
+ console.info(
35
+ pc.gray('\nNote: All environment variables are optional for local development.')
36
+ )
37
+ process.exit(0)
38
+ }
39
+
40
+ process.on('SIGINT', cleanup)
41
+ process.on('SIGTERM', cleanup)
42
+
43
+ try {
44
+ clack.intro(pc.bgCyan(pc.black(' Production Environment Setup ')))
45
+
46
+ console.info(pc.gray('All environment variables are optional.'))
47
+ console.info(pc.gray('You can skip any section or re-run this setup anytime.\n'))
48
+
49
+ // check if .env.production exists, if not create from example
50
+ if (!envFileExists(cwd, envFile)) {
51
+ const createFile = await clack.confirm({
52
+ message: `${envFile} doesn't exist. Create it from example?`,
53
+ initialValue: true,
54
+ })
55
+
56
+ if (clack.isCancel(createFile) || !createFile) {
57
+ clack.cancel('Setup cancelled')
58
+ process.removeListener('SIGINT', cleanup)
59
+ process.removeListener('SIGTERM', cleanup)
60
+ return false
61
+ }
62
+
63
+ const exampleFile = '.env.production.example'
64
+ if (envFileExists(cwd, exampleFile)) {
65
+ copyEnvFile(cwd, exampleFile, envFile)
66
+ console.info(pc.green(`✓ Created ${envFile} from example\n`))
67
+ } else {
68
+ // create empty file
69
+ writeFileSync(fullPath, '# Production Environment Variables\n')
70
+ console.info(pc.green(`✓ Created empty ${envFile}\n`))
71
+ }
72
+ }
73
+
74
+ // filter categories if specific one requested
75
+ let categoriesToSetup = options.onlyCategory
76
+ ? envCategories.filter((cat) => cat.id === options.onlyCategory)
77
+ : envCategories
78
+
79
+ if (categoriesToSetup.length === 0) {
80
+ clack.cancel(`Category "${options.onlyCategory}" not found`)
81
+ process.removeListener('SIGINT', cleanup)
82
+ process.removeListener('SIGTERM', cleanup)
83
+ return false
84
+ }
85
+
86
+ // ask about setting up production env
87
+ if (options.interactive !== false && !options.onlyCategory) {
88
+ const setupProd = await clack.confirm({
89
+ message: 'Do you want to set up production environment variables?',
90
+ initialValue: false,
91
+ })
92
+
93
+ if (clack.isCancel(setupProd) || !setupProd) {
94
+ clack.note(
95
+ `You can set up production environment later with:\n${pc.cyan('bun takeout env:setup')}`,
96
+ pc.yellow('Skipping production setup')
97
+ )
98
+ process.removeListener('SIGINT', cleanup)
99
+ process.removeListener('SIGTERM', cleanup)
100
+ return true
101
+ }
102
+ }
103
+
104
+ // process each category
105
+ for (const category of categoriesToSetup) {
106
+ const shouldSetup = await setupCategory(category, envFile, cwd, options)
107
+ if (!shouldSetup) {
108
+ continue
109
+ }
110
+ }
111
+
112
+ // summary
113
+ const configuredVars: string[] = []
114
+ const skippedVars: string[] = []
115
+
116
+ for (const category of categoriesToSetup) {
117
+ for (const variable of category.variables) {
118
+ const value = readEnvVariable(cwd, variable.key, envFile)
119
+ if (value && value !== '' && !value.includes('your-')) {
120
+ configuredVars.push(variable.key)
121
+ } else if (variable.required) {
122
+ skippedVars.push(variable.key)
123
+ }
124
+ }
125
+ }
126
+
127
+ if (configuredVars.length > 0) {
128
+ clack.outro(pc.green('✓ Environment setup complete!'))
129
+ console.info(
130
+ pc.gray(`\nConfigured ${configuredVars.length} variables in ${envFile}`)
131
+ )
132
+
133
+ if (skippedVars.length > 0) {
134
+ console.info(
135
+ pc.yellow(
136
+ `\nNote: Some required variables were skipped. You'll need to configure these before deploying:`
137
+ )
138
+ )
139
+ skippedVars.forEach((v) => console.info(pc.gray(` - ${v}`)))
140
+ }
141
+
142
+ console.info(pc.cyan('\nYou can re-run this setup anytime with:'))
143
+ console.info(pc.gray(' bun takeout env:setup'))
144
+ console.info(pc.cyan('\nOr set up specific categories:'))
145
+ console.info(pc.gray(' bun takeout env:setup --category aws'))
146
+ console.info(pc.gray(' bun takeout env:setup --category apple'))
147
+ } else {
148
+ clack.outro(pc.yellow('No variables configured'))
149
+ console.info(pc.gray('\nYou can re-run this setup anytime with:'))
150
+ console.info(pc.gray(' bun takeout env:setup'))
151
+ }
152
+
153
+ process.removeListener('SIGINT', cleanup)
154
+ process.removeListener('SIGTERM', cleanup)
155
+ return true
156
+ } catch (error) {
157
+ process.removeListener('SIGINT', cleanup)
158
+ process.removeListener('SIGTERM', cleanup)
159
+ if (error instanceof Error && error.message.includes('cancelled')) {
160
+ return false
161
+ }
162
+ throw error
163
+ }
164
+ }
165
+
166
+ async function setupCategory(
167
+ category: EnvCategory,
168
+ envFile: string,
169
+ cwd: string,
170
+ options: SetupOptions
171
+ ): Promise<boolean> {
172
+ const spinner = clack.spinner()
173
+
174
+ // build category prompt message
175
+ let message = `Set up ${pc.bold(category.name)}?`
176
+ if (!category.required) {
177
+ message += pc.gray(' (optional)')
178
+ }
179
+ if (category.setupTime) {
180
+ message += pc.yellow(` ${category.setupTime}`)
181
+ }
182
+
183
+ console.info('') // add spacing
184
+ const setupCategory = await clack.confirm({
185
+ message,
186
+ initialValue: category.required,
187
+ })
188
+
189
+ if (clack.isCancel(setupCategory) || !setupCategory) {
190
+ console.info(pc.gray(` Skipping ${category.name}`))
191
+ return false
192
+ }
193
+
194
+ console.info(pc.gray(`\n${category.description}\n`))
195
+
196
+ // process each variable in the category
197
+ for (const variable of category.variables) {
198
+ await setupVariable(variable, envFile, cwd)
199
+ }
200
+
201
+ return true
202
+ }
203
+
204
+ async function setupVariable(
205
+ variable: EnvVariable,
206
+ envFile: string,
207
+ cwd: string
208
+ ): Promise<void> {
209
+ // check if already configured
210
+ const existingValue = readEnvVariable(cwd, variable.key, envFile)
211
+ const hasValue =
212
+ existingValue && existingValue !== '' && !existingValue.includes('your-')
213
+
214
+ console.info('') // spacing
215
+ console.info(pc.bold(variable.label))
216
+ console.info(pc.gray(variable.description))
217
+
218
+ if (hasValue) {
219
+ const update = await clack.confirm({
220
+ message: `${pc.green('✓')} Already configured. Update?`,
221
+ initialValue: false,
222
+ })
223
+
224
+ if (clack.isCancel(update) || !update) {
225
+ return
226
+ }
227
+ }
228
+
229
+ // show instructions
230
+ console.info('')
231
+ console.info(pc.cyan('Instructions:'))
232
+ variable.instructions.split('\n').forEach((line) => {
233
+ console.info(pc.gray(` ${line}`))
234
+ })
235
+ console.info('')
236
+
237
+ // handle different input types
238
+ let value: string | undefined
239
+
240
+ if (variable.generator) {
241
+ const generate = await clack.confirm({
242
+ message: `Generate ${variable.label} automatically?`,
243
+ initialValue: true,
244
+ })
245
+
246
+ if (!clack.isCancel(generate) && generate) {
247
+ value = variable.generator()
248
+ console.info(pc.green(`✓ Generated ${variable.label}`))
249
+ }
250
+ }
251
+
252
+ if (!value) {
253
+ if (variable.type === 'multiline') {
254
+ console.info(pc.gray('Paste content (press Enter twice when done):'))
255
+ value = await readMultilineInput()
256
+ } else if (variable.type === 'secret') {
257
+ const result = await clack.password({
258
+ message: `Enter ${variable.label}:`,
259
+ mask: '*',
260
+ })
261
+ if (!clack.isCancel(result)) {
262
+ value = result
263
+ }
264
+ } else {
265
+ const result = await clack.text({
266
+ message: `Enter ${variable.label}:`,
267
+ placeholder: variable.placeholder,
268
+ defaultValue: variable.default,
269
+ validate: (val) => {
270
+ if (variable.required && !val) {
271
+ return 'This field is required'
272
+ }
273
+ },
274
+ })
275
+ if (!clack.isCancel(result)) {
276
+ value = result
277
+ }
278
+ }
279
+ }
280
+
281
+ if (value && !clack.isCancel(value)) {
282
+ updateEnvVariable(cwd, variable.key, value, envFile)
283
+ console.info(pc.green(`✓ Saved ${variable.key}`))
284
+ } else if (variable.required) {
285
+ console.info(pc.yellow(`⚠ Skipped required variable: ${variable.key}`))
286
+ } else {
287
+ console.info(pc.gray(` Skipped ${variable.key}`))
288
+ }
289
+ }
290
+
291
+ async function readMultilineInput(): Promise<string> {
292
+ return new Promise((resolve) => {
293
+ const lines: string[] = []
294
+ let emptyLineCount = 0
295
+
296
+ const reader = process.stdin
297
+ reader.setEncoding('utf8')
298
+
299
+ const onData = (chunk: string) => {
300
+ const chunkLines = chunk.split('\n')
301
+ for (const line of chunkLines) {
302
+ if (line === '') {
303
+ emptyLineCount++
304
+ if (emptyLineCount >= 2) {
305
+ reader.removeListener('data', onData)
306
+ resolve(lines.join('\n'))
307
+ return
308
+ }
309
+ } else {
310
+ if (emptyLineCount === 1) {
311
+ lines.push('') // add the single empty line
312
+ }
313
+ emptyLineCount = 0
314
+ lines.push(line)
315
+ }
316
+ }
317
+ }
318
+
319
+ reader.on('data', onData)
320
+ })
321
+ }
322
+
323
+ export function listCategories(): void {
324
+ console.info(pc.bold('\nAvailable environment categories:\n'))
325
+
326
+ for (const category of envCategories) {
327
+ const status = category.required ? pc.red('required') : pc.gray('optional')
328
+ console.info(` ${pc.cyan(category.id.padEnd(12))} - ${category.name} ${status}`)
329
+ console.info(` ${pc.gray(category.description)}`)
330
+ if (category.setupTime) {
331
+ console.info(` ${pc.yellow(category.setupTime)}`)
332
+ }
333
+ console.info('')
334
+ }
335
+
336
+ console.info(pc.gray('Run setup for a specific category:'))
337
+ console.info(pc.cyan(' bun takeout env:setup --category <id>\n'))
338
+ }
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Environment file operations
3
+ */
4
+
5
+ import { randomBytes } from 'node:crypto'
6
+ import { copyFileSync, existsSync, readFileSync, writeFileSync } from 'node:fs'
7
+ import { join } from 'node:path'
8
+
9
+ export function generateSecret(length = 32): string {
10
+ return randomBytes(length).toString('hex')
11
+ }
12
+
13
+ export function envFileExists(cwd: string, filename = '.env'): boolean {
14
+ return existsSync(join(cwd, filename))
15
+ }
16
+
17
+ export function copyEnvFile(
18
+ cwd: string,
19
+ source: string,
20
+ target: string
21
+ ): { success: boolean; error?: string } {
22
+ const sourcePath = join(cwd, source)
23
+ const targetPath = join(cwd, target)
24
+
25
+ if (!existsSync(sourcePath)) {
26
+ return { success: false, error: `Source file ${source} not found` }
27
+ }
28
+
29
+ if (existsSync(targetPath)) {
30
+ return { success: false, error: `Target file ${target} already exists` }
31
+ }
32
+
33
+ try {
34
+ copyFileSync(sourcePath, targetPath)
35
+ return { success: true }
36
+ } catch (error) {
37
+ return {
38
+ success: false,
39
+ error: error instanceof Error ? error.message : 'Unknown error',
40
+ }
41
+ }
42
+ }
43
+
44
+ export function updateEnvVariable(
45
+ cwd: string,
46
+ key: string,
47
+ value: string,
48
+ filename = '.env'
49
+ ): { success: boolean; error?: string } {
50
+ const envPath = join(cwd, filename)
51
+
52
+ if (!existsSync(envPath)) {
53
+ return { success: false, error: `${filename} not found` }
54
+ }
55
+
56
+ try {
57
+ let content = readFileSync(envPath, 'utf-8')
58
+
59
+ // Check if key exists
60
+ const keyRegex = new RegExp(`^${key}=.*$`, 'm')
61
+
62
+ if (keyRegex.test(content)) {
63
+ // Replace existing value
64
+ content = content.replace(keyRegex, `${key}=${value}`)
65
+ } else {
66
+ // Append new key-value
67
+ content = content.trimEnd() + `\n${key}=${value}\n`
68
+ }
69
+
70
+ writeFileSync(envPath, content, 'utf-8')
71
+ return { success: true }
72
+ } catch (error) {
73
+ return {
74
+ success: false,
75
+ error: error instanceof Error ? error.message : 'Unknown error',
76
+ }
77
+ }
78
+ }
79
+
80
+ export function createEnvLocal(cwd: string): { success: boolean; error?: string } {
81
+ const envLocalPath = join(cwd, '.env.local')
82
+
83
+ if (existsSync(envLocalPath)) {
84
+ return { success: true } // Already exists, that's fine
85
+ }
86
+
87
+ const template = `# Local environment overrides
88
+ # This file is gitignored and never committed
89
+ # Add your personal secrets and local configuration here
90
+ # These values override .env
91
+
92
+ # Example:
93
+ # BETTER_AUTH_SECRET=your-secret-here
94
+ # AWS_ACCESS_KEY_ID=your-key-here
95
+ `
96
+
97
+ try {
98
+ writeFileSync(envLocalPath, template, 'utf-8')
99
+ return { success: true }
100
+ } catch (error) {
101
+ return {
102
+ success: false,
103
+ error: error instanceof Error ? error.message : 'Unknown error',
104
+ }
105
+ }
106
+ }
107
+
108
+ export function readEnvVariable(
109
+ cwd: string,
110
+ key: string,
111
+ filename = '.env'
112
+ ): string | null {
113
+ const envPath = join(cwd, filename)
114
+
115
+ if (!existsSync(envPath)) {
116
+ return null
117
+ }
118
+
119
+ try {
120
+ const content = readFileSync(envPath, 'utf-8')
121
+ const keyRegex = new RegExp(`^${key}=(.*)$`, 'm')
122
+ const match = content.match(keyRegex)
123
+ return match?.[1]?.trim().replace(/^["']|["']$/g, '') || null
124
+ } catch {
125
+ return null
126
+ }
127
+ }