@imenam/simple-scraper 1.0.18 → 1.0.19

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/README.md CHANGED
@@ -90,6 +90,23 @@ PUPPETEER_DEVICE_SCALE_FACTOR=1
90
90
  # APP_GROUP=Scraping
91
91
  ```
92
92
 
93
+ ### The process environment wins over `.env`
94
+
95
+ Any variable already set in the environment of the process that starts this MCP
96
+ (a shell `export`, a `claude_desktop_config.json` `env` block, or a supervisor
97
+ such as `@imenam/mcp-gateway-manager`) **takes precedence over the same key in
98
+ this repository's `.env`**. This is dotenv's default behaviour, and the usual
99
+ Unix convention: the caller wins.
100
+
101
+ The `.env` is still reloaded on the fly — the GUI writes to it and the change is
102
+ picked up without restarting the server — but that reload can no longer clobber
103
+ what the caller injected. Concretely, an `APP_GROUP=Scraping` line in this
104
+ `.env` no longer overrides an `APP_GROUP` passed in by a supervisor; it only
105
+ applies when nobody passed one.
106
+
107
+ To change a variable that the caller provides, change it where the caller sets
108
+ it; editing `.env` will have no effect on that key.
109
+
93
110
  ## Usage with Claude Desktop
94
111
 
95
112
  Add the following to your `claude_desktop_config.json`. Full example with all available options:
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Chargement du `.env` du dépôt, sans jamais écraser l'environnement du process.
3
+ *
4
+ * ## Le problème
5
+ *
6
+ * Ce MCP rechargeait son `.env` avec `dotenv.config({ override: true })`, au
7
+ * démarrage et à chaque `reloadEnv` du `GuiLauncher`. C'est délibéré : la GUI
8
+ * écrit dans le `.env` et le code relit la valeur sans redémarrer le process.
9
+ * Sans `override`, dotenv ignore toute clé déjà présente dans `process.env` —
10
+ * donc la deuxième lecture ne verrait jamais rien changer.
11
+ *
12
+ * Mais `override: true` écrase **aussi** ce qu'un superviseur a injecté. Quand
13
+ * le hub `mcp-gateway-manager` lance ce MCP en lui passant `APP_GROUP`,
14
+ * `PROXY_URL` ou `APP_PATH_PREFIX` dans son bloc `env`, le `.env` du dépôt
15
+ * reprenait la main et l'injection échouait **silencieusement**.
16
+ *
17
+ * ## La règle appliquée ici
18
+ *
19
+ * Une variable **déjà présente dans l'environnement du process au démarrage**
20
+ * l'emporte sur le `.env` du dépôt — c'est le comportement par défaut de dotenv,
21
+ * et la convention de tout l'écosystème Unix : l'appelant gagne.
22
+ *
23
+ * L'`override` n'est pas supprimé pour autant, il est **restreint** : il reste
24
+ * entier pour toutes les variables que le process n'a pas héritées, c'est-à-dire
25
+ * exactement celles que l'interface graphique édite dans le `.env`. On ne perd
26
+ * donc pas le rechargement à chaud, on l'empêche seulement de piétiner
27
+ * l'appelant.
28
+ *
29
+ * L'instantané est pris à l'évaluation de ce module : il doit donc être importé
30
+ * avant tout appel à `dotenv.config`.
31
+ */
32
+ import dotenv from 'dotenv';
33
+ /** Environnement du process **avant** tout chargement de `.env`. */
34
+ const inherited = Object.freeze(Object.fromEntries(Object.entries(process.env).filter((entry) => typeof entry[1] === 'string')));
35
+ /** La variable vient-elle de l'appelant (superviseur, shell) plutôt que du `.env` ? */
36
+ export function isInheritedFromProcess(key) {
37
+ return Object.prototype.hasOwnProperty.call(inherited, key);
38
+ }
39
+ /**
40
+ * Charge un fichier `.env` en écrasant les valeurs déjà lues depuis ce fichier,
41
+ * mais **jamais** celles héritées de l'environnement du process.
42
+ */
43
+ export function loadEnvFile(options) {
44
+ // Le résultat peut être absent quand dotenv est remplacé par un test double.
45
+ const result = dotenv.config({ ...options, override: true });
46
+ for (const key of Object.keys(result?.parsed ?? {})) {
47
+ const value = inherited[key];
48
+ if (value !== undefined)
49
+ process.env[key] = value;
50
+ }
51
+ }
package/dist/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
3
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
- import dotenv from 'dotenv';
4
+ // Importé AVANT tout appel à dotenv : ce module prend l'instantané de
5
+ // l'environnement hérité du process, qui doit primer sur le `.env` du dépôt.
6
+ import { loadEnvFile } from './env-precedence.js';
5
7
  import fs from 'fs';
6
8
  import path from 'path';
7
9
  import { fileURLToPath } from 'url';
@@ -21,11 +23,14 @@ if (process.argv.slice(2).includes('--claude-setup-mcp')) {
21
23
  const { runSetupMcp } = await import('./cli/setup-mcp.js');
22
24
  process.exit(runSetupMcp({ cwd: process.cwd(), force: process.argv.slice(2).includes('--force') }));
23
25
  }
24
- dotenv.config({ path: envPath, override: true });
26
+ // `override` restreint : la GUI peut toujours éditer le `.env` et voir l'effet
27
+ // sans redémarrage, mais une variable injectée par un superviseur (`PROXY_URL`,
28
+ // `APP_GROUP`, `APP_PATH_PREFIX`…) reste intacte. Voir ./env-precedence.ts.
29
+ loadEnvFile({ path: envPath });
25
30
  setupLogging('MASTER');
26
31
  const launcher = new GuiLauncher({
27
32
  guiPath: path.join(__dirname, 'gui.js'),
28
- reloadEnv: () => dotenv.config({ path: envPath, override: true }),
33
+ reloadEnv: () => loadEnvFile({ path: envPath }),
29
34
  onMessage: (msg) => {
30
35
  if (msg.type === 'STOP') {
31
36
  process.exit(0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imenam/simple-scraper",
3
- "version": "1.0.18",
3
+ "version": "1.0.19",
4
4
  "description": "MCP server for web scraping and JavaScript execution using Puppeteer",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",