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