@tapestry-mud/cli 0.3.10 → 0.3.11

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tapestry-mud/cli",
3
- "version": "0.3.10",
3
+ "version": "0.3.11",
4
4
  "description": "CLI for the Tapestry MUD engine",
5
5
  "bin": {
6
6
  "tapestry": "./bin/tapestry.js"
@@ -28,7 +28,7 @@ function buildManifest(name, deps, engineVersion, engineChannel) {
28
28
  ].join('\n');
29
29
  }
30
30
 
31
- function buildServerYaml({ serverName, adminHandle, adminPassword, telemetry }) {
31
+ function buildServerYaml({ serverName, adminHandle, adminEmail, adminPassword, telemetry }) {
32
32
  const telemetryBlock = telemetry
33
33
  ? [
34
34
  `telemetry:`,
@@ -59,6 +59,7 @@ function buildServerYaml({ serverName, adminHandle, adminPassword, telemetry })
59
59
  ``,
60
60
  `admin:`,
61
61
  ` handle: ${adminHandle}`,
62
+ ` email: ${adminEmail}`,
62
63
  ` password: ${adminPassword}`,
63
64
  ``,
64
65
  `# --- Telemetry (OpenTelemetry) ---`,
@@ -105,6 +106,15 @@ function buildServerYaml({ serverName, adminHandle, adminPassword, telemetry })
105
106
  `# pre_auth:`,
106
107
  `# enabled: false`,
107
108
  `# token_expiry_seconds: 60`,
109
+ ``,
110
+ `# --- Accounts ---`,
111
+ `# accounts:`,
112
+ `# max_concurrent_characters: 1`,
113
+ ``,
114
+ `# --- Link-Dead (player disconnect grace period) ---`,
115
+ `# link_dead:`,
116
+ `# enabled: true`,
117
+ `# timeout_seconds: 120`,
108
118
  ].join('\n');
109
119
  }
110
120
 
@@ -157,6 +167,7 @@ async function init(cwd, { registryUrl = DEFAULT_REGISTRY, yes = false, prompter
157
167
  answers = {
158
168
  gameName: dirName,
159
169
  adminHandle: 'admin',
170
+ adminEmail: 'admin@localhost',
160
171
  adminPassword: 'changeme',
161
172
  telemetry: false,
162
173
  };
@@ -177,6 +188,17 @@ async function init(cwd, { registryUrl = DEFAULT_REGISTRY, yes = false, prompter
177
188
  message: 'Admin handle:',
178
189
  validate: (v) => (v.trim().length > 0 && !/\s/.test(v)) || 'Required, no spaces',
179
190
  },
191
+ {
192
+ type: 'input',
193
+ name: 'adminEmail',
194
+ message: 'Admin email:',
195
+ validate: (v) => {
196
+ v = v.trim();
197
+ if (!v) { return 'Required'; }
198
+ if (!v.includes('@') || !v.includes('.')) { return 'Must be a valid email'; }
199
+ return true;
200
+ },
201
+ },
180
202
  {
181
203
  type: 'password',
182
204
  name: 'adminPassword',
@@ -208,6 +230,7 @@ async function init(cwd, { registryUrl = DEFAULT_REGISTRY, yes = false, prompter
208
230
  buildServerYaml({
209
231
  serverName: answers.gameName,
210
232
  adminHandle: answers.adminHandle,
233
+ adminEmail: answers.adminEmail,
211
234
  adminPassword: answers.adminPassword,
212
235
  telemetry: answers.telemetry,
213
236
  })
@@ -5,7 +5,7 @@ const os = require('os');
5
5
  const path = require('path');
6
6
  const { readYaml, writeYaml } = require('../util/yaml');
7
7
  const { resolve } = require('../lib/semver-resolver');
8
- const { readLock, writeLock } = require('../lib/lock-file');
8
+ const { readLock, writeLock, hashDeps } = require('../lib/lock-file');
9
9
  const { fetchTarball, DEFAULT_REGISTRY } = require('../lib/registry-client');
10
10
  const { verifyIntegrity, saveTarball, extractTarball } = require('../lib/tarball');
11
11
  const { addPackageToBoot } = require('../lib/boot');
@@ -25,6 +25,9 @@ function parsePackageArg(arg) {
25
25
  }
26
26
 
27
27
  function isLockCurrent(manifestDeps, lock) {
28
+ if (!lock.deps_hash || lock.deps_hash !== hashDeps(manifestDeps)) {
29
+ return false;
30
+ }
28
31
  const lockResolved = lock.resolved || {};
29
32
  return Object.keys(manifestDeps).every((name) => lockResolved[name]);
30
33
  }
@@ -34,8 +37,18 @@ async function installResolved(cwd, resolved, token) {
34
37
  const destDir = packInstallPath(cwd, packageName);
35
38
 
36
39
  if (fs.existsSync(destDir)) {
37
- console.log(` already installed ${packageName}@${info.version}`);
38
- continue;
40
+ const installedManifestPath = path.join(destDir, 'tapestry.yaml');
41
+ if (fs.existsSync(installedManifestPath)) {
42
+ const installed = readYaml(installedManifestPath);
43
+ if (installed.version === info.version) {
44
+ console.log(` already installed ${packageName}@${info.version}`);
45
+ continue;
46
+ }
47
+ console.log(` upgrading ${packageName} ${installed.version} -> ${info.version}`);
48
+ } else {
49
+ console.log(` reinstalling ${packageName}@${info.version} (missing manifest)`);
50
+ }
51
+ fs.rmSync(destDir, { recursive: true });
39
52
  }
40
53
 
41
54
  console.log(` installing ${packageName}@${info.version}`);
@@ -95,7 +108,8 @@ async function install(packageArg, { cwd = process.cwd(), registryUrl = DEFAULT_
95
108
  }
96
109
 
97
110
  await installResolved(cwd, resolved, token);
98
- writeLock(cwd, { lockfile_version: 1, resolved });
111
+ const deps = manifest.dependencies || {};
112
+ writeLock(cwd, { lockfile_version: 1, deps_hash: hashDeps(deps), resolved });
99
113
  console.log('Done.');
100
114
  }
101
115
 
@@ -1,11 +1,17 @@
1
1
  'use strict';
2
2
 
3
+ const crypto = require('crypto');
3
4
  const fs = require('fs');
4
5
  const path = require('path');
5
6
  const { readYaml, writeYaml } = require('../util/yaml');
6
7
 
7
8
  const LOCK_FILE = 'tapestry-lock.yaml';
8
9
 
10
+ function hashDeps(deps) {
11
+ const sorted = Object.keys(deps).sort().map((k) => `${k}@${deps[k]}`).join('\n');
12
+ return crypto.createHash('sha256').update(sorted).digest('hex');
13
+ }
14
+
9
15
  function readLock(cwd) {
10
16
  const lockPath = path.join(cwd, LOCK_FILE);
11
17
  if (!fs.existsSync(lockPath)) {
@@ -18,4 +24,4 @@ function writeLock(cwd, lock) {
18
24
  writeYaml(path.join(cwd, LOCK_FILE), lock);
19
25
  }
20
26
 
21
- module.exports = { readLock, writeLock };
27
+ module.exports = { readLock, writeLock, hashDeps };