@bagelink/workspace 1.8.0 → 1.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +290 -7
  2. package/bin/bgl.ts +160 -11
  3. package/dist/bin/bgl.cjs +1283 -18
  4. package/dist/bin/bgl.mjs +1279 -15
  5. package/dist/composable.cjs +21 -0
  6. package/dist/composable.d.cts +50 -0
  7. package/dist/composable.d.mts +50 -0
  8. package/dist/composable.d.ts +50 -0
  9. package/dist/composable.mjs +18 -0
  10. package/dist/index.cjs +3 -155
  11. package/dist/index.d.cts +4 -133
  12. package/dist/index.d.mts +4 -133
  13. package/dist/index.d.ts +4 -133
  14. package/dist/index.mjs +2 -139
  15. package/dist/shared/workspace.CefUteAh.d.cts +49 -0
  16. package/dist/shared/workspace.CefUteAh.d.mts +49 -0
  17. package/dist/shared/workspace.CefUteAh.d.ts +49 -0
  18. package/dist/shared/workspace.Dx9_TIij.cjs +86 -0
  19. package/dist/shared/workspace.Twuo1PFw.mjs +78 -0
  20. package/dist/vite.cjs +110 -0
  21. package/dist/vite.d.cts +98 -0
  22. package/dist/vite.d.mts +98 -0
  23. package/dist/vite.d.ts +98 -0
  24. package/dist/vite.mjs +99 -0
  25. package/env.d.ts +29 -0
  26. package/package.json +28 -5
  27. package/src/build.ts +45 -0
  28. package/src/composable.ts +65 -0
  29. package/src/detect.ts +90 -0
  30. package/src/dev.ts +162 -0
  31. package/src/index.ts +11 -71
  32. package/src/init.ts +60 -12
  33. package/src/lint.ts +323 -0
  34. package/src/netlify.ts +54 -3
  35. package/src/proxy.ts +23 -3
  36. package/src/sdk.ts +196 -0
  37. package/src/types.ts +5 -0
  38. package/src/vite.ts +139 -0
  39. package/src/workspace.ts +107 -23
  40. package/templates/dev-runner.ts +61 -0
  41. package/templates/tsconfig.app.json +23 -0
  42. package/dist/shared/workspace.Bwsdwbt-.cjs +0 -575
  43. package/dist/shared/workspace.Dq-27S1f.mjs +0 -560
package/src/lint.ts ADDED
@@ -0,0 +1,323 @@
1
+ import { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs'
2
+ import { resolve } from 'node:path'
3
+ import process from 'node:process'
4
+ import prompts from 'prompts'
5
+
6
+ /**
7
+ * List of redundant lint config files that can be safely removed
8
+ * after setting up the new lint configuration
9
+ */
10
+ const REDUNDANT_FILES = [
11
+ // Old ESLint configs
12
+ '.eslintrc',
13
+ '.eslintrc.json',
14
+ '.eslintrc.js',
15
+ '.eslintrc.cjs',
16
+ '.eslintrc.yaml',
17
+ '.eslintrc.yml',
18
+ // Oxlint
19
+ 'oxlint.json',
20
+ // Old Prettier configs (we create .prettierrc)
21
+ 'prettier.config.js',
22
+ 'prettier.config.cjs',
23
+ 'prettier.config.mjs',
24
+ '.prettierrc.json',
25
+ '.prettierrc.yaml',
26
+ '.prettierrc.yml',
27
+ '.prettierrc.js',
28
+ '.prettierrc.cjs',
29
+ '.prettierrc.mjs',
30
+ '.prettierrc.toml',
31
+ ]
32
+
33
+ /**
34
+ * Set up linting in a project
35
+ */
36
+ export async function setupLint(
37
+ root: string = process.cwd(),
38
+ isWorkspace: boolean = false,
39
+ ): Promise<void> {
40
+ console.log('\nšŸ” Setting up linting...\n')
41
+
42
+ const response = await prompts([
43
+ {
44
+ type: 'multiselect',
45
+ name: 'configs',
46
+ message: 'Select configurations to set up:',
47
+ choices: [
48
+ { title: 'ESLint', value: 'eslint', selected: true },
49
+ { title: 'Prettier', value: 'prettier', selected: true },
50
+ { title: 'EditorConfig', value: 'editorconfig', selected: true },
51
+ { title: 'Git Hooks', value: 'githooks', selected: false },
52
+ ],
53
+ },
54
+ {
55
+ type: 'confirm',
56
+ name: 'cleanRedundant',
57
+ message: 'Clean up redundant lint config files?',
58
+ initial: true,
59
+ },
60
+ {
61
+ type: 'confirm',
62
+ name: 'installDeps',
63
+ message: 'Install dependencies?',
64
+ initial: true,
65
+ },
66
+ ])
67
+
68
+ if (!response || !response.configs) {
69
+ console.log('\nāŒ Setup cancelled.\n')
70
+ process.exit(1)
71
+ }
72
+
73
+ const { configs, cleanRedundant, installDeps } = response
74
+
75
+ // Clean up redundant files first
76
+ if (cleanRedundant) {
77
+ await cleanRedundantFiles(root)
78
+ }
79
+
80
+ // Create config files
81
+ if (configs.includes('eslint')) {
82
+ createEslintConfig(root, isWorkspace)
83
+ }
84
+
85
+ if (configs.includes('prettier')) {
86
+ createPrettierConfig(root)
87
+ }
88
+
89
+ if (configs.includes('editorconfig')) {
90
+ createEditorConfig(root)
91
+ }
92
+
93
+ if (configs.includes('githooks')) {
94
+ createGitHooks(root)
95
+ }
96
+
97
+ // Update package.json
98
+ updatePackageJsonLint(root, configs)
99
+
100
+ if (installDeps) {
101
+ console.log('\nšŸ“¦ Installing dependencies...')
102
+ console.log('Run: bun add -D @bagelink/lint-config eslint prettier typescript')
103
+ }
104
+
105
+ console.log('\nāœ… Linting setup complete!')
106
+ console.log('\nAvailable commands:')
107
+ console.log(' bun run lint - Run linter')
108
+ console.log(' bun run lint:fix - Fix linting issues')
109
+ console.log(' bun run format - Format code with Prettier')
110
+ console.log('')
111
+ }
112
+
113
+ /**
114
+ * Create ESLint config
115
+ */
116
+ function createEslintConfig(root: string, isWorkspace: boolean): void {
117
+ const configPath = resolve(root, 'eslint.config.js')
118
+
119
+ const config = isWorkspace
120
+ ? `import { defineConfig } from '@bagelink/lint-config/eslint'
121
+
122
+ export default defineConfig({
123
+ // Workspace-level ESLint config
124
+ ignores: ['**/dist/**', '**/node_modules/**', '**/.bun-cache/**'],
125
+ })
126
+ `
127
+ : `import vue3Config from '@bagelink/lint-config/eslint/vue3'
128
+
129
+ export default vue3Config
130
+ `
131
+
132
+ writeFileSync(configPath, config)
133
+ console.log('āœ… Created eslint.config.js')
134
+ }
135
+
136
+ /**
137
+ * Create Prettier config
138
+ */
139
+ function createPrettierConfig(root: string): void {
140
+ const configPath = resolve(root, '.prettierrc')
141
+
142
+ const config = {
143
+ semi: false,
144
+ singleQuote: true,
145
+ tabWidth: 2,
146
+ useTabs: true,
147
+ trailingComma: 'all',
148
+ printWidth: 100,
149
+ arrowParens: 'avoid',
150
+ }
151
+
152
+ writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`)
153
+ console.log('āœ… Created .prettierrc')
154
+
155
+ // .prettierignore
156
+ const ignorePath = resolve(root, '.prettierignore')
157
+ const ignore = `dist
158
+ node_modules
159
+ .bun-cache
160
+ *.min.js
161
+ *.min.css
162
+ `
163
+
164
+ writeFileSync(ignorePath, ignore)
165
+ console.log('āœ… Created .prettierignore')
166
+ }
167
+
168
+ /**
169
+ * Create EditorConfig
170
+ */
171
+ function createEditorConfig(root: string): void {
172
+ const configPath = resolve(root, '.editorconfig')
173
+
174
+ const config = `root = true
175
+
176
+ [*]
177
+ charset = utf-8
178
+ indent_style = tab
179
+ indent_size = 2
180
+ end_of_line = lf
181
+ insert_final_newline = true
182
+ trim_trailing_whitespace = true
183
+
184
+ [*.md]
185
+ trim_trailing_whitespace = false
186
+
187
+ [*.{json,yml,yaml}]
188
+ indent_style = space
189
+ indent_size = 2
190
+ `
191
+
192
+ writeFileSync(configPath, config)
193
+ console.log('āœ… Created .editorconfig')
194
+ }
195
+
196
+ /**
197
+ * Create Git Hooks
198
+ */
199
+ function createGitHooks(root: string): void {
200
+ const packageJsonPath = resolve(root, 'package.json')
201
+
202
+ if (!existsSync(packageJsonPath)) {
203
+ console.warn('āš ļø No package.json found, skipping git hooks')
204
+ return
205
+ }
206
+
207
+ // .lintstagedrc
208
+ const lintStagedConfig = {
209
+ '*.{js,jsx,ts,tsx,vue}': ['eslint --fix'],
210
+ '*.{json,md,yml,yaml}': ['prettier --write'],
211
+ }
212
+
213
+ writeFileSync(
214
+ resolve(root, '.lintstagedrc'),
215
+ `${JSON.stringify(lintStagedConfig, null, 2)}\n`,
216
+ )
217
+
218
+ console.log('āœ… Created .lintstagedrc')
219
+ console.log('ā„¹ļø Add simple-git-hooks and lint-staged to devDependencies')
220
+ console.log(' Then run: npx simple-git-hooks')
221
+ }
222
+
223
+ /**
224
+ * Clean up redundant lint configuration files
225
+ */
226
+ async function cleanRedundantFiles(root: string): Promise<void> {
227
+ const foundFiles: string[] = []
228
+
229
+ // Check which redundant files exist
230
+ for (const file of REDUNDANT_FILES) {
231
+ const filePath = resolve(root, file)
232
+ if (existsSync(filePath)) {
233
+ foundFiles.push(file)
234
+ }
235
+ }
236
+
237
+ if (foundFiles.length === 0) {
238
+ console.log('✨ No redundant files found')
239
+ return
240
+ }
241
+
242
+ console.log('\nšŸ“‹ Found redundant files:')
243
+ foundFiles.forEach((file) => { console.log(` - ${file}`) })
244
+
245
+ const confirmResponse = await prompts({
246
+ type: 'confirm',
247
+ name: 'confirm',
248
+ message: `Delete ${foundFiles.length} redundant file${foundFiles.length > 1 ? 's' : ''}?`,
249
+ initial: true,
250
+ })
251
+
252
+ if (!confirmResponse.confirm) {
253
+ console.log('ā­ļø Skipped cleaning redundant files')
254
+ return
255
+ }
256
+
257
+ // Delete confirmed files
258
+ let deleted = 0
259
+ for (const file of foundFiles) {
260
+ try {
261
+ unlinkSync(resolve(root, file))
262
+ console.log(`šŸ—‘ļø Deleted ${file}`)
263
+ deleted++
264
+ }
265
+ catch (error) {
266
+ console.error(`āŒ Failed to delete ${file}:`, error)
267
+ }
268
+ }
269
+
270
+ console.log(`āœ… Cleaned up ${deleted} file${deleted > 1 ? 's' : ''}`)
271
+ }
272
+
273
+ /**
274
+ * Update package.json with lint scripts
275
+ */
276
+ function updatePackageJsonLint(root: string, configs: string[]): void {
277
+ const packageJsonPath = resolve(root, 'package.json')
278
+
279
+ if (!existsSync(packageJsonPath)) {
280
+ console.warn('āš ļø No package.json found')
281
+ return
282
+ }
283
+
284
+ try {
285
+ const packageJson = JSON.parse(
286
+ readFileSync(packageJsonPath, 'utf-8'),
287
+ )
288
+
289
+ if (!packageJson.scripts) {
290
+ packageJson.scripts = {}
291
+ }
292
+
293
+ // Add lint scripts
294
+ if (configs.includes('eslint')) {
295
+ if (!packageJson.scripts.lint) {
296
+ packageJson.scripts.lint = 'eslint .'
297
+ }
298
+ if (!packageJson.scripts['lint:fix']) {
299
+ packageJson.scripts['lint:fix'] = 'eslint . --fix'
300
+ }
301
+ }
302
+
303
+ // Add format scripts
304
+ if (configs.includes('prettier')) {
305
+ if (!packageJson.scripts.format) {
306
+ packageJson.scripts.format = 'prettier --write .'
307
+ }
308
+ if (!packageJson.scripts['format:check']) {
309
+ packageJson.scripts['format:check'] = 'prettier --check .'
310
+ }
311
+ }
312
+
313
+ writeFileSync(
314
+ packageJsonPath,
315
+ `${JSON.stringify(packageJson, null, 2)}\n`,
316
+ )
317
+
318
+ console.log('āœ… Updated package.json with lint scripts')
319
+ }
320
+ catch (error) {
321
+ console.error('āŒ Failed to update package.json:', error)
322
+ }
323
+ }
package/src/netlify.ts CHANGED
@@ -5,9 +5,13 @@ import process from 'node:process'
5
5
 
6
6
  /**
7
7
  * Generate netlify.toml redirect configuration
8
+ * Uses environment variables for flexibility across environments
8
9
  */
9
10
  export function generateNetlifyRedirect(config: WorkspaceConfig): string {
10
- const redirect = `[[redirects]]
11
+ const redirect = `# API Proxy Configuration
12
+ # Environment variables are set in Netlify UI or netlify.toml [build.environment] section
13
+
14
+ [[redirects]]
11
15
  from = "${config.proxy}/*"
12
16
  to = "${config.host}/:splat"
13
17
  status = 200
@@ -18,13 +22,49 @@ export function generateNetlifyRedirect(config: WorkspaceConfig): string {
18
22
  return redirect
19
23
  }
20
24
 
25
+ /**
26
+ * Generate netlify.toml with environment variable template
27
+ * Provides a standard config that can be reused across projects
28
+ */
29
+ export function generateNetlifyConfigTemplate(): string {
30
+ return `# Standard Netlify configuration for Bagelink projects
31
+ # Uses environment variables for proxy configuration
32
+
33
+ [build.environment]
34
+ # Set these in Netlify UI or override here
35
+ # BGL_PROXY_PATH = "/api"
36
+ # BGL_API_HOST = "https://your-project.bagel.to"
37
+
38
+ [[redirects]]
39
+ # Proxy API requests to backend
40
+ # Uses BGL_PROXY_PATH and BGL_API_HOST from environment
41
+ from = "/api/*"
42
+ to = "https://your-project.bagel.to/:splat"
43
+ status = 200
44
+ force = true
45
+ headers = {X-From = "Netlify"}
46
+
47
+ # Example: Multiple API backends
48
+ # [[redirects]]
49
+ # from = "/api/v2/*"
50
+ # to = "https://api-v2.example.com/:splat"
51
+ # status = 200
52
+ # force = true
53
+ `
54
+ }
55
+
21
56
  /**
22
57
  * Generate complete netlify.toml file
23
58
  */
24
59
  export function generateNetlifyConfig(
25
60
  config: WorkspaceConfig,
26
61
  additionalConfig?: string,
62
+ useTemplate: boolean = false,
27
63
  ): string {
64
+ if (useTemplate) {
65
+ return generateNetlifyConfigTemplate()
66
+ }
67
+
28
68
  const redirect = generateNetlifyRedirect(config)
29
69
 
30
70
  if (additionalConfig !== undefined && additionalConfig !== '') {
@@ -40,13 +80,24 @@ export function generateNetlifyConfig(
40
80
  export function writeNetlifyConfig(
41
81
  config: WorkspaceConfig,
42
82
  outPath: string = './netlify.toml',
43
- additionalConfig?: string
83
+ additionalConfig?: string,
84
+ useTemplate: boolean = false,
44
85
  ): void {
45
- const content = generateNetlifyConfig(config, additionalConfig)
86
+ const content = generateNetlifyConfig(config, additionalConfig, useTemplate)
46
87
  const resolvedPath = resolve(outPath)
47
88
 
48
89
  writeFileSync(resolvedPath, content, 'utf-8')
49
90
  console.log(`āœ“ Generated netlify.toml at ${resolvedPath}`)
91
+
92
+ if (!useTemplate) {
93
+ console.log('\nšŸ’” Tip: For environment-based config, set these in Netlify UI:')
94
+ console.log(` BGL_PROXY_PATH = "${config.proxy}"`)
95
+ console.log(` BGL_API_HOST = "${config.host}"`)
96
+ if (config.openapi_url) {
97
+ console.log(` BGL_OPENAPI_URL = "${config.openapi_url}"`)
98
+ }
99
+ console.log('')
100
+ }
50
101
  }
51
102
 
52
103
  /**
package/src/proxy.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { IncomingMessage, ServerResponse, ClientRequest } from 'node:http'
1
2
  import type { WorkspaceConfig, ProxyConfig } from './types'
2
3
 
3
4
  /**
@@ -12,7 +13,22 @@ export function createViteProxy(config: WorkspaceConfig): ProxyConfig {
12
13
  target: config.host,
13
14
  changeOrigin: true,
14
15
  rewrite: (path: string) => path.replace(new RegExp(`^${config.proxy}`), ''),
15
- secure: true,
16
+ secure: false,
17
+ ws: true,
18
+ followRedirects: true,
19
+ autoRewrite: true,
20
+ protocolRewrite: 'http',
21
+ configure: (proxy: any, _options: any) => {
22
+ proxy.on('proxyReq', (proxyReq: ClientRequest, req: IncomingMessage, _res: ServerResponse) => {
23
+ // Ensure proper headers are forwarded
24
+ if (req.headers.origin) {
25
+ proxyReq.setHeader('origin', config.host)
26
+ }
27
+ })
28
+ proxy.on('error', (err: Error, _req: IncomingMessage, _res: ServerResponse) => {
29
+ console.log('proxy error', err)
30
+ })
31
+ },
16
32
  }
17
33
  }
18
34
 
@@ -21,7 +37,9 @@ export function createViteProxy(config: WorkspaceConfig): ProxyConfig {
21
37
  proxy['/files'] = {
22
38
  target: config.host,
23
39
  changeOrigin: true,
24
- secure: true,
40
+ secure: false,
41
+ ws: true,
42
+ followRedirects: true,
25
43
  }
26
44
  }
27
45
 
@@ -38,6 +56,7 @@ export function createCustomProxy(
38
56
  changeOrigin?: boolean
39
57
  rewrite?: boolean
40
58
  secure?: boolean
59
+ ws?: boolean
41
60
  } = {}
42
61
  ): ProxyConfig {
43
62
  const proxy: ProxyConfig = {}
@@ -46,7 +65,8 @@ export function createCustomProxy(
46
65
  proxy[path] = {
47
66
  target,
48
67
  changeOrigin: options.changeOrigin ?? true,
49
- secure: options.secure ?? true,
68
+ secure: options.secure ?? false,
69
+ ws: options.ws ?? true,
50
70
  ...(options.rewrite === true && {
51
71
  rewrite: (p: string) => p.replace(new RegExp(`^${path}`), ''),
52
72
  }),
package/src/sdk.ts ADDED
@@ -0,0 +1,196 @@
1
+ import type { WorkspaceConfig } from './types'
2
+ import { existsSync, mkdirSync, writeFileSync } from 'node:fs'
3
+ import { resolve } from 'node:path'
4
+ import process from 'node:process'
5
+ import prompts from 'prompts'
6
+
7
+ /**
8
+ * Generate SDK from OpenAPI spec
9
+ */
10
+ export async function generateSDK(
11
+ root: string = process.cwd(),
12
+ ): Promise<void> {
13
+ console.log('\nšŸ”§ Generating SDK from OpenAPI...\n')
14
+
15
+ // Try to load config
16
+ let config: WorkspaceConfig | null = null
17
+ let openApiUrl: string | undefined
18
+
19
+ try {
20
+ const configPath = resolve(root, 'bgl.config.ts')
21
+ if (existsSync(configPath)) {
22
+ const module = await import(`file://${configPath}`)
23
+ const workspace = module.default
24
+ if (typeof workspace === 'function') {
25
+ config = workspace('development')
26
+ if (config?.openapi_url) {
27
+ openApiUrl = config.openapi_url
28
+ }
29
+ }
30
+ }
31
+ }
32
+ catch {
33
+ // Ignore config load errors
34
+ }
35
+
36
+ // Prompt for missing info
37
+ const response = await prompts([
38
+ {
39
+ type: openApiUrl !== undefined ? null : 'text',
40
+ name: 'openApiUrl',
41
+ message: 'OpenAPI spec URL:',
42
+ initial: openApiUrl ?? 'http://localhost:8000/openapi.json',
43
+ },
44
+ {
45
+ type: 'text',
46
+ name: 'outputDir',
47
+ message: 'Output directory:',
48
+ initial: './src/api',
49
+ },
50
+ {
51
+ type: 'confirm',
52
+ name: 'splitFiles',
53
+ message: 'Split into organized files?',
54
+ initial: true,
55
+ },
56
+ ])
57
+
58
+ if (!response) {
59
+ console.log('\nāŒ SDK generation cancelled.\n')
60
+ process.exit(1)
61
+ }
62
+
63
+ const finalUrl = openApiUrl ?? response.openApiUrl
64
+ const { outputDir, splitFiles } = response
65
+
66
+ console.log(`\nšŸ“” Fetching OpenAPI spec from: ${finalUrl}`)
67
+ console.log(`šŸ“ Output directory: ${outputDir}\n`)
68
+
69
+ try {
70
+ // Dynamic import of @bagelink/sdk
71
+ const { openAPI } = await import('@bagelink/sdk')
72
+ const { readFileSync } = await import('node:fs')
73
+ const { dirname, join } = await import('node:path')
74
+ const { fileURLToPath } = await import('node:url')
75
+
76
+ const { types, code } = await openAPI(finalUrl, '/api')
77
+
78
+ const outputPath = resolve(root, outputDir)
79
+ if (!existsSync(outputPath)) {
80
+ mkdirSync(outputPath, { recursive: true })
81
+ }
82
+
83
+ // Write types
84
+ const typesPath = resolve(outputPath, 'types.d.ts')
85
+ writeFileSync(typesPath, types)
86
+ console.log('āœ… Generated types.d.ts')
87
+
88
+ // Write API client
89
+ const apiPath = resolve(outputPath, 'api.ts')
90
+ writeFileSync(apiPath, code)
91
+ console.log('āœ… Generated api.ts')
92
+
93
+ // Copy streamClient.ts from @bagelink/sdk
94
+ try {
95
+ const sdkModule = await import('@bagelink/sdk')
96
+ const sdkPath = fileURLToPath(import.meta.resolve('@bagelink/sdk'))
97
+ const sdkDir = dirname(sdkPath)
98
+ const streamClientSource = join(sdkDir, 'openAPITools', 'streamClient.ts')
99
+
100
+ if (existsSync(streamClientSource)) {
101
+ const streamClientCode = readFileSync(streamClientSource, 'utf-8')
102
+ const streamClientPath = resolve(outputPath, 'streamClient.ts')
103
+ writeFileSync(streamClientPath, streamClientCode)
104
+ console.log('āœ… Generated streamClient.ts')
105
+ }
106
+ } catch (e) {
107
+ // Stream client is optional, don't fail if not found
108
+ console.log('ā„¹ļø streamClient.ts not found (optional)')
109
+ }
110
+
111
+ // Write index
112
+ const indexPath = resolve(outputPath, 'index.ts')
113
+ writeFileSync(
114
+ indexPath,
115
+ 'export * from \'./api\'\nexport * from \'./types.d\'\n',
116
+ )
117
+ console.log('āœ… Generated index.ts')
118
+
119
+ if (splitFiles) {
120
+ console.log('\nšŸ”€ Splitting into organized files...')
121
+ console.log('ā„¹ļø File splitting requires @bagelink/sdk bin scripts')
122
+ console.log(' Keeping monolithic structure for now')
123
+ // Note: File splitting requires unpublished bin scripts
124
+ // Users can manually run: bunx bagelink generate
125
+ }
126
+
127
+ console.log('\nāœ… SDK generated successfully!')
128
+ console.log(`\nImport it in your code:`)
129
+ console.log(` import { api } from '${outputDir.replace('./src/', './')}'`)
130
+ console.log('')
131
+ }
132
+ catch (error: unknown) {
133
+ console.error('\nāŒ Failed to generate SDK:')
134
+ if (error instanceof Error) {
135
+ console.error(error.message)
136
+ }
137
+ else {
138
+ console.error(error)
139
+ }
140
+ console.log('\nMake sure:')
141
+ console.log(' 1. @bagelink/sdk is installed: bun add -D @bagelink/sdk')
142
+ console.log(' 2. OpenAPI URL is accessible')
143
+ console.log(' 3. API server is running (if using localhost)')
144
+ process.exit(1)
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Generate SDK for all projects in workspace
150
+ */
151
+ export async function generateSDKForWorkspace(root: string = process.cwd()): Promise<void> {
152
+ console.log('\nšŸ¢ Generating SDK for workspace projects...\n')
153
+
154
+ // Find all projects
155
+ const fs = await import('node:fs')
156
+ const items = fs.readdirSync(root, { withFileTypes: true })
157
+ const projects = items
158
+ .filter(
159
+ item => item.isDirectory()
160
+ && item.name !== 'node_modules'
161
+ && item.name !== 'shared'
162
+ && item.name !== '.git'
163
+ && !item.name.startsWith('.'),
164
+ )
165
+ .map(item => item.name)
166
+
167
+ if (projects.length === 0) {
168
+ console.log('No projects found in workspace')
169
+ return
170
+ }
171
+
172
+ const response = await prompts({
173
+ type: 'multiselect',
174
+ name: 'selectedProjects',
175
+ message: 'Select projects to generate SDK for:',
176
+ choices: projects.map(p => ({ title: p, value: p, selected: true })),
177
+ })
178
+
179
+ if (!response || !response.selectedProjects || response.selectedProjects.length === 0) {
180
+ console.log('\nāŒ No projects selected.\n')
181
+ return
182
+ }
183
+
184
+ for (const project of response.selectedProjects) {
185
+ console.log(`\nšŸ“¦ Generating SDK for: ${project}`)
186
+ const projectPath = resolve(root, project)
187
+ try {
188
+ await generateSDK(projectPath)
189
+ }
190
+ catch {
191
+ console.error(`Failed to generate SDK for ${project}`)
192
+ }
193
+ }
194
+
195
+ console.log('\nāœ… All SDKs generated!')
196
+ }
package/src/types.ts CHANGED
@@ -45,5 +45,10 @@ export interface ProxyConfig {
45
45
  changeOrigin: boolean
46
46
  rewrite?: (path: string) => string
47
47
  secure: boolean
48
+ ws?: boolean
49
+ followRedirects?: boolean
50
+ autoRewrite?: boolean
51
+ protocolRewrite?: string
52
+ configure?: (proxy: any, options: any) => void
48
53
  }
49
54
  }