@bagelink/workspace 1.8.26 → 1.8.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/dist/bin/bgl.mjs CHANGED
@@ -2,413 +2,9 @@
2
2
  import { resolve } from 'node:path';
3
3
  import process from 'node:process';
4
4
  import { spawn } from 'node:child_process';
5
- import { existsSync, mkdirSync, writeFileSync, readdirSync, readFileSync, unlinkSync } from 'node:fs';
5
+ import { l as listProjects, w as writeNetlifyConfig, i as initWorkspace, a as addProject } from '../shared/workspace.ThBu2HJO.mjs';
6
+ import { existsSync, readFileSync, readdirSync, writeFileSync, unlinkSync, mkdirSync } from 'node:fs';
6
7
  import prompts from 'prompts';
7
- import { w as writeNetlifyConfig } from '../shared/workspace.Twuo1PFw.mjs';
8
-
9
- async function initWorkspace(root = process.cwd()) {
10
- console.log("\n\u{1F680} Creating Bagel workspace...\n");
11
- const response = await prompts([
12
- {
13
- type: "text",
14
- name: "workspaceName",
15
- message: "Workspace name:",
16
- initial: "my-workspace"
17
- },
18
- {
19
- type: "text",
20
- name: "projectId",
21
- message: "Bagel project ID:",
22
- initial: "my-project"
23
- },
24
- {
25
- type: "confirm",
26
- name: "createFirstProject",
27
- message: "Create first project?",
28
- initial: true
29
- },
30
- {
31
- type: (prev) => prev ? "text" : null,
32
- name: "firstProjectName",
33
- message: "First project name:",
34
- initial: "web"
35
- }
36
- ]);
37
- if (!response || !response.workspaceName) {
38
- console.log("\n\u274C Workspace creation cancelled.\n");
39
- process.exit(1);
40
- }
41
- const { workspaceName, projectId, createFirstProject, firstProjectName } = response;
42
- const workspaceDir = resolve(root, workspaceName);
43
- createWorkspaceRoot(root, workspaceName, projectId);
44
- createSharedPackage(workspaceDir);
45
- if (createFirstProject && firstProjectName) {
46
- await addProject(firstProjectName, workspaceDir);
47
- }
48
- console.log("\n\u2705 Workspace created successfully!");
49
- console.log("\nNext steps:");
50
- console.log(` cd ${workspaceName}`);
51
- console.log(" bun install");
52
- if (createFirstProject) {
53
- console.log(` bun run dev:${firstProjectName}`);
54
- } else {
55
- console.log(" bgl add <project-name> # Add a project");
56
- }
57
- console.log("");
58
- }
59
- function createWorkspaceRoot(root, name, projectId) {
60
- const workspaceDir = resolve(root, name);
61
- if (existsSync(workspaceDir)) {
62
- console.error(`\u274C Directory ${name} already exists`);
63
- process.exit(1);
64
- }
65
- mkdirSync(workspaceDir, { recursive: true });
66
- const packageJson = {
67
- name,
68
- private: true,
69
- workspaces: ["*", "!node_modules"],
70
- scripts: {
71
- "dev": "bgl dev",
72
- "dev:local": "bgl dev --mode localhost",
73
- "dev:verbose": "bun run --filter './!shared*' dev",
74
- "build": "bgl build",
75
- "typecheck": "tsc --noEmit",
76
- "lint": "eslint . --cache",
77
- "lint:fix": "eslint . --cache --fix"
78
- },
79
- dependencies: {
80
- "@bagelink/auth": "latest",
81
- "@bagelink/sdk": "latest",
82
- "@bagelink/vue": "latest",
83
- "pinia": "latest",
84
- "vue": "latest",
85
- "vue-router": "latest"
86
- },
87
- devDependencies: {
88
- "@bagelink/lint-config": "latest",
89
- "@bagelink/workspace": "latest",
90
- "@vitejs/plugin-vue": "latest",
91
- "eslint": "latest",
92
- "typescript": "^5.0.0",
93
- "vite": "latest"
94
- }
95
- };
96
- writeFileSync(
97
- resolve(workspaceDir, "package.json"),
98
- `${JSON.stringify(packageJson, null, 2)}
99
- `
100
- );
101
- const bglConfig = `import { defineWorkspace } from '@bagelink/workspace'
102
-
103
- export default defineWorkspace({
104
- localhost: {
105
- host: 'http://localhost:8000',
106
- proxy: '/api',
107
- openapi_url: 'http://localhost:8000/openapi.json',
108
- },
109
- development: {
110
- host: 'https://${projectId}.bagel.to',
111
- proxy: '/api',
112
- openapi_url: 'https://${projectId}.bagel.to/openapi.json',
113
- },
114
- production: {
115
- host: 'https://${projectId}.bagel.to',
116
- proxy: '/api',
117
- openapi_url: 'https://${projectId}.bagel.to/openapi.json',
118
- },
119
- })
120
- `;
121
- writeFileSync(resolve(workspaceDir, "bgl.config.ts"), bglConfig);
122
- const tsConfig = {
123
- compilerOptions: {
124
- target: "ES2020",
125
- useDefineForClassFields: true,
126
- module: "ESNext",
127
- lib: ["ES2020", "DOM", "DOM.Iterable"],
128
- skipLibCheck: true,
129
- moduleResolution: "bundler",
130
- allowImportingTsExtensions: true,
131
- resolveJsonModule: true,
132
- isolatedModules: true,
133
- noEmit: true,
134
- jsx: "preserve",
135
- strict: true,
136
- noUnusedLocals: true,
137
- noUnusedParameters: true,
138
- noFallthroughCasesInSwitch: true,
139
- baseUrl: ".",
140
- paths: {
141
- "shared/*": ["./shared/*"]
142
- }
143
- }
144
- };
145
- writeFileSync(
146
- resolve(workspaceDir, "tsconfig.json"),
147
- `${JSON.stringify(tsConfig, null, 2)}
148
- `
149
- );
150
- const gitignore = `node_modules
151
- dist
152
- .DS_Store
153
- *.local
154
- .env.local
155
- .vite
156
- `;
157
- writeFileSync(resolve(workspaceDir, ".gitignore"), gitignore);
158
- const scriptsDir = resolve(workspaceDir, "scripts");
159
- mkdirSync(scriptsDir, { recursive: true });
160
- const devRunnerContent = `#!/usr/bin/env bun
161
- import { spawn } from 'bun'
162
- import { readdir } from 'fs/promises'
163
- import { resolve } from 'path'
164
-
165
- const projectsRoot = process.cwd()
166
- const projects = (await readdir(projectsRoot, { withFileTypes: true }))
167
- .filter(
168
- item =>
169
- item.isDirectory()
170
- && item.name !== 'node_modules'
171
- && item.name !== 'shared'
172
- && item.name !== 'scripts'
173
- && item.name !== '.git'
174
- && !item.name.startsWith('.'),
175
- )
176
- .map(item => item.name)
177
-
178
- console.log(\`\\n\u{1F680} Starting \${projects.length} project\${projects.length > 1 ? 's' : ''}...\\n\`)
179
-
180
- const urlPattern = /Local:\\s+(http:\\/\\/localhost:\\d+)/
181
-
182
- projects.forEach((project) => {
183
- const proc = spawn({
184
- cmd: ['bun', 'run', 'dev'],
185
- cwd: resolve(projectsRoot, project),
186
- stdout: 'pipe',
187
- stderr: 'pipe',
188
- })
189
-
190
- const decoder = new TextDecoder()
191
-
192
- proc.stdout.pipeTo(
193
- new WritableStream({
194
- write(chunk) {
195
- const text = decoder.decode(chunk)
196
- const match = text.match(urlPattern)
197
- if (match) {
198
- console.log(\` \u2713 \${project.padEnd(15)} \u2192 \${match[1]}\`)
199
- }
200
- },
201
- }),
202
- )
203
-
204
- proc.stderr.pipeTo(
205
- new WritableStream({
206
- write(chunk) {
207
- const text = decoder.decode(chunk)
208
- if (text.includes('error') || text.includes('Error')) {
209
- console.error(\` \u2717 \${project}: \${text.trim()}\`)
210
- }
211
- },
212
- }),
213
- )
214
- })
215
-
216
- console.log('\\n\u{1F4A1} Press Ctrl+C to stop all servers\\n')
217
-
218
- process.on('SIGINT', () => {
219
- console.log('\\n\\n\u{1F44B} Stopping all servers...\\n')
220
- process.exit()
221
- })
222
- `;
223
- writeFileSync(resolve(scriptsDir, "dev.ts"), devRunnerContent);
224
- console.log(`\u2705 Created workspace: ${name}`);
225
- }
226
- function createSharedPackage(root) {
227
- const sharedDir = resolve(root, "shared");
228
- mkdirSync(sharedDir, { recursive: true });
229
- const packageJson = {
230
- name: "shared",
231
- version: "1.0.0",
232
- type: "module",
233
- exports: {
234
- ".": "./index.ts",
235
- "./utils": "./utils/index.ts",
236
- "./types": "./types/index.ts"
237
- }
238
- };
239
- writeFileSync(
240
- resolve(sharedDir, "package.json"),
241
- `${JSON.stringify(packageJson, null, 2)}
242
- `
243
- );
244
- writeFileSync(
245
- resolve(sharedDir, "index.ts"),
246
- "// Shared utilities and exports\nexport * from './utils'\n"
247
- );
248
- mkdirSync(resolve(sharedDir, "utils"), { recursive: true });
249
- writeFileSync(
250
- resolve(sharedDir, "utils", "index.ts"),
251
- "// Shared utility functions\nexport function formatDate(date: Date): string {\n return date.toISOString()\n}\n"
252
- );
253
- mkdirSync(resolve(sharedDir, "types"), { recursive: true });
254
- writeFileSync(
255
- resolve(sharedDir, "types", "index.ts"),
256
- "// Shared types\nexport interface User {\n id: string\n name: string\n}\n"
257
- );
258
- console.log("\u2705 Created shared package");
259
- }
260
- async function addProject(name, root = process.cwd()) {
261
- const projectDir = resolve(root, name);
262
- if (existsSync(projectDir)) {
263
- console.error(`\u274C Project ${name} already exists`);
264
- process.exit(1);
265
- }
266
- console.log(`
267
- \u{1F4E6} Creating project: ${name}
268
- `);
269
- mkdirSync(projectDir, { recursive: true });
270
- const isWorkspace = existsSync(resolve(root, "bgl.config.ts"));
271
- const packageJson = {
272
- name,
273
- type: "module",
274
- scripts: {
275
- dev: "vite",
276
- build: "vite build",
277
- preview: "vite preview"
278
- },
279
- dependencies: {},
280
- devDependencies: {
281
- "@vitejs/plugin-vue": "latest",
282
- "vite": "latest",
283
- "vue": "latest"
284
- }
285
- };
286
- if (isWorkspace) {
287
- packageJson.dependencies.shared = "workspace:*";
288
- }
289
- writeFileSync(
290
- resolve(projectDir, "package.json"),
291
- `${JSON.stringify(packageJson, null, 2)}
292
- `
293
- );
294
- const bglConfigContent = isWorkspace ? `import { defineWorkspace } from '@bagelink/workspace'
295
- import rootWorkspace from '../bgl.config'
296
-
297
- export default defineWorkspace({
298
- localhost: rootWorkspace('localhost'),
299
- development: rootWorkspace('development'),
300
- production: rootWorkspace('production'),
301
- })
302
- ` : `import { defineWorkspace } from '@bagelink/workspace'
303
-
304
- export default defineWorkspace({
305
- localhost: {
306
- host: 'http://localhost:8000',
307
- proxy: '/api',
308
- },
309
- development: {
310
- host: 'https://my-project.bagel.to',
311
- proxy: '/api',
312
- },
313
- production: {
314
- host: 'https://my-project.bagel.to',
315
- proxy: '/api',
316
- },
317
- })
318
- `;
319
- writeFileSync(resolve(projectDir, "bgl.config.ts"), bglConfigContent);
320
- const viteConfig = `import { defineConfig } from 'vite'
321
- import vue from '@vitejs/plugin-vue'
322
- import { bagelink } from '@bagelink/workspace/vite'
323
- import workspace from './bgl.config'
324
-
325
- export default defineConfig({
326
- plugins: [
327
- vue(),
328
- bagelink({ workspace }),
329
- ],
330
- })
331
- `;
332
- writeFileSync(resolve(projectDir, "vite.config.ts"), viteConfig);
333
- const srcDir = resolve(projectDir, "src");
334
- mkdirSync(srcDir, { recursive: true });
335
- const indexHtml = `<!DOCTYPE html>
336
- <html lang="en">
337
- <head>
338
- <meta charset="UTF-8">
339
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
340
- <title>${name}</title>
341
- </head>
342
- <body>
343
- <div id="app"></div>
344
- <script type="module" src="/src/main.ts"><\/script>
345
- </body>
346
- </html>
347
- `;
348
- writeFileSync(resolve(projectDir, "index.html"), indexHtml);
349
- const mainTs = `import { createApp } from 'vue'
350
- import App from './App.vue'
351
-
352
- createApp(App).mount('#app')
353
- `;
354
- writeFileSync(resolve(srcDir, "main.ts"), mainTs);
355
- const appVue = `<script setup lang="ts">
356
- import { ref } from 'vue'
357
- ${isWorkspace ? "import { formatDate } from 'shared/utils'\n" : ""}
358
- const count = ref(0)
359
- <\/script>
360
-
361
- <template>
362
- <div>
363
- <h1>${name}</h1>
364
- <button @click="count++">Count: {{ count }}</button>
365
- ${isWorkspace ? "<p>{{ formatDate(new Date()) }}</p>" : ""}
366
- </div>
367
- </template>
368
- `;
369
- writeFileSync(resolve(srcDir, "App.vue"), appVue);
370
- console.log(`\u2705 Created project: ${name}`);
371
- if (isWorkspace) {
372
- updateWorkspaceScripts(root, name);
373
- }
374
- console.log("\nNext steps:");
375
- console.log(` cd ${name}`);
376
- console.log(" bun install");
377
- console.log(" bun run dev");
378
- console.log("");
379
- }
380
- function updateWorkspaceScripts(root, projectName) {
381
- const packageJsonPath = resolve(root, "package.json");
382
- if (!existsSync(packageJsonPath)) return;
383
- try {
384
- const packageJson = JSON.parse(
385
- readFileSync(packageJsonPath, "utf-8")
386
- );
387
- if (!packageJson.scripts) {
388
- packageJson.scripts = {};
389
- }
390
- packageJson.scripts[`dev:${projectName}`] = `bun --filter ${projectName} dev`;
391
- packageJson.scripts[`build:${projectName}`] = `bun --filter ${projectName} build`;
392
- writeFileSync(
393
- packageJsonPath,
394
- `${JSON.stringify(packageJson, null, 2)}
395
- `
396
- );
397
- console.log(`\u2705 Added scripts: dev:${projectName}, build:${projectName}`);
398
- } catch (error) {
399
- console.warn("\u26A0\uFE0F Could not update workspace scripts");
400
- }
401
- }
402
- function listProjects(root = process.cwd()) {
403
- try {
404
- const items = readdirSync(root, { withFileTypes: true });
405
- return items.filter(
406
- (item) => item.isDirectory() && item.name !== "node_modules" && item.name !== "shared" && item.name !== "scripts" && item.name !== ".git" && !item.name.startsWith(".")
407
- ).map((item) => item.name);
408
- } catch {
409
- return [];
410
- }
411
- }
412
8
 
413
9
  async function runBuild(filter, additionalArgs = []) {
414
10
  const argsStr = additionalArgs.length > 0 ? ` -- ${additionalArgs.join(" ")}` : "";
@@ -464,7 +60,9 @@ function isWorkspace(root = process.cwd()) {
464
60
  }
465
61
 
466
62
  const servers = /* @__PURE__ */ new Map();
63
+ const projectToPort = /* @__PURE__ */ new Map();
467
64
  const seenLines = /* @__PURE__ */ new Set();
65
+ const START_PORT = 5173;
468
66
  const colors = {
469
67
  reset: "\x1B[0m",
470
68
  cyan: "\x1B[36m",
@@ -479,12 +77,13 @@ function clearAndPrintServers() {
479
77
  }
480
78
  console.log(`${colors.cyan}\u{1F680} Development Servers${colors.reset}
481
79
  `);
482
- for (const [name, info] of servers.entries()) {
483
- if (info.status === "ready" && info.port) {
484
- const url = `http://localhost:${info.port}`;
80
+ const sortedServers = Array.from(servers.entries()).sort((a, b) => a[1].order - b[1].order);
81
+ for (const [name, info] of sortedServers) {
82
+ const url = `http://localhost:${info.assignedPort}`;
83
+ if (info.status === "ready") {
485
84
  console.log(`${colors.green}\u25CF${colors.reset} ${colors.cyan}${name}${colors.reset} ${colors.dim}\u2192${colors.reset} ${url}`);
486
85
  } else {
487
- console.log(`${colors.yellow}\u25CB${colors.reset} ${colors.dim}${name} (starting...)${colors.reset}`);
86
+ console.log(`${colors.yellow}\u25CB${colors.reset} ${colors.dim}${name} (starting...)${colors.reset} ${colors.dim}${url}${colors.reset}`);
488
87
  }
489
88
  }
490
89
  console.log("");
@@ -493,10 +92,20 @@ async function runDev(filter, additionalArgs = []) {
493
92
  const argsStr = additionalArgs.length > 0 ? ` -- ${additionalArgs.join(" ")}` : "";
494
93
  const resolvedFilters = resolveFilters(filter);
495
94
  if (!resolvedFilters || resolvedFilters.length === 0) return 1;
95
+ const projectNames = resolvedFilters.map((f) => f.replace("./", "")).sort();
96
+ projectNames.forEach((name, index) => {
97
+ const assignedPort = START_PORT + index;
98
+ servers.set(name, {
99
+ name,
100
+ assignedPort,
101
+ status: "starting",
102
+ order: index
103
+ });
104
+ projectToPort.set(name, assignedPort);
105
+ });
106
+ clearAndPrintServers();
496
107
  const filterArgs = resolvedFilters.map((f) => `--filter '${f}'`).join(" ");
497
- const projectNames = resolvedFilters.map((f) => f.replace("./", "")).join(", ");
498
- console.log(`${colors.dim}Starting dev servers: ${projectNames}${argsStr}${colors.reset}
499
- `);
108
+ projectNames.join(", ");
500
109
  const command = `bun run ${filterArgs} dev${argsStr}`;
501
110
  const proc = spawn(command, {
502
111
  cwd: process.cwd(),
@@ -509,15 +118,6 @@ async function runDev(filter, additionalArgs = []) {
509
118
  if (!line.trim()) return;
510
119
  if (seenLines.has(line)) return;
511
120
  seenLines.add(line);
512
- const projectMatch = line.match(/^(\w+)\s+dev:/);
513
- if (projectMatch) {
514
- const name = projectMatch[1];
515
- if (!servers.has(name)) {
516
- console.log(`${colors.dim}[DEBUG] Detected project: ${name}${colors.reset}`);
517
- servers.set(name, { name, status: "starting" });
518
- clearAndPrintServers();
519
- }
520
- }
521
121
  const portMatch = line.match(/Local:\s+http:\/\/localhost:(\d+)/);
522
122
  if (portMatch) {
523
123
  const port = Number.parseInt(portMatch[1], 10);
@@ -525,9 +125,8 @@ async function runDev(filter, additionalArgs = []) {
525
125
  if (projectInLine) {
526
126
  const name = projectInLine[1];
527
127
  const info = servers.get(name);
528
- console.log(`${colors.dim}[DEBUG] Port ${port} for project: ${name}, exists: ${!!info}, hasPort: ${info?.port}${colors.reset}`);
529
- if (info && !info.port) {
530
- info.port = port;
128
+ if (info && info.assignedPort === port && !info.actualPort) {
129
+ info.actualPort = port;
531
130
  info.status = "ready";
532
131
  clearAndPrintServers();
533
132
  }