@bagelink/workspace 1.8.0 → 1.8.3

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/README.md CHANGED
@@ -79,7 +79,66 @@ export default defineWorkspace(configs)
79
79
 
80
80
  ## Usage
81
81
 
82
- ### 1. Configure Vite (`vite.config.ts`)
82
+ ### 1. Add Type Definitions
83
+
84
+ Add to your project's `env.d.ts`:
85
+
86
+ ```typescript
87
+ /// <reference types="@bagelink/workspace/env" />
88
+ ```
89
+
90
+ This provides TypeScript types for injected environment variables.
91
+
92
+ ### 2. Configure Vite (`vite.config.ts`)
93
+
94
+ **Recommended: Use the Vite plugin (keeps your config clean and standard)**
95
+
96
+ ```typescript
97
+ import { defineConfig } from 'vite'
98
+ import vue from '@vitejs/plugin-vue'
99
+ import { bagelink } from '@bagelink/workspace/vite'
100
+ import workspace from './bgl.config'
101
+
102
+ export default defineConfig({
103
+ plugins: [
104
+ vue(),
105
+ bagelink({ workspace }),
106
+ ],
107
+ })
108
+ ```
109
+
110
+ The plugin automatically:
111
+ - Configures proxy based on `bgl.config.ts`
112
+ - Sets up `@` alias pointing to `./src`
113
+ - Sets up `@shared` alias (in monorepos)
114
+ - Keeps your vite.config.ts clean and extensible
115
+
116
+ **Advanced: Custom options**
117
+
118
+ ```typescript
119
+ import { defineConfig } from 'vite'
120
+ import vue from '@vitejs/plugin-vue'
121
+ import { bagelink } from '@bagelink/workspace/vite'
122
+ import { fileURLToPath } from 'node:url'
123
+ import workspace from './bgl.config'
124
+
125
+ export default defineConfig({
126
+ plugins: [
127
+ vue(),
128
+ bagelink({
129
+ workspace,
130
+ config: {
131
+ sharedPath: '../packages/shared',
132
+ additionalAliases: {
133
+ '@utils': fileURLToPath(new URL('./src/utils', import.meta.url))
134
+ }
135
+ }
136
+ }),
137
+ ],
138
+ })
139
+ ```
140
+
141
+ **Legacy: Manual proxy setup**
83
142
 
84
143
  ```typescript
85
144
  import { defineConfig } from 'vite'
@@ -98,7 +157,46 @@ export default defineConfig(({ mode }) => {
98
157
  })
99
158
  ```
100
159
 
101
- ### 2. Add scripts to `package.json`
160
+ ### 3. Use Configuration in Your App
161
+
162
+ **Access config at runtime with `useWorkspace()`:**
163
+
164
+ ```typescript
165
+ import { useWorkspace, getApiUrl } from '@bagelink/workspace'
166
+
167
+ // In your app setup
168
+ const { proxy, host, mode } = useWorkspace()
169
+ const auth = createAuth({ baseURL: proxy })
170
+
171
+ // Or get full API URL
172
+ const apiUrl = getApiUrl() // 'https://project.bagel.to/api'
173
+ ```
174
+
175
+ **Vue component example:**
176
+
177
+ ```vue
178
+ <script setup lang="ts">
179
+ import { useWorkspace } from '@bagelink/workspace'
180
+ import { createAuth } from '@bagelink/auth'
181
+
182
+ const { proxy, host, mode } = useWorkspace()
183
+ const auth = createAuth({ baseURL: proxy })
184
+
185
+ console.log('API Host:', host)
186
+ console.log('Environment:', mode)
187
+ </script>
188
+ ```
189
+
190
+ **Access raw environment variables:**
191
+
192
+ ```typescript
193
+ // These are injected at build time by the bagelink plugin
194
+ const proxy = import.meta.env.VITE_BGL_PROXY // '/api'
195
+ const host = import.meta.env.VITE_BGL_HOST // 'https://project.bagel.to'
196
+ const openapi = import.meta.env.VITE_BGL_OPENAPI_URL // optional
197
+ ```
198
+
199
+ ### 4. Add scripts to `package.json`
102
200
 
103
201
  ```json
104
202
  {
@@ -110,7 +208,7 @@ export default defineConfig(({ mode }) => {
110
208
  }
111
209
  ```
112
210
 
113
- ### 3. Generate Netlify Config
211
+ ### 5. Generate Netlify Config
114
212
 
115
213
  ```typescript
116
214
  import { writeNetlifyConfig } from '@bagelink/workspace'
@@ -268,13 +366,182 @@ bun run build
268
366
  - Third project: `http://localhost:5175`
269
367
  - etc.
270
368
 
369
+ ### Linting Setup
370
+
371
+ #### `bgl lint init`
372
+
373
+ Set up linting and formatting in your project:
374
+
375
+ ```bash
376
+ bgl lint init
377
+
378
+ ? Select configurations to set up:
379
+ ✔ ESLint
380
+ ✔ Prettier
381
+ ✔ EditorConfig
382
+ ○ Git Hooks
383
+ ? Install dependencies? › Yes
384
+
385
+ ✅ Created eslint.config.js
386
+ ✅ Created .prettierrc
387
+ ✅ Created .prettierignore
388
+ ✅ Created .editorconfig
389
+ ✅ Updated package.json with lint scripts
390
+ ```
391
+
392
+ **Creates:**
393
+ - `eslint.config.js` - ESLint configuration (Vue 3 + TypeScript)
394
+ - `.prettierrc` - Prettier configuration
395
+ - `.prettierignore` - Prettier ignore patterns
396
+ - `.editorconfig` - Editor configuration
397
+ - `.lintstagedrc` - Lint-staged configuration (if git hooks selected)
398
+
399
+ **Adds scripts:**
400
+ - `bun run lint` - Run linter
401
+ - `bun run lint:fix` - Fix linting issues
402
+ - `bun run format` - Format code
403
+ - `bun run format:check` - Check formatting
404
+
405
+ **Auto-detects workspace:**
406
+ ```bash
407
+ # In workspace root (auto-detected)
408
+ bgl lint init
409
+ ✓ Detected workspace mode
410
+ # Sets up at workspace root
411
+
412
+ # In single project (auto-detected)
413
+ bgl lint init
414
+ # Sets up in current project
415
+
416
+ # Force modes:
417
+ bgl lint init --workspace # Force workspace mode
418
+ bgl lint init --project # Force single project mode
419
+ ```
420
+
421
+ **Workspace detection:**
422
+ - Checks for `workspaces` field in package.json
423
+ - Checks for multiple project directories
424
+ - Auto-applies best mode
425
+
426
+ ### SDK Generation
427
+
428
+ #### `bgl sdk generate`
429
+
430
+ Generate TypeScript SDK from OpenAPI specification:
431
+
432
+ ```bash
433
+ bgl sdk generate
434
+
435
+ ? OpenAPI spec URL: › http://localhost:8000/openapi.json
436
+ ? Output directory: › ./src/api
437
+ ? Split into organized files? › Yes
438
+
439
+ 📡 Fetching OpenAPI spec from: http://localhost:8000/openapi.json
440
+ 📁 Output directory: ./src/api
441
+
442
+ ✅ Generated types.d.ts
443
+ ✅ Generated api.ts
444
+ ✅ Generated index.ts
445
+ 🔀 Splitting into organized files...
446
+ ✅ Files organized into directories
447
+
448
+ ✅ SDK generated successfully!
449
+
450
+ Import it in your code:
451
+ import { api } from './api'
452
+ ```
453
+
454
+ **Features:**
455
+ - Auto-reads `openapi_url` from `bgl.config.ts`
456
+ - Generates TypeScript types from OpenAPI schema
457
+ - Creates type-safe API client
458
+ - Optional file organization (split by endpoints)
459
+ - Works with both local and remote OpenAPI specs
460
+
461
+ **Auto-detects workspace:**
462
+ ```bash
463
+ # In workspace root (auto-detected)
464
+ bgl sdk generate
465
+ ✓ Detected workspace mode - will generate for multiple projects
466
+
467
+ ? Select projects to generate SDK for:
468
+ ✔ admin
469
+ ✔ customer
470
+ ✔ mobile
471
+
472
+ # In single project (auto-detected)
473
+ bgl sdk generate
474
+ # Generates SDK for current project only
475
+
476
+ # Force modes:
477
+ bgl sdk generate --workspace # Force workspace mode
478
+ bgl sdk generate --project # Force single project mode
479
+ ```
480
+
481
+ **Smart behavior:**
482
+ - Auto-detects workspace structure
483
+ - Prompts for project selection in workspace mode
484
+ - Reads `openapi_url` from each project's `bgl.config.ts`
485
+
486
+ **Generated structure:**
487
+ ```
488
+ src/api/
489
+ ├── index.ts # Main export
490
+ ├── types.d.ts # TypeScript types
491
+ └── api.ts # API client
492
+
493
+ # Or with --split:
494
+ src/api/
495
+ ├── endpoints/
496
+ │ ├── users.ts
497
+ │ ├── auth.ts
498
+ │ └── data.ts
499
+ ├── types/
500
+ │ └── index.ts
501
+ └── index.ts
502
+ ```
503
+
271
504
  ### `npx bgl --help`
272
505
 
273
506
  Show CLI help.
274
507
 
275
508
  ## API
276
509
 
277
- ### `defineWorkspace(configs)`
510
+ ### Runtime Functions
511
+
512
+ #### `useWorkspace()`
513
+
514
+ Get workspace configuration at runtime. Config is injected as environment variables during build.
515
+
516
+ ```typescript
517
+ import { useWorkspace } from '@bagelink/workspace'
518
+
519
+ const { proxy, host, openapiUrl, mode } = useWorkspace()
520
+ ```
521
+
522
+ **Returns:**
523
+ ```typescript
524
+ interface RuntimeWorkspaceConfig {
525
+ proxy: string // '/api'
526
+ host: string // 'https://project.bagel.to'
527
+ openapiUrl?: string // optional
528
+ mode: 'localhost' | 'development' | 'production'
529
+ }
530
+ ```
531
+
532
+ #### `getApiUrl()`
533
+
534
+ Get the full API URL by combining host and proxy.
535
+
536
+ ```typescript
537
+ import { getApiUrl } from '@bagelink/workspace'
538
+
539
+ const apiUrl = getApiUrl() // 'https://project.bagel.to/api'
540
+ ```
541
+
542
+ ### Configuration Functions
543
+
544
+ #### `defineWorkspace(configs)`
278
545
 
279
546
  Define workspace configuration for all environments.
280
547
 
@@ -313,21 +580,37 @@ const proxy = workspace.createProxy(config)
313
580
  workspace.generateNetlify(config, './netlify.toml')
314
581
  ```
315
582
 
316
- ### `createViteProxy(config)`
583
+ ### Build-Time Functions
584
+
585
+ These are available from `@bagelink/workspace/vite`:
586
+
587
+ #### `createViteProxy(config)`
317
588
 
318
589
  Generate Vite proxy configuration.
319
590
 
320
- ### `writeNetlifyConfig(config, outPath?, additionalConfig?)`
591
+ ```typescript
592
+ import { createViteProxy } from '@bagelink/workspace/vite'
593
+ ```
594
+
595
+ #### `writeNetlifyConfig(config, outPath?, additionalConfig?)`
321
596
 
322
597
  Generate and write netlify.toml file.
323
598
 
324
- ### `setBuildEnvVars(config)`
599
+ ```typescript
600
+ import { writeNetlifyConfig } from '@bagelink/workspace/vite'
601
+ ```
602
+
603
+ #### `setBuildEnvVars(config)`
325
604
 
326
605
  Set environment variables for build process:
327
606
  - `BGL_PROXY_PATH` - Proxy path (e.g., `/api`)
328
607
  - `BGL_API_HOST` - API host URL
329
608
  - `BGL_OPENAPI_URL` - OpenAPI specification URL
330
609
 
610
+ ```typescript
611
+ import { setBuildEnvVars } from '@bagelink/workspace/vite'
612
+ ```
613
+
331
614
  ## License
332
615
 
333
616
  MIT © Bagel Studio
package/bin/bgl.ts CHANGED
@@ -1,22 +1,41 @@
1
1
  #!/usr/bin/env node
2
+ import { resolve } from 'node:path'
2
3
  import process from 'node:process'
4
+ import { runBuild } from '../src/build.js'
5
+ import { isWorkspace } from '../src/detect.js'
6
+ import { runDev } from '../src/dev.js'
3
7
  import { generateWorkspaceConfig } from '../src/init.js'
8
+ import { setupLint } from '../src/lint.js'
9
+ import { generateSDK, generateSDKForWorkspace } from '../src/sdk.js'
4
10
  import { addProject, initWorkspace, listProjects } from '../src/workspace.js'
5
11
 
6
- const [,, command, ...args] = process.argv
12
+ const [,, command, subcommand, ...args] = process.argv
7
13
 
8
14
  async function main() {
9
15
  if (command === 'init') {
10
- const isWorkspace = args.includes('--workspace') || args.includes('-w')
11
- if (isWorkspace) {
16
+ // Check both subcommand and args for --workspace flag
17
+ const createWorkspace
18
+ = subcommand === '--workspace'
19
+ || subcommand === '-w'
20
+ || args.includes('--workspace')
21
+ || args.includes('-w')
22
+
23
+ // Support 'bgl init .' or 'bgl init <path>'
24
+ let targetPath = process.cwd()
25
+ if (subcommand && !subcommand.startsWith('-')) {
26
+ // If subcommand is not a flag, treat it as a path
27
+ targetPath = subcommand === '.' ? process.cwd() : resolve(process.cwd(), subcommand)
28
+ }
29
+
30
+ if (createWorkspace) {
12
31
  await initWorkspace()
13
32
  }
14
33
  else {
15
- await generateWorkspaceConfig()
34
+ await generateWorkspaceConfig(targetPath)
16
35
  }
17
36
  }
18
37
  else if (command === 'add') {
19
- const projectName = args[0]
38
+ const projectName = subcommand // 'bgl add admin' -> subcommand is 'admin'
20
39
  if (!projectName) {
21
40
  console.error('Error: Project name is required')
22
41
  console.log('Usage: bgl add <project-name>')
@@ -31,27 +50,157 @@ async function main() {
31
50
  }
32
51
  else {
33
52
  console.log('\nProjects:')
34
- projects.forEach(p => console.log(` - ${p}`))
53
+ projects.forEach((p) => { console.log(` - ${p}`) })
35
54
  console.log('')
36
55
  }
37
56
  }
57
+ else if (command === 'lint') {
58
+ if (subcommand === 'init') {
59
+ // Auto-detect workspace or allow override
60
+ const forceWorkspace = args.includes('--workspace') || args.includes('-w')
61
+ const forceProject = args.includes('--project') || args.includes('-p')
62
+
63
+ let workspaceMode = isWorkspace(process.cwd())
64
+ if (forceWorkspace) workspaceMode = true
65
+ if (forceProject) workspaceMode = false
66
+
67
+ if (workspaceMode) {
68
+ console.log('✓ Detected workspace mode')
69
+ }
70
+
71
+ await setupLint(process.cwd(), workspaceMode)
72
+ }
73
+ else {
74
+ console.log(`
75
+ Lint Commands:
76
+ bgl lint init Set up linting (auto-detects workspace)
77
+ bgl lint init --workspace Force workspace mode
78
+ bgl lint init --project Force single project mode
79
+ `)
80
+ process.exit(1)
81
+ }
82
+ }
83
+ else if (command === 'sdk') {
84
+ if (subcommand === 'generate') {
85
+ // Auto-detect workspace or allow override
86
+ const forceWorkspace = args.includes('--workspace') || args.includes('-w')
87
+ const forceProject = args.includes('--project') || args.includes('-p')
88
+
89
+ let workspaceMode = isWorkspace(process.cwd())
90
+ if (forceWorkspace) workspaceMode = true
91
+ if (forceProject) workspaceMode = false
92
+
93
+ if (workspaceMode) {
94
+ console.log('✓ Detected workspace mode - will generate for multiple projects')
95
+ await generateSDKForWorkspace()
96
+ }
97
+ else {
98
+ await generateSDK(process.cwd())
99
+ }
100
+ }
101
+ else {
102
+ console.log(`
103
+ SDK Commands:
104
+ bgl sdk generate Generate SDK (auto-detects workspace)
105
+ bgl sdk generate --workspace Force workspace mode
106
+ bgl sdk generate --project Force single project mode
107
+ `)
108
+ process.exit(1)
109
+ }
110
+ }
111
+ else if (command === 'dev') {
112
+ const { filter, additionalArgs } = parseFilterArgs(
113
+ undefined,
114
+ subcommand,
115
+ args,
116
+ )
117
+ const exitCode = await runDev(filter, additionalArgs)
118
+ process.exit(exitCode)
119
+ }
120
+ else if (command === 'build') {
121
+ const { filter, additionalArgs } = parseFilterArgs(
122
+ undefined,
123
+ subcommand,
124
+ args,
125
+ )
126
+ const exitCode = await runBuild(filter, additionalArgs)
127
+ process.exit(exitCode)
128
+ }
38
129
  else {
39
130
  console.log(`
40
131
  Bagel Workspace CLI
41
132
 
42
133
  Usage:
43
- bgl init Generate bgl.config.ts for single project
44
- bgl init --workspace Create a new workspace with multiple projects
45
- bgl add <name> Add a new project to workspace
46
- bgl list List all projects in workspace
134
+ bgl init [path] Generate bgl.config.ts for single project
135
+ Examples: bgl init, bgl init ., bgl init ./my-app
136
+ bgl init --workspace Create a new workspace with multiple projects
137
+ bgl add <name> Add a new project to workspace
138
+ bgl list List all projects in workspace
139
+ bgl dev [filter] [...args] Run dev servers with clean output (default: './!shared*')
140
+ Additional args are passed to vite (e.g., --mode localhost)
141
+ bgl build [project] [...args] Build project by directory (default: all projects)
142
+ bgl lint init Set up linting (auto-detects workspace)
143
+ bgl sdk generate Generate SDK (auto-detects workspace)
47
144
 
48
145
  Options:
49
- --help, -h Show this help message
146
+ --workspace, -w Force workspace mode
147
+ --project, -p Force single project mode
148
+ --help, -h Show this help message
149
+
150
+ Note: Commands auto-detect workspace mode based on directory structure
50
151
  `)
51
152
  process.exit(command === '--help' || command === '-h' ? 0 : 1)
52
153
  }
53
154
  }
54
155
 
156
+ function normalizeFilter(input: string): string {
157
+ // Keep glob patterns as-is, otherwise ensure ./ prefix
158
+ if (input.startsWith('.') || input.includes('*') || input.includes('[')) {
159
+ return input
160
+ }
161
+ return `./${input}`
162
+ }
163
+
164
+ function parseFilterArgs(
165
+ defaultFilter: string | undefined,
166
+ subcommandArg?: string,
167
+ argsList: string[] = [],
168
+ ): { filter?: string, additionalArgs: string[] } {
169
+ const tokens = [subcommandArg, ...argsList].filter(Boolean) as string[]
170
+
171
+ // Flags that take values
172
+ const flagsWithValues = new Set(['--mode', '--host', '--port'])
173
+
174
+ // Find non-flag tokens (excluding flag values)
175
+ const nonFlagIndexes: number[] = []
176
+ for (let i = 0; i < tokens.length; i++) {
177
+ const token = tokens[i]
178
+ if (token.startsWith('-')) {
179
+ // If this flag takes a value, skip the next token
180
+ if (flagsWithValues.has(token)) {
181
+ i++ // Skip next token (the value)
182
+ }
183
+ } else {
184
+ // Not a flag and not a flag value
185
+ const prevToken = i > 0 ? tokens[i - 1] : null
186
+ if (!prevToken || !flagsWithValues.has(prevToken)) {
187
+ nonFlagIndexes.push(i)
188
+ }
189
+ }
190
+ }
191
+
192
+ const filterIndex = nonFlagIndexes.length > 0
193
+ ? nonFlagIndexes[nonFlagIndexes.length - 1]
194
+ : -1
195
+ const filter = filterIndex >= 0
196
+ ? normalizeFilter(tokens[filterIndex])
197
+ : defaultFilter
198
+ const additionalArgs = filterIndex >= 0
199
+ ? tokens.filter((_, index) => index !== filterIndex)
200
+ : tokens
201
+ return { filter, additionalArgs }
202
+ }
203
+
55
204
  main().catch((error: unknown) => {
56
205
  console.error('Error:', error)
57
206
  process.exit(1)