backend-manager 5.0.132 → 5.0.134

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/CLAUDE.md CHANGED
@@ -467,16 +467,16 @@ npx bm test
467
467
  ```
468
468
 
469
469
  ### Log Files
470
- Both `npx bm emulator` and `npx bm test` automatically save all output to log files in the project directory while still streaming to the console:
471
- - **`emulator.log`** — Full emulator output (Firebase emulator + Cloud Functions logs)
472
- - **`test.log`** — Test runner output (when running against an existing emulator)
470
+ BEM CLI commands automatically save all output to log files in `functions/` while still streaming to the console:
471
+ - **`functions/serve.log`** — Output from `npx bm serve` (Firebase serve)
472
+ - **`functions/emulator.log`** — Full emulator output (Firebase emulator + Cloud Functions logs)
473
+ - **`functions/test.log`** — Test runner output (when running against an existing emulator)
474
+ - **`functions/logs.log`** — Cloud Function logs from `npx bm logs:read` or `npx bm logs:tail` (raw JSON for `read`, streaming text for `tail`)
473
475
 
474
476
  When `npx bm test` starts its own emulator, logs go to `emulator.log` (since it delegates to the emulator command). When running against an already-running emulator, logs go to `test.log`.
475
477
 
476
478
  These files are overwritten on each run and are gitignored (`*.log`). Use them to search for errors, debug webhook pipelines, or review full function output after a test run.
477
479
 
478
- - **`logs.log`** — Cloud Function logs from `npx bm logs:read` or `npx bm logs:tail` (raw JSON for `read`, streaming text for `tail`)
479
-
480
480
  ### Filtering Tests
481
481
  ```bash
482
482
  npx bm test rules/ # Run rules tests (both BEM and project)
@@ -630,7 +630,7 @@ npx bm logs:tail # Stream live logs
630
630
  npx bm logs:tail --fn bm_paymentsWebhookOnWrite # Stream filtered live logs
631
631
  ```
632
632
 
633
- Both commands save output to `logs.log` in the project directory (overwritten on each run). `logs:read` saves raw JSON; `logs:tail` streams text.
633
+ Both commands save output to `functions/logs.log` (overwritten on each run). `logs:read` saves raw JSON; `logs:tail` streams text.
634
634
 
635
635
  | Flag | Description | Default | Commands |
636
636
  |------|-------------|---------|----------|
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backend-manager",
3
- "version": "5.0.132",
3
+ "version": "5.0.134",
4
4
  "description": "Quick tools for developing Firebase functions",
5
5
  "main": "src/manager/index.js",
6
6
  "bin": {
@@ -18,11 +18,11 @@
18
18
  "node": "22"
19
19
  },
20
20
  "projectScripts": {
21
- "start": "npx bm setup && npx bm serve",
22
- "deploy": "npx bm setup && npx bm deploy",
23
- "emulator": "npx bm setup && npx bm emulator",
24
- "test": "npx bm setup && npx bm test",
25
- "setup": "npx bm setup"
21
+ "start": "npx mgr setup && npx mgr serve",
22
+ "deploy": "npx mgr setup && npx mgr deploy",
23
+ "emulator": "npx mgr setup && npx mgr emulator",
24
+ "test": "npx mgr setup && npx mgr test",
25
+ "setup": "npx mgr setup"
26
26
  },
27
27
  "repository": {
28
28
  "type": "git",
@@ -62,7 +62,7 @@ class EmulatorCommand extends BaseCommand {
62
62
  const emulatorCommand = `BEM_TESTING=true firebase emulators:exec --only functions,firestore,auth,database,hosting,pubsub --ui "${command}"`;
63
63
 
64
64
  // Set up log file in the project directory
65
- const logPath = path.join(projectDir, 'emulator.log');
65
+ const logPath = path.join(projectDir, 'functions', 'emulator.log');
66
66
  const logStream = fs.createWriteStream(logPath, { flags: 'w' });
67
67
  const stripAnsi = (str) => str.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '');
68
68
 
@@ -73,7 +73,7 @@ class LogsCommand extends BaseCommand {
73
73
 
74
74
  // Set up log file in the project directory
75
75
  const projectDir = this.main.firebaseProjectPath;
76
- const logPath = path.join(projectDir, 'logs.log');
76
+ const logPath = path.join(projectDir, 'functions', 'logs.log');
77
77
 
78
78
  this.log(chalk.gray(` Filter: ${filter || '(none)'}`));
79
79
  this.log(chalk.gray(` Limit: ${limit}`));
@@ -127,7 +127,7 @@ class LogsCommand extends BaseCommand {
127
127
 
128
128
  // Set up log file in the project directory
129
129
  const projectDir = this.main.firebaseProjectPath;
130
- const logPath = path.join(projectDir, 'logs.log');
130
+ const logPath = path.join(projectDir, 'functions', 'logs.log');
131
131
  const logStream = fs.createWriteStream(logPath, { flags: 'w' });
132
132
 
133
133
  const filter = this.buildFilter(argv, { excludeTimestamp: true });
@@ -1,4 +1,7 @@
1
1
  const BaseCommand = require('./base-command');
2
+ const path = require('path');
3
+ const fs = require('fs');
4
+ const chalk = require('chalk');
2
5
  const powertools = require('node-powertools');
3
6
  const WatchCommand = require('./watch');
4
7
 
@@ -6,6 +9,7 @@ class ServeCommand extends BaseCommand {
6
9
  async execute() {
7
10
  const self = this.main;
8
11
  const port = self.argv.port || self.argv?._?.[1] || '5000';
12
+ const projectDir = self.firebaseProjectPath;
9
13
 
10
14
  // Start BEM watcher in background
11
15
  const watcher = new WatchCommand(self);
@@ -14,8 +18,44 @@ class ServeCommand extends BaseCommand {
14
18
  // Start Stripe webhook forwarding in background
15
19
  this.startStripeWebhookForwarding();
16
20
 
17
- // Execute
18
- await powertools.execute(`firebase serve --port ${port}`, { log: true });
21
+ // Set up log file in the project directory
22
+ const logPath = path.join(projectDir, 'functions', 'serve.log');
23
+ const logStream = fs.createWriteStream(logPath, { flags: 'w' });
24
+ const stripAnsi = (str) => str.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '');
25
+
26
+ this.log(chalk.gray(` Logs saving to: ${logPath}\n`));
27
+
28
+ // Execute with tee to log file
29
+ try {
30
+ await powertools.execute(`firebase serve --port ${port}`, {
31
+ log: false,
32
+ cwd: projectDir,
33
+ config: {
34
+ stdio: ['inherit', 'pipe', 'pipe'],
35
+ env: { ...process.env, FORCE_COLOR: '1' },
36
+ },
37
+ }, (child) => {
38
+ // Tee stdout to both console and log file (strip ANSI codes for clean log)
39
+ child.stdout.on('data', (data) => {
40
+ process.stdout.write(data);
41
+ logStream.write(stripAnsi(data.toString()));
42
+ });
43
+
44
+ // Tee stderr to both console and log file (strip ANSI codes for clean log)
45
+ child.stderr.on('data', (data) => {
46
+ process.stderr.write(data);
47
+ logStream.write(stripAnsi(data.toString()));
48
+ });
49
+
50
+ // Clean up log stream when child exits
51
+ child.on('close', () => {
52
+ logStream.end();
53
+ });
54
+ });
55
+ } catch (error) {
56
+ // User pressed Ctrl+C - this is expected
57
+ this.log(chalk.gray('\n Server stopped.\n'));
58
+ }
19
59
  }
20
60
  }
21
61
 
@@ -2,17 +2,28 @@ const BaseTest = require('./base-test');
2
2
  const jetpack = require('fs-jetpack');
3
3
  const _ = require('lodash');
4
4
 
5
+ const ENABLED = false;
6
+
5
7
  class RemoteconfigTemplateInJsonTest extends BaseTest {
6
8
  getName() {
7
9
  return 'remoteconfig template in JSON';
8
10
  }
9
11
 
10
12
  async run() {
11
- return this.self.firebaseJSON?.remoteconfig?.template === 'remoteconfig.template.json';
13
+ if (ENABLED) {
14
+ return this.self.firebaseJSON?.remoteconfig?.template === 'remoteconfig.template.json';
15
+ }
16
+
17
+ return !this.self.firebaseJSON?.remoteconfig;
12
18
  }
13
19
 
14
20
  async fix() {
15
- _.set(this.self.firebaseJSON, 'remoteconfig.template', 'remoteconfig.template.json');
21
+ if (ENABLED) {
22
+ _.set(this.self.firebaseJSON, 'remoteconfig.template', 'remoteconfig.template.json');
23
+ } else {
24
+ delete this.self.firebaseJSON.remoteconfig;
25
+ }
26
+
16
27
  jetpack.write(`${this.self.firebaseProjectPath}/firebase.json`, JSON.stringify(this.self.firebaseJSON, null, 2));
17
28
  }
18
29
  }
@@ -185,7 +185,7 @@ class TestCommand extends BaseCommand {
185
185
  this.log(chalk.gray(` UI: http://127.0.0.1:${emulatorPorts.ui}`));
186
186
 
187
187
  // Set up log file in the project directory
188
- const logPath = path.join(projectDir, 'test.log');
188
+ const logPath = path.join(projectDir, 'functions', 'test.log');
189
189
  const logStream = fs.createWriteStream(logPath, { flags: 'w' });
190
190
  const stripAnsi = (str) => str.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '');
191
191
 
@@ -271,9 +271,6 @@ async function uploadPost(assistant, octokit, settings, content) {
271
271
  throw existing;
272
272
  }
273
273
 
274
- // Wait for GitHub to process images
275
- await powertools.wait(30000);
276
-
277
274
  // Upload post
278
275
  const result = await octokit.rest.repos.createOrUpdateFileContents({
279
276
  owner: owner,