@13w/miri 1.1.12 → 1.1.15

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/cli.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { readFileSync, realpathSync } from 'node:fs';
1
2
  import { readFile } from 'node:fs/promises';
2
3
  Error.stackTraceLimit = Infinity;
3
4
  import { join } from 'node:path';
@@ -9,11 +10,47 @@ import { createTunnel } from 'tunnel-ssh';
9
10
  import SSHConfig from 'ssh-config';
10
11
  import connection from './mongodb.js';
11
12
  import Miri, { IndexStatus, PatchStatus } from './miri.js';
12
- import { readFileSync } from 'fs';
13
- import { realpathSync } from 'node:fs';
14
13
  const pkg = await readFile(join(import.meta.dirname, '../package.json'), 'utf-8').then((content) => JSON.parse(content));
15
14
  const mirirc = await readFile(join(process.cwd(), '.mirirc'), 'utf-8').then((content) => JSON.parse(content), () => ({}));
16
15
  const { SSH_AUTH_SOCK, HOME } = process.env;
16
+ const askPassword = async (message = 'Password: ') => {
17
+ process.stdin.resume();
18
+ process.stdin.setEncoding('utf8');
19
+ process.stdin.setRawMode(true);
20
+ return new Promise((resolve, reject) => {
21
+ let password = '';
22
+ const readPass = function (chunk) {
23
+ const str = chunk.toString();
24
+ // backspace
25
+ if (str.charCodeAt(0) === 127) {
26
+ password = password.slice(0, -1);
27
+ return;
28
+ }
29
+ switch (str) {
30
+ case '\n':
31
+ case '\r':
32
+ case '\u0004':
33
+ // They've finished typing their password
34
+ process.stdin.setRawMode(false);
35
+ process.stdin.pause();
36
+ process.stdout.write('\n');
37
+ process.stdin.off('data', readPass);
38
+ resolve(password);
39
+ return;
40
+ case '\u0003':
41
+ // Ctrl C
42
+ process.stdin.off('data', readPass);
43
+ reject(new Error('Cancelled'));
44
+ default:
45
+ // More passsword characters
46
+ password += str;
47
+ break;
48
+ }
49
+ };
50
+ process.stdout.write(message);
51
+ process.stdin.on('data', readPass);
52
+ });
53
+ };
17
54
  const program = new Command();
18
55
  program.version(pkg.version);
19
56
  program.option('-e --env <environment>', 'Environment name from .mirirc', 'default');
@@ -24,6 +61,7 @@ program.option('--ssh-host <host>', 'Connect via SSH proxy Host');
24
61
  program.option('--ssh-port <port>', 'Connect via SSH proxy Port');
25
62
  program.option('--ssh-user <user>', 'Connect via SSH proxy User');
26
63
  program.option('--ssh-key <path/to/key>', 'Connect via SSH proxy IdentityKey');
64
+ program.option('--ssh-ask-pass', 'Ask for the private key password', false);
27
65
  let configCache;
28
66
  const getConfig = (programOpts) => {
29
67
  if (configCache) {
@@ -42,18 +80,23 @@ const getConfig = (programOpts) => {
42
80
  config.sshKey = programOpts.sshKey ?? parsed.IdentityFile?.[0];
43
81
  config.sshUser = programOpts.sshUser ?? parsed.User;
44
82
  }
45
- // console.dir(config)
46
83
  return configCache = config;
47
84
  };
48
85
  const createSSHTunnel = async (opts) => {
49
86
  const config = getConfig(opts);
87
+ let passphrase = '';
88
+ if (config.sshKey && config.sshAskPass) {
89
+ passphrase = await askPassword();
90
+ }
50
91
  const sshOptions = {
51
92
  host: config.sshHost,
52
93
  port: Number(config.sshPort ?? 22),
53
94
  username: config.sshUser,
54
- agent: SSH_AUTH_SOCK,
95
+ // agent: SSH_AUTH_SOCK,
55
96
  privateKey: config.sshKey ? readFileSync(realpathSync(config.sshKey)) : void 0,
97
+ passphrase,
56
98
  };
99
+ console.dir([config, sshOptions]);
57
100
  const dst = new URL(config.db);
58
101
  const forwardOptions = {
59
102
  dstPort: Number(dst.port ?? 27017),
@@ -152,11 +195,19 @@ initProgram.command('apply')
152
195
  .argument('[patch]', 'patch name')
153
196
  .option('--no-exec', 'Don\' execute patch, just set as done')
154
197
  .option('--force', 'Force apply patch')
155
- .action(async (opts, patch) => {
198
+ .action(async (patch, opts) => {
156
199
  const miri = await getMiri();
157
200
  await miri.init(opts, patch);
158
201
  await miri[Symbol.asyncDispose]();
159
202
  });
203
+ initProgram.command('remove')
204
+ .argument('<patch>', 'patch name')
205
+ .option('--no-exec', 'Don\' execute patch, just set as done')
206
+ .action(async (patch, opts) => {
207
+ const miri = await getMiri();
208
+ await miri.remove('init', patch, Boolean(opts?.exec));
209
+ await miri[Symbol.asyncDispose]();
210
+ });
160
211
  initProgram.command('status')
161
212
  .action(() => status(false, 'init'));
162
213
  const indexesProgram = program.command('indexes')
@@ -215,5 +266,23 @@ patchProgram.command('sync')
215
266
  await miri.sync(opts);
216
267
  await miri[Symbol.asyncDispose]();
217
268
  });
269
+ patchProgram.command('apply')
270
+ .argument('<group>', 'group name')
271
+ .argument('<patch>', 'patch name')
272
+ .option('--no-exec', 'Don\' execute patch, just set as done')
273
+ .action(async (group, patch, opts) => {
274
+ const miri = await getMiri();
275
+ await miri.applySingle(group, patch, Boolean(opts.exec));
276
+ await miri[Symbol.asyncDispose]();
277
+ });
278
+ patchProgram.command('remove')
279
+ .argument('<group>', 'group name')
280
+ .argument('<patch>', 'patch name')
281
+ .option('--no-exec', 'Don\' execute patch, just set as done')
282
+ .action(async (group, patch, opts) => {
283
+ const miri = await getMiri();
284
+ await miri.remove(group, patch, Boolean(opts.exec));
285
+ await miri[Symbol.asyncDispose]();
286
+ });
218
287
  program.parse();
219
288
  //# sourceMappingURL=cli.js.map
package/dist/evaluator.js CHANGED
@@ -12,7 +12,7 @@ const print = (values, type) => {
12
12
  return String(object);
13
13
  }
14
14
  else {
15
- return inspect(object, { colors: true, customInspect: true, depth: 22 });
15
+ return inspect(object, { colors: false, customInspect: true, depth: 22 });
16
16
  }
17
17
  };
18
18
  for (const value of values) {
package/dist/miri.js CHANGED
@@ -276,7 +276,7 @@ export default class Migrator {
276
276
  }
277
277
  }
278
278
  }
279
- async init({ noExec = false, force = false } = {}, patch) {
279
+ async init({ exec = false, force = false } = {}, patch) {
280
280
  const localInits = await this.getLocalPatches(true, 'init', patch);
281
281
  const remoteInits = await this.getRemotePatches('init', patch);
282
282
  if (!localInits.length) {
@@ -292,7 +292,7 @@ export default class Migrator {
292
292
  console.groupEnd();
293
293
  continue;
294
294
  }
295
- if (force || !noExec) {
295
+ if (force || exec) {
296
296
  console.log('applying');
297
297
  await this.applyPatchContent({ body: patch.raw, hash: '' }, `${patch.group}/${patch.name}`, false);
298
298
  }
@@ -322,5 +322,51 @@ export default class Migrator {
322
322
  }
323
323
  return patches;
324
324
  }
325
+ async applySingle(group, name, exec = false) {
326
+ const [local] = await this.getLocalPatches(false, group, name);
327
+ const [remote] = await this.getRemotePatches(group, name);
328
+ if (!local) {
329
+ console.group(`Patch ${group}/${name} not found.`);
330
+ return;
331
+ }
332
+ console.group('Patch found');
333
+ if (exec && local.content.up) {
334
+ console.group(colors.cyan('applying migration...'));
335
+ await this.applyPatchContent(local.content.up, `${local.group}/${local.name}`);
336
+ console.log(colors.green('done'));
337
+ console.groupEnd();
338
+ }
339
+ else {
340
+ console.log('set as done');
341
+ }
342
+ const _id = remote?._id ?? local._id;
343
+ await this.#collection.updateOne({ _id }, {
344
+ $set: {
345
+ _id,
346
+ group: local.group,
347
+ name: local.name,
348
+ content: local.content,
349
+ },
350
+ }, { upsert: true });
351
+ console.groupEnd();
352
+ }
353
+ async remove(group, name, exec = false) {
354
+ const [patch] = await this.getRemotePatches(group, name);
355
+ if (!patch) {
356
+ console.group(`Patch ${group}/${name} not found.`);
357
+ return;
358
+ }
359
+ console.group('Patch found, start removing');
360
+ if (exec && patch.content.down) {
361
+ console.group('De-applying patch...');
362
+ await this.applyPatchContent(patch.content.down, `${patch.group}/${patch.name}`);
363
+ console.log('done');
364
+ console.groupEnd();
365
+ }
366
+ console.group('Removing patch from database');
367
+ await this.#collection.deleteOne({ group, name });
368
+ console.log('done');
369
+ console.groupEnd();
370
+ }
325
371
  }
326
372
  //# sourceMappingURL=miri.js.map
package/package.json CHANGED
@@ -1,12 +1,17 @@
1
1
  {
2
2
  "name": "@13w/miri",
3
3
  "description": "MongoDB patch manager",
4
- "version": "1.1.12",
4
+ "version": "1.1.15",
5
5
  "type": "module",
6
6
  "engines": {
7
7
  "node": "v20"
8
8
  },
9
- "packageManager": "^pnpm@8.15.4",
9
+ "keywords": [
10
+ "MongoDB",
11
+ "patch",
12
+ "migration",
13
+ "ssh"
14
+ ],
10
15
  "bin": {
11
16
  "miri": "bin/miri"
12
17
  },
@@ -19,30 +24,30 @@
19
24
  ],
20
25
  "main": "bin/miri",
21
26
  "types": "types/miri.d.ts",
27
+ "scripts": {
28
+ "build": "tsc -p tsconfig.json",
29
+ "lint": "eslint src/ --ext .ts --quiet",
30
+ "prepublish": "pnpm run build"
31
+ },
22
32
  "dependencies": {
23
- "@mongosh/service-provider-server": "^2.1.5",
24
- "@mongosh/shell-api": "^2.1.5",
25
- "@mongosh/shell-evaluator": "^2.1.5",
33
+ "@mongosh/service-provider-server": "^2.2.12",
34
+ "@mongosh/shell-api": "^2.2.12",
35
+ "@mongosh/shell-evaluator": "^2.2.12",
26
36
  "colors": "^1.4.0",
27
- "commander": "^12.0.0",
28
- "console-table-printer": "^2.12.0",
29
- "mongodb": "^6.5.0",
30
- "ssh-config": "^4.4.2",
37
+ "commander": "^12.1.0",
38
+ "console-table-printer": "^2.12.1",
39
+ "mongodb": "^6.8.0",
40
+ "ssh-config": "^4.4.4",
31
41
  "tunnel-ssh": "^5.1.2"
32
42
  },
33
43
  "devDependencies": {
34
- "@types/node": "^20.11.27",
35
- "@typescript-eslint/eslint-plugin": "^7.2.0",
36
- "@typescript-eslint/parser": "^7.2.0",
44
+ "@types/node": "^20.14.12",
45
+ "@typescript-eslint/eslint-plugin": "^7.17.0",
46
+ "@typescript-eslint/parser": "^7.17.0",
37
47
  "eslint": "^8.57.0",
38
48
  "eslint-plugin-deprecation": "^2.0.0",
39
49
  "ts-node": "^10.9.2",
40
- "typescript": "^5.4.2"
50
+ "typescript": "^5.5.4"
41
51
  },
42
- "license": "MIT",
43
- "scripts": {
44
- "build": "tsc -p tsconfig.json",
45
- "lint": "eslint src/ --ext .ts --quiet",
46
- "prepublish": "pnpm run build"
47
- }
48
- }
52
+ "license": "MIT"
53
+ }