meadow-integration 1.0.37 → 1.0.39

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.
@@ -27,7 +27,7 @@
27
27
  "ConnectionPoolLimit": 20
28
28
  }
29
29
  },
30
- "SchemaPath": "./schema/Model-Extended.json",
30
+ "SchemaPath": "",
31
31
  "Sync":
32
32
  {
33
33
  "DefaultSyncMode": "Initial",
@@ -1,5 +1,6 @@
1
1
  const libCLICommandLineCommand = require('pict-service-commandlineutility').ServiceCommandLineCommand;
2
2
 
3
+ const libFs = require('fs');
3
4
  const libPath = require('path');
4
5
 
5
6
  const libMeadowConnectionManager = require('../../services/clone/Meadow-Service-ConnectionManager.js');
@@ -7,6 +8,35 @@ const libMeadowCloneRestClient = require('../../services/clone/Meadow-Service-Re
7
8
  const libMeadowSync = require('../../services/clone/Meadow-Service-Sync.js');
8
9
  const libSessionManagerSetup = require('../../Meadow-Integration-SessionManagerSetup.js');
9
10
 
11
+ // Resolve an env var with the standard `_FILE` suffix fallback for
12
+ // secrets — so docker / k8s secret mounts work without bespoke wiring.
13
+ // Returns undefined when neither the var nor its `_FILE` companion is
14
+ // set; existing JSON-config + CLI-override layers then take effect
15
+ // unchanged.
16
+ function _envOrFile(pVarName)
17
+ {
18
+ let tmpValue = process.env[pVarName];
19
+ if (tmpValue !== undefined && tmpValue !== '')
20
+ {
21
+ return tmpValue;
22
+ }
23
+ let tmpFilePath = process.env[pVarName + '_FILE'];
24
+ if (tmpFilePath)
25
+ {
26
+ try
27
+ {
28
+ return libFs.readFileSync(tmpFilePath, 'utf8').replace(/\s+$/, '');
29
+ }
30
+ catch (pErr)
31
+ {
32
+ // Soft fail — fall through to undefined so the config-file
33
+ // layer (or CLI flag) still has a chance.
34
+ console.warn(`Meadow-Integration: ${pVarName}_FILE=${tmpFilePath} unreadable: ${pErr.message}`);
35
+ }
36
+ }
37
+ return undefined;
38
+ }
39
+
10
40
  class DataClone extends libCLICommandLineCommand
11
41
  {
12
42
  constructor(pFable, pOptions, pServiceHash)
@@ -23,13 +53,13 @@ class DataClone extends libCLICommandLineCommand
23
53
  this.options.CommandOptions.push({ Name: '-p, --api_password [api_password]', Description: 'The API password to authenticate with.' });
24
54
 
25
55
  this.options.CommandOptions.push({ Name: '-d, --db_provider [db_provider]', Description: 'The database provider (MySQL or MSSQL). Default is MySQL.', DefaultValue: 'MySQL' });
26
- this.options.CommandOptions.push({ Name: '-dh, --db_host [db_host]', Description: 'The database host address.' });
27
- this.options.CommandOptions.push({ Name: '-dp, --db_port [db_port]', Description: 'The database port.' });
28
- this.options.CommandOptions.push({ Name: '-du, --db_username [db_username]', Description: 'The database username.' });
29
- this.options.CommandOptions.push({ Name: '-dw, --db_password [db_password]', Description: 'The database password.' });
30
- this.options.CommandOptions.push({ Name: '-dn, --db_name [db_name]', Description: 'The database name.' });
56
+ this.options.CommandOptions.push({ Name: '--db_host [db_host]', Description: 'The database host address.' });
57
+ this.options.CommandOptions.push({ Name: '--db_port [db_port]', Description: 'The database port.' });
58
+ this.options.CommandOptions.push({ Name: '--db_username [db_username]', Description: 'The database username.' });
59
+ this.options.CommandOptions.push({ Name: '--db_password [db_password]', Description: 'The database password.' });
60
+ this.options.CommandOptions.push({ Name: '--db_name [db_name]', Description: 'The database name.' });
31
61
 
32
- this.options.CommandOptions.push({ Name: '-sp, --schema_path [schema_path]', Description: 'Path to the Meadow extended schema JSON file.' });
62
+ this.options.CommandOptions.push({ Name: '--schema_path [schema_path]', Description: 'Path to the Meadow extended schema JSON file.' });
33
63
 
34
64
  this.options.CommandOptions.push({ Name: '-s, --sync_mode [sync_mode]', Description: 'The sync mode: "Initial" or "Ongoing". Default is "Initial".', DefaultValue: 'Initial' });
35
65
 
@@ -42,6 +72,11 @@ class DataClone extends libCLICommandLineCommand
42
72
  {
43
73
  const tmpConfig = JSON.parse(JSON.stringify(this.fable.ProgramConfiguration));
44
74
 
75
+ // Layer 1: env vars (overlay on top of the config-file values).
76
+ // Layer 2 (CLI flags) below still wins — keeps the existing
77
+ // precedence intact for standalone CLI users.
78
+ this._applyEnvOverrides(tmpConfig);
79
+
45
80
  // Apply command-line overrides for Source (API)
46
81
  if (!tmpConfig.Source)
47
82
  {
@@ -106,6 +141,21 @@ class DataClone extends libCLICommandLineCommand
106
141
  tmpConfig.SchemaPath = this.CommandOptions.schema_path;
107
142
  }
108
143
 
144
+ // Final fallback: a bundled sample schema ships with the
145
+ // package at <pkg>/schema/default.json (BookStore reference
146
+ // model). Lets containerized launches succeed out of the box
147
+ // even when no SchemaPath is configured, so operators get a
148
+ // "yes it ran" smoke test before wiring their real schema.
149
+ if (!tmpConfig.SchemaPath)
150
+ {
151
+ let tmpBundled = libPath.resolve(__dirname, '..', '..', '..', 'schema', 'default.json');
152
+ if (libFs.existsSync(tmpBundled))
153
+ {
154
+ tmpConfig.SchemaPath = tmpBundled;
155
+ this.log.info(`No SchemaPath configured; falling back to bundled default at ${tmpBundled}`);
156
+ }
157
+ }
158
+
109
159
  // Sync config
110
160
  if (!tmpConfig.Sync)
111
161
  {
@@ -115,6 +165,52 @@ class DataClone extends libCLICommandLineCommand
115
165
  return tmpConfig;
116
166
  }
117
167
 
168
+ // Overlay MEADOW_INTEGRATION_* env vars onto the config object in
169
+ // place. Mutates pConfig; called between the config-file load and
170
+ // the CLI-override pass so the layering stays predictable
171
+ // (CLI > env > file > defaults). Honors the `_FILE` suffix on
172
+ // secret-bearing keys.
173
+ _applyEnvOverrides(pConfig)
174
+ {
175
+ // Source (API) ----------------------------------------------
176
+ let tmpApiServer = _envOrFile('MEADOW_INTEGRATION_API_SERVER');
177
+ let tmpApiUser = _envOrFile('MEADOW_INTEGRATION_API_USERNAME');
178
+ let tmpApiPass = _envOrFile('MEADOW_INTEGRATION_API_PASSWORD');
179
+ if (tmpApiServer || tmpApiUser || tmpApiPass)
180
+ {
181
+ if (!pConfig.Source) { pConfig.Source = {}; }
182
+ if (tmpApiServer) { pConfig.Source.ServerURL = tmpApiServer; }
183
+ if (tmpApiUser) { pConfig.Source.UserID = tmpApiUser; }
184
+ if (tmpApiPass) { pConfig.Source.Password = tmpApiPass; }
185
+ }
186
+
187
+ // Destination (Database) ------------------------------------
188
+ let tmpDbProvider = _envOrFile('MEADOW_INTEGRATION_DB_PROVIDER');
189
+ let tmpDbHost = _envOrFile('MEADOW_INTEGRATION_DB_HOST');
190
+ let tmpDbPort = _envOrFile('MEADOW_INTEGRATION_DB_PORT');
191
+ let tmpDbUser = _envOrFile('MEADOW_INTEGRATION_DB_USERNAME');
192
+ let tmpDbPass = _envOrFile('MEADOW_INTEGRATION_DB_PASSWORD');
193
+ let tmpDbName = _envOrFile('MEADOW_INTEGRATION_DB_NAME');
194
+ let tmpHasDb = tmpDbProvider || tmpDbHost || tmpDbPort || tmpDbUser || tmpDbPass || tmpDbName;
195
+ if (tmpHasDb)
196
+ {
197
+ if (!pConfig.Destination) { pConfig.Destination = {}; }
198
+ if (tmpDbProvider) { pConfig.Destination.Provider = tmpDbProvider; }
199
+ let tmpProviderKey = pConfig.Destination.Provider || 'MySQL';
200
+ if (!pConfig.Destination[tmpProviderKey]) { pConfig.Destination[tmpProviderKey] = {}; }
201
+ let tmpProviderCfg = pConfig.Destination[tmpProviderKey];
202
+ if (tmpDbHost) { tmpProviderCfg.server = tmpDbHost; }
203
+ if (tmpDbPort) { tmpProviderCfg.port = parseInt(tmpDbPort, 10); }
204
+ if (tmpDbUser) { tmpProviderCfg.user = tmpDbUser; }
205
+ if (tmpDbPass) { tmpProviderCfg.password = tmpDbPass; }
206
+ if (tmpDbName) { tmpProviderCfg.database = tmpDbName; }
207
+ }
208
+
209
+ // Schema path -----------------------------------------------
210
+ let tmpSchemaPath = _envOrFile('MEADOW_INTEGRATION_SCHEMA_PATH');
211
+ if (tmpSchemaPath) { pConfig.SchemaPath = tmpSchemaPath; }
212
+ }
213
+
118
214
  onRunAsync(fCallback)
119
215
  {
120
216
  const tmpConfig = this._resolveConfig();