Browse Source

Fix class skill names, add targeting modes, music autostart, WASD auto-enable

- Fix class skill names: Game now reads from class_skills table (what admin edits) instead of legacy class_skill_names table
- Add per-hit targeting mode for multi-hit skills (configurable in admin)
- Music now attempts autostart on page load
- WASD keyboard controls auto-enable test mode (like on-screen buttons)
- Update CLAUDE.md with Docker restart vs rebuild documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
master
HikeMap User 1 month ago
parent
commit
b94737f3c6
  1. 72
      CLAUDE.md
  2. 49
      admin.html
  3. 47
      database.js
  4. 798
      index.html
  5. 602
      package-lock.json
  6. 44
      server.js
  7. 2
      service-worker.js

72
CLAUDE.md

@ -271,3 +271,75 @@ useSkill(skillId) // Execute skill in combat
1. Insert into `monster_types` via admin panel or database 1. Insert into `monster_types` via admin panel or database
2. Set level range, stats, dialogues 2. Set level range, stats, dialogues
3. Optionally add to `monster_skills` for special abilities 3. Optionally add to `monster_skills` for special abilities
---
## Troubleshooting
### Docker: Restart vs Rebuild
Most source files are **volume-mounted** in `docker-compose.yml`, so changes are reflected without rebuilding.
**Action required by file type:**
| File | Action | Notes |
|------|--------|-------|
| `index.html` | Browser refresh | Volume-mounted, served fresh |
| `admin.html` | Browser refresh | Volume-mounted, served fresh |
| `service-worker.js` | Browser refresh + bump cache version | Volume-mounted |
| `server.js` | `docker restart hikemap_hikemap_1` | Volume-mounted, Node needs restart |
| `database.js` | `docker restart hikemap_hikemap_1` | Volume-mounted, Node needs restart |
| `mapgameimgs/*` | Browser refresh | Volume-mounted |
| `mapgamemusic/*` | Browser refresh | Volume-mounted |
| `sfx/*` | Browser refresh | Volume-mounted |
| `hikemap.db` | Nothing | Volume-mounted, persists outside container |
**Files requiring full rebuild** (`docker-compose up -d --build`):
| File | Why Rebuild? |
|------|--------------|
| `package.json` | New npm dependencies need installing |
| `Dockerfile` | Build process changes |
| `manifest.json` | Not volume-mounted |
| `icon-*.png` | Not volume-mounted |
| `.env` | Not volume-mounted |
| `.well-known/*` | Not volume-mounted |
| `default.kml` | Not volume-mounted |
| `docker-compose.yml` | Container config changes |
**Commands:**
```bash
# Restart container (fast - for server.js/database.js changes)
docker restart hikemap_hikemap_1
# Full rebuild (slow - only when needed)
docker-compose up -d --build
# If rebuild fails with volume errors:
docker ps -a | grep hike # Find container ID
docker rm <container_id>
docker-compose up -d --build
```
### Cache Issues
After server-side changes, users may need to clear browser cache:
1. Increment `CACHE_NAME` version in `service-worker.js`
2. Hard refresh in browser (Ctrl+Shift+R)
3. Or clear site data in browser DevTools
### Common Issues
**"Changes not appearing after edit"**
- Client files (html/js): Just refresh browser
- Server files (server.js, database.js): Run `docker restart hikemap_hikemap_1`
- Did you bump the service worker cache version?
**"API returns old data"**
- Check container is running: `docker ps | grep hike`
- Restart container: `docker restart hikemap_hikemap_1`
- Check container logs: `docker logs hikemap_hikemap_1`
**"Database changes lost after rebuild"**
- The `hikemap.db` file is mounted as a volume and persists
- Schema changes are applied via migrations in `database.js` on startup

49
admin.html

@ -936,6 +936,18 @@
<small style="color: #888; font-size: 11px;">Warning shown this many seconds before logout</small> <small style="color: #888; font-size: 11px;">Warning shown this many seconds before logout</small>
</div> </div>
</div> </div>
<h3 style="margin: 20px 0 10px; color: #666; font-size: 14px;">Combat UI Settings</h3>
<div class="form-row">
<div class="form-group">
<label>Combat Monster Icon Scale (Mobile)</label>
<input type="number" id="setting-combatIconScale" placeholder="0.7" min="0.3" max="1.5" step="0.1">
<small style="color: #888; font-size: 11px;">Scale for monster icons on mobile only (0.3 = 30px, 0.7 = 70px, 1.0 = 100px). Desktop always uses 100px.</small>
</div>
<div class="form-group">
<!-- empty for alignment -->
</div>
</div>
</div> </div>
<div class="form-actions"> <div class="form-actions">
<button class="btn btn-primary" id="saveSettingsBtn">Save Settings</button> <button class="btn btn-primary" id="saveSettingsBtn">Save Settings</button>
@ -1185,6 +1197,17 @@
<input type="number" id="skillHitCount" value="1" min="1"> <input type="number" id="skillHitCount" value="1" min="1">
</div> </div>
</div> </div>
<div class="form-row-2" id="targetingModeRow">
<div class="form-group">
<label>Targeting Mode (Multi-Hit)</label>
<select id="skillTargetingMode">
<option value="same_target">Same Target (all hits on selected enemy)</option>
<option value="per_hit">Per-Hit Selection (player chooses each hit)</option>
<option value="random">Random (each hit targets random enemy)</option>
</select>
<small style="color: #666; font-size: 11px;">Only applies when Hit Count > 1 and multiple enemies present</small>
</div>
</div>
<div class="status-effect-section"> <div class="status-effect-section">
<h4>Status Effect (optional)</h4> <h4>Status Effect (optional)</h4>
@ -2045,6 +2068,7 @@
document.getElementById('skillDescription').value = skill.description || ''; document.getElementById('skillDescription').value = skill.description || '';
document.getElementById('skillType').value = skill.type; document.getElementById('skillType').value = skill.type;
document.getElementById('skillTarget').value = skill.target; document.getElementById('skillTarget').value = skill.target;
document.getElementById('skillTargetingMode').value = skill.targeting_mode || 'same_target';
document.getElementById('skillMpCost').value = skill.mp_cost; document.getElementById('skillMpCost').value = skill.mp_cost;
document.getElementById('skillBasePower').value = skill.base_power; document.getElementById('skillBasePower').value = skill.base_power;
document.getElementById('skillAccuracy').value = skill.accuracy; document.getElementById('skillAccuracy').value = skill.accuracy;
@ -2105,6 +2129,7 @@
document.getElementById('skillPlayerUsable').checked = true; document.getElementById('skillPlayerUsable').checked = true;
document.getElementById('skillMonsterUsable').checked = true; document.getElementById('skillMonsterUsable').checked = true;
document.getElementById('skillEnabled').checked = true; document.getElementById('skillEnabled').checked = true;
document.getElementById('skillTargetingMode').value = 'same_target';
// Reset to default (damage) type and toggle visibility // Reset to default (damage) type and toggle visibility
document.getElementById('skillType').value = 'damage'; document.getElementById('skillType').value = 'damage';
handleSkillTypeChange(); handleSkillTypeChange();
@ -2173,6 +2198,7 @@
description: document.getElementById('skillDescription').value, description: document.getElementById('skillDescription').value,
type: document.getElementById('skillType').value, type: document.getElementById('skillType').value,
target: document.getElementById('skillTarget').value, target: document.getElementById('skillTarget').value,
targeting_mode: document.getElementById('skillTargetingMode').value,
mp_cost: parseInt(document.getElementById('skillMpCost').value) || 0, mp_cost: parseInt(document.getElementById('skillMpCost').value) || 0,
base_power: parseInt(document.getElementById('skillBasePower').value) || 100, base_power: parseInt(document.getElementById('skillBasePower').value) || 100,
accuracy: parseInt(document.getElementById('skillAccuracy').value) || 95, accuracy: parseInt(document.getElementById('skillAccuracy').value) || 95,
@ -2605,11 +2631,29 @@
<button class="btn btn-secondary btn-small" onclick="toggleAdmin(${u.id}, ${!u.is_admin})"> <button class="btn btn-secondary btn-small" onclick="toggleAdmin(${u.id}, ${!u.is_admin})">
${u.is_admin ? 'Revoke Admin' : 'Grant Admin'} ${u.is_admin ? 'Revoke Admin' : 'Grant Admin'}
</button> </button>
<button class="btn btn-danger btn-small" onclick="deleteUser(${u.id}, '${escapeHtml(u.username).replace(/'/g, "\\'")}')">Delete</button>
</td> </td>
</tr> </tr>
`).join(''); `).join('');
} }
async function deleteUser(id, username) {
if (!confirm(`Are you sure you want to DELETE user "${username}"?\n\nThis will permanently remove:\n- User account\n- Character data\n- Monsters\n- Buffs\n- All progress\n\nThis action cannot be undone!`)) return;
// Double confirm for safety
if (!confirm(`FINAL WARNING: Delete user "${username}" permanently?`)) return;
try {
await api(`/api/admin/users/${id}`, { method: 'DELETE' });
// Remove from local array immediately
users = users.filter(u => u.id !== id);
showToast(`User "${username}" deleted`);
renderUserTable();
} catch (e) {
showToast('Failed to delete user: ' + e.message, 'error');
}
}
async function toggleAdmin(id, isAdmin) { async function toggleAdmin(id, isAdmin) {
const action = isAdmin ? 'grant admin to' : 'revoke admin from'; const action = isAdmin ? 'grant admin to' : 'revoke admin from';
if (!confirm(`Are you sure you want to ${action} this user?`)) return; if (!confirm(`Are you sure you want to ${action} this user?`)) return;
@ -2747,6 +2791,8 @@
document.getElementById('setting-inactivityTimeout').value = Math.round(inactivityMs / 60000); document.getElementById('setting-inactivityTimeout').value = Math.round(inactivityMs / 60000);
const warningMs = settings.inactivityWarningTime || 60000; const warningMs = settings.inactivityWarningTime || 60000;
document.getElementById('setting-inactivityWarningTime').value = Math.round(warningMs / 1000); document.getElementById('setting-inactivityWarningTime').value = Math.round(warningMs / 1000);
// Combat UI settings
document.getElementById('setting-combatIconScale').value = settings.combatIconScale || 1.0;
} catch (e) { } catch (e) {
showToast('Failed to load settings: ' + e.message, 'error'); showToast('Failed to load settings: ' + e.message, 'error');
} }
@ -2774,7 +2820,8 @@
homeRegenPercent: parseFloat(document.getElementById('setting-homeRegenPercent').value) || 5, homeRegenPercent: parseFloat(document.getElementById('setting-homeRegenPercent').value) || 5,
homeBaseRadius: parseInt(document.getElementById('setting-homeBaseRadius').value) || 20, homeBaseRadius: parseInt(document.getElementById('setting-homeBaseRadius').value) || 20,
inactivityTimeout: inactivityMinutes * 60000, inactivityTimeout: inactivityMinutes * 60000,
inactivityWarningTime: warningSeconds * 1000
inactivityWarningTime: warningSeconds * 1000,
combatIconScale: parseFloat(document.getElementById('setting-combatIconScale').value) || 1.0
}; };
try { try {

47
database.js

@ -258,6 +258,11 @@ class HikeMapDB {
this.db.exec(`ALTER TABLE monster_skills ADD COLUMN custom_name TEXT`); this.db.exec(`ALTER TABLE monster_skills ADD COLUMN custom_name TEXT`);
} catch (e) { /* Column already exists */ } } catch (e) { /* Column already exists */ }
// Migration: Add targeting_mode to skills for multi-hit targeting behavior
try {
this.db.exec(`ALTER TABLE skills ADD COLUMN targeting_mode TEXT DEFAULT 'same_target'`);
} catch (e) { /* Column already exists */ }
// Migration: Add home base and death system columns to rpg_stats // Migration: Add home base and death system columns to rpg_stats
try { try {
this.db.exec(`ALTER TABLE rpg_stats ADD COLUMN home_base_lat REAL`); this.db.exec(`ALTER TABLE rpg_stats ADD COLUMN home_base_lat REAL`);
@ -1041,8 +1046,8 @@ class HikeMapDB {
createSkill(skillData) { createSkill(skillData) {
const stmt = this.db.prepare(` const stmt = this.db.prepare(`
INSERT INTO skills (id, name, description, type, mp_cost, base_power, accuracy, hit_count, target, status_effect, player_usable, monster_usable, enabled)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
INSERT INTO skills (id, name, description, type, mp_cost, base_power, accuracy, hit_count, target, targeting_mode, status_effect, player_usable, monster_usable, enabled)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`); `);
const statusEffect = skillData.statusEffect const statusEffect = skillData.statusEffect
? (typeof skillData.statusEffect === 'string' ? skillData.statusEffect : JSON.stringify(skillData.statusEffect)) ? (typeof skillData.statusEffect === 'string' ? skillData.statusEffect : JSON.stringify(skillData.statusEffect))
@ -1057,6 +1062,7 @@ class HikeMapDB {
skillData.accuracy || 100, skillData.accuracy || 100,
skillData.hitCount || skillData.hit_count || 1, skillData.hitCount || skillData.hit_count || 1,
skillData.target || 'enemy', skillData.target || 'enemy',
skillData.targetingMode || skillData.targeting_mode || 'same_target',
statusEffect, statusEffect,
skillData.playerUsable !== false ? 1 : 0, skillData.playerUsable !== false ? 1 : 0,
skillData.monsterUsable !== false ? 1 : 0, skillData.monsterUsable !== false ? 1 : 0,
@ -1068,7 +1074,7 @@ class HikeMapDB {
const stmt = this.db.prepare(` const stmt = this.db.prepare(`
UPDATE skills SET UPDATE skills SET
name = ?, description = ?, type = ?, mp_cost = ?, base_power = ?, name = ?, description = ?, type = ?, mp_cost = ?, base_power = ?,
accuracy = ?, hit_count = ?, target = ?, status_effect = ?,
accuracy = ?, hit_count = ?, target = ?, targeting_mode = ?, status_effect = ?,
player_usable = ?, monster_usable = ?, enabled = ? player_usable = ?, monster_usable = ?, enabled = ?
WHERE id = ? WHERE id = ?
`); `);
@ -1098,6 +1104,7 @@ class HikeMapDB {
skillData.accuracy || 100, skillData.accuracy || 100,
skillData.hitCount || skillData.hit_count || 1, skillData.hitCount || skillData.hit_count || 1,
skillData.target || 'enemy', skillData.target || 'enemy',
skillData.targetingMode || skillData.targeting_mode || 'same_target',
statusEffect, statusEffect,
playerUsable, playerUsable,
monsterUsable, monsterUsable,
@ -1118,6 +1125,17 @@ class HikeMapDB {
// CLASS SKILL NAMES METHODS // CLASS SKILL NAMES METHODS
// ===================== // =====================
// Get custom names from class_skills table (primary source - what admin panel edits)
getAllClassSkillNamesFromClassSkills() {
const stmt = this.db.prepare(`
SELECT cs.id, cs.skill_id, cs.class_id, cs.custom_name, cs.custom_description
FROM class_skills cs
WHERE cs.custom_name IS NOT NULL AND cs.custom_name != ''
`);
return stmt.all();
}
// Legacy: Get from class_skill_names table (deprecated)
getAllClassSkillNames() { getAllClassSkillNames() {
const stmt = this.db.prepare(`SELECT * FROM class_skill_names`); const stmt = this.db.prepare(`SELECT * FROM class_skill_names`);
return stmt.all(); return stmt.all();
@ -1985,6 +2003,29 @@ class HikeMapDB {
return stmt.run(userId); return stmt.run(userId);
} }
// Admin: Delete user completely
deleteUser(userId) {
const transaction = this.db.transaction(() => {
// Delete in order to respect foreign key constraints (if any)
// Delete monster entourage
this.db.prepare(`DELETE FROM monster_entourage WHERE user_id = ?`).run(userId);
// Delete player buffs
this.db.prepare(`DELETE FROM player_buffs WHERE player_id = ?`).run(userId);
// Delete refresh tokens
this.db.prepare(`DELETE FROM refresh_tokens WHERE user_id = ?`).run(userId);
// Delete RPG stats
this.db.prepare(`DELETE FROM rpg_stats WHERE user_id = ?`).run(userId);
// Delete user account
this.db.prepare(`DELETE FROM users WHERE id = ?`).run(userId);
});
return transaction();
}
// Game settings methods // Game settings methods
getSetting(key) { getSetting(key) {
const stmt = this.db.prepare(`SELECT value FROM game_settings WHERE key = ?`); const stmt = this.db.prepare(`SELECT value FROM game_settings WHERE key = ?`);

798
index.html
File diff suppressed because it is too large
View File

602
package-lock.json

@ -10,8 +10,11 @@
"dependencies": { "dependencies": {
"@bubblewrap/cli": "^1.24.1", "@bubblewrap/cli": "^1.24.1",
"@pwabuilder/cli": "^0.0.17", "@pwabuilder/cli": "^0.0.17",
"bcrypt": "^5.1.1",
"better-sqlite3": "^9.4.0",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"express": "^4.18.2", "express": "^4.18.2",
"jsonwebtoken": "^9.0.2",
"web-push": "^3.6.6", "web-push": "^3.6.6",
"ws": "^8.14.2" "ws": "^8.14.2"
}, },
@ -786,6 +789,98 @@
"regenerator-runtime": "^0.13.3" "regenerator-runtime": "^0.13.3"
} }
}, },
"node_modules/@mapbox/node-pre-gyp": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz",
"integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==",
"license": "BSD-3-Clause",
"dependencies": {
"detect-libc": "^2.0.0",
"https-proxy-agent": "^5.0.0",
"make-dir": "^3.1.0",
"node-fetch": "^2.6.7",
"nopt": "^5.0.0",
"npmlog": "^5.0.1",
"rimraf": "^3.0.2",
"semver": "^7.3.5",
"tar": "^6.1.11"
},
"bin": {
"node-pre-gyp": "bin/node-pre-gyp"
}
},
"node_modules/@mapbox/node-pre-gyp/node_modules/agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
"integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
"license": "MIT",
"dependencies": {
"debug": "4"
},
"engines": {
"node": ">= 6.0.0"
}
},
"node_modules/@mapbox/node-pre-gyp/node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/@mapbox/node-pre-gyp/node_modules/https-proxy-agent": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
"integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
"license": "MIT",
"dependencies": {
"agent-base": "6",
"debug": "4"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/@mapbox/node-pre-gyp/node_modules/make-dir": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
"integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
"license": "MIT",
"dependencies": {
"semver": "^6.0.0"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@mapbox/node-pre-gyp/node_modules/make-dir/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/@mapbox/node-pre-gyp/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/@maxim_mazurok/gapi.client.androidpublisher-v3": { "node_modules/@maxim_mazurok/gapi.client.androidpublisher-v3": {
"version": "0.1.20251216", "version": "0.1.20251216",
"resolved": "https://registry.npmjs.org/@maxim_mazurok/gapi.client.androidpublisher-v3/-/gapi.client.androidpublisher-v3-0.1.20251216.tgz", "resolved": "https://registry.npmjs.org/@maxim_mazurok/gapi.client.androidpublisher-v3/-/gapi.client.androidpublisher-v3-0.1.20251216.tgz",
@ -1419,6 +1514,12 @@
"node": ">=20.0.0" "node": ">=20.0.0"
} }
}, },
"node_modules/abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"license": "ISC"
},
"node_modules/abort-controller": { "node_modules/abort-controller": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
@ -1587,6 +1688,40 @@
} }
} }
}, },
"node_modules/aproba": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz",
"integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==",
"license": "ISC"
},
"node_modules/are-we-there-yet": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz",
"integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==",
"deprecated": "This package is no longer supported.",
"license": "ISC",
"dependencies": {
"delegates": "^1.0.0",
"readable-stream": "^3.6.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/are-we-there-yet/node_modules/readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"license": "MIT",
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/arr-diff": { "node_modules/arr-diff": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
@ -1822,6 +1957,31 @@
], ],
"license": "MIT" "license": "MIT"
}, },
"node_modules/bcrypt": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz",
"integrity": "sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"@mapbox/node-pre-gyp": "^1.0.11",
"node-addon-api": "^5.0.0"
},
"engines": {
"node": ">= 10.0.0"
}
},
"node_modules/better-sqlite3": {
"version": "9.6.0",
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-9.6.0.tgz",
"integrity": "sha512-yR5HATnqeYNVnkaUTf4bOP2dJSnyhP4puJN/QPRyx4YkBEEUxib422n2XzPqDEHjQQqazoYoADdAm5vE15+dAQ==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"bindings": "^1.5.0",
"prebuild-install": "^7.1.1"
}
},
"node_modules/bignumber.js": { "node_modules/bignumber.js": {
"version": "9.3.1", "version": "9.3.1",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz",
@ -1845,7 +2005,6 @@
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"license": "MIT", "license": "MIT",
"optional": true,
"dependencies": { "dependencies": {
"file-uri-to-path": "1.0.0" "file-uri-to-path": "1.0.0"
} }
@ -2388,6 +2547,15 @@
"simple-swizzle": "^0.2.2" "simple-swizzle": "^0.2.2"
} }
}, },
"node_modules/color-support": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
"integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
"license": "ISC",
"bin": {
"color-support": "bin.js"
}
},
"node_modules/colors": { "node_modules/colors": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
@ -2445,6 +2613,12 @@
"typedarray": "^0.0.6" "typedarray": "^0.0.6"
} }
}, },
"node_modules/console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==",
"license": "ISC"
},
"node_modules/content-disposition": { "node_modules/content-disposition": {
"version": "0.5.4", "version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
@ -2573,6 +2747,21 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/decompress-response": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
"license": "MIT",
"dependencies": {
"mimic-response": "^3.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/decompress-tar": { "node_modules/decompress-tar": {
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz",
@ -2708,6 +2897,15 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/deep-extend": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"license": "MIT",
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/defaults": { "node_modules/defaults": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
@ -2768,6 +2966,12 @@
"node": ">=0.4.0" "node": ">=0.4.0"
} }
}, },
"node_modules/delegates": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==",
"license": "MIT"
},
"node_modules/depd": { "node_modules/depd": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@ -2787,6 +2991,15 @@
"npm": "1.2.8000 || >= 1.4.16" "npm": "1.2.8000 || >= 1.4.16"
} }
}, },
"node_modules/detect-libc": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
"license": "Apache-2.0",
"engines": {
"node": ">=8"
}
},
"node_modules/diagnostic-channel": { "node_modules/diagnostic-channel": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/diagnostic-channel/-/diagnostic-channel-1.1.1.tgz", "resolved": "https://registry.npmjs.org/diagnostic-channel/-/diagnostic-channel-1.1.1.tgz",
@ -3015,6 +3228,15 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/expand-template": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
"license": "(MIT OR WTFPL)",
"engines": {
"node": ">=6"
}
},
"node_modules/express": { "node_modules/express": {
"version": "4.22.1", "version": "4.22.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz",
@ -3188,8 +3410,7 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
"license": "MIT",
"optional": true
"license": "MIT"
}, },
"node_modules/filename-regex": { "node_modules/filename-regex": {
"version": "2.0.1", "version": "2.0.1",
@ -3406,6 +3627,27 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/gauge": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz",
"integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==",
"deprecated": "This package is no longer supported.",
"license": "ISC",
"dependencies": {
"aproba": "^1.0.3 || ^2.0.0",
"color-support": "^1.1.2",
"console-control-strings": "^1.0.0",
"has-unicode": "^2.0.1",
"object-assign": "^4.1.1",
"signal-exit": "^3.0.0",
"string-width": "^4.2.3",
"strip-ansi": "^6.0.1",
"wide-align": "^1.1.2"
},
"engines": {
"node": ">=10"
}
},
"node_modules/gaxios": { "node_modules/gaxios": {
"version": "4.3.3", "version": "4.3.3",
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.3.tgz", "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.3.3.tgz",
@ -3560,6 +3802,12 @@
"omggif": "^1.0.10" "omggif": "^1.0.10"
} }
}, },
"node_modules/github-from-package": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
"license": "MIT"
},
"node_modules/glob": { "node_modules/glob": {
"version": "7.2.3", "version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@ -3770,6 +4018,12 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/has-unicode": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==",
"license": "ISC"
},
"node_modules/has-value": { "node_modules/has-value": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
@ -4031,6 +4285,12 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC" "license": "ISC"
}, },
"node_modules/ini": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
"license": "ISC"
},
"node_modules/inquirer": { "node_modules/inquirer": {
"version": "8.2.7", "version": "8.2.7",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.7.tgz", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.7.tgz",
@ -4437,6 +4697,34 @@
"bignumber.js": "^9.0.0" "bignumber.js": "^9.0.0"
} }
}, },
"node_modules/jsonwebtoken": {
"version": "9.0.3",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz",
"integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==",
"license": "MIT",
"dependencies": {
"jws": "^4.0.1",
"lodash.includes": "^4.3.0",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.1.1",
"semver": "^7.5.4"
},
"engines": {
"node": ">=12",
"npm": ">=6"
}
},
"node_modules/jsonwebtoken/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/jwa": { "node_modules/jwa": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz",
@ -4492,6 +4780,48 @@
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/lodash.includes": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
"license": "MIT"
},
"node_modules/lodash.isboolean": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
"license": "MIT"
},
"node_modules/lodash.isinteger": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
"integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
"license": "MIT"
},
"node_modules/lodash.isnumber": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
"integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
"license": "MIT"
},
"node_modules/lodash.isplainobject": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
"license": "MIT"
},
"node_modules/lodash.isstring": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
"license": "MIT"
},
"node_modules/lodash.once": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
"license": "MIT"
},
"node_modules/log-symbols": { "node_modules/log-symbols": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
@ -4670,6 +5000,18 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/mimic-response": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
"license": "MIT",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/min-document": { "node_modules/min-document": {
"version": "2.19.2", "version": "2.19.2",
"resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.2.tgz", "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.2.tgz",
@ -4777,6 +5119,12 @@
"mkdirp": "bin/cmd.js" "mkdirp": "bin/cmd.js"
} }
}, },
"node_modules/mkdirp-classic": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
"license": "MIT"
},
"node_modules/module-details-from-path": { "node_modules/module-details-from-path": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz", "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz",
@ -4851,6 +5199,12 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/napi-build-utils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
"integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==",
"license": "MIT"
},
"node_modules/negotiator": { "node_modules/negotiator": {
"version": "0.6.3", "version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
@ -4860,6 +5214,24 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/node-abi": {
"version": "3.85.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.85.0.tgz",
"integrity": "sha512-zsFhmbkAzwhTft6nd3VxcG0cvJsT70rL+BIGHWVq5fi6MwGrHwzqKaxXE+Hl2GmnGItnDKPPkO5/LQqjVkIdFg==",
"license": "MIT",
"dependencies": {
"semver": "^7.3.5"
},
"engines": {
"node": ">=10"
}
},
"node_modules/node-addon-api": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz",
"integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==",
"license": "MIT"
},
"node_modules/node-fetch": { "node_modules/node-fetch": {
"version": "2.7.0", "version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
@ -4889,6 +5261,21 @@
"node": ">= 6.13.0" "node": ">= 6.13.0"
} }
}, },
"node_modules/nopt": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
"integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
"license": "ISC",
"dependencies": {
"abbrev": "1"
},
"bin": {
"nopt": "bin/nopt.js"
},
"engines": {
"node": ">=6"
}
},
"node_modules/normalize-path": { "node_modules/normalize-path": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
@ -4901,6 +5288,19 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/npmlog": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz",
"integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==",
"deprecated": "This package is no longer supported.",
"license": "ISC",
"dependencies": {
"are-we-there-yet": "^2.0.0",
"console-control-strings": "^1.1.0",
"gauge": "^3.0.0",
"set-blocking": "^2.0.0"
}
},
"node_modules/object-assign": { "node_modules/object-assign": {
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@ -5291,6 +5691,32 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/prebuild-install": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz",
"integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
"license": "MIT",
"dependencies": {
"detect-libc": "^2.0.0",
"expand-template": "^2.0.3",
"github-from-package": "0.0.0",
"minimist": "^1.2.3",
"mkdirp-classic": "^0.5.3",
"napi-build-utils": "^2.0.0",
"node-abi": "^3.3.0",
"pump": "^3.0.0",
"rc": "^1.2.7",
"simple-get": "^4.0.0",
"tar-fs": "^2.0.0",
"tunnel-agent": "^0.6.0"
},
"bin": {
"prebuild-install": "bin.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/preserve": { "node_modules/preserve": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
@ -5340,6 +5766,16 @@
"url": "https://github.com/sponsors/lupomontero" "url": "https://github.com/sponsors/lupomontero"
} }
}, },
"node_modules/pump": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
"integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==",
"license": "MIT",
"dependencies": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
}
},
"node_modules/punycode": { "node_modules/punycode": {
"version": "2.3.1", "version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@ -5435,6 +5871,21 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/rc": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
"license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
"dependencies": {
"deep-extend": "^0.6.0",
"ini": "~1.3.0",
"minimist": "^1.2.0",
"strip-json-comments": "~2.0.1"
},
"bin": {
"rc": "cli.js"
}
},
"node_modules/readable-stream": { "node_modules/readable-stream": {
"version": "2.3.8", "version": "2.3.8",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
@ -5942,6 +6393,22 @@
"node": ">= 0.8.15" "node": ">= 0.8.15"
} }
}, },
"node_modules/rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
"deprecated": "Rimraf versions prior to v4 are no longer supported",
"license": "ISC",
"dependencies": {
"glob": "^7.1.3"
},
"bin": {
"rimraf": "bin.js"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/run-async": { "node_modules/run-async": {
"version": "2.4.1", "version": "2.4.1",
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
@ -6071,6 +6538,12 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
"license": "ISC"
},
"node_modules/set-function-length": { "node_modules/set-function-length": {
"version": "1.2.2", "version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
@ -6217,6 +6690,51 @@
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"license": "ISC" "license": "ISC"
}, },
"node_modules/simple-concat": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/simple-get": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
"integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT",
"dependencies": {
"decompress-response": "^6.0.0",
"once": "^1.3.1",
"simple-concat": "^1.0.0"
}
},
"node_modules/simple-swizzle": { "node_modules/simple-swizzle": {
"version": "0.2.4", "version": "0.2.4",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz",
@ -6489,6 +7007,15 @@
"is-natural-number": "^4.0.1" "is-natural-number": "^4.0.1"
} }
}, },
"node_modules/strip-json-comments": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/strtok3": { "node_modules/strtok3": {
"version": "6.3.0", "version": "6.3.0",
"resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz", "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz",
@ -6565,6 +7092,54 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/tar-fs": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
"integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
"license": "MIT",
"dependencies": {
"chownr": "^1.1.1",
"mkdirp-classic": "^0.5.2",
"pump": "^3.0.0",
"tar-stream": "^2.1.4"
}
},
"node_modules/tar-fs/node_modules/chownr": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
"license": "ISC"
},
"node_modules/tar-fs/node_modules/readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"license": "MIT",
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/tar-fs/node_modules/tar-stream": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
"license": "MIT",
"dependencies": {
"bl": "^4.0.3",
"end-of-stream": "^1.4.1",
"fs-constants": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^3.1.1"
},
"engines": {
"node": ">=6"
}
},
"node_modules/tar-stream": { "node_modules/tar-stream": {
"version": "1.6.2", "version": "1.6.2",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz",
@ -6783,6 +7358,18 @@
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD" "license": "0BSD"
}, },
"node_modules/tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
"license": "Apache-2.0",
"dependencies": {
"safe-buffer": "^5.0.1"
},
"engines": {
"node": "*"
}
},
"node_modules/type-fest": { "node_modules/type-fest": {
"version": "0.21.3", "version": "0.21.3",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
@ -7086,6 +7673,15 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/wide-align": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
"integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==",
"license": "ISC",
"dependencies": {
"string-width": "^1.0.2 || 2 || 3 || 4"
}
},
"node_modules/wrap-ansi": { "node_modules/wrap-ansi": {
"version": "6.2.0", "version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",

44
server.js

@ -865,6 +865,11 @@ app.post('/api/user/character', authenticateToken, (req, res) => {
} }
db.createCharacter(req.user.userId, characterData); db.createCharacter(req.user.userId, characterData);
// Clear any existing monsters when creating a new character
// This ensures new characters start fresh without monsters from previous playthroughs
db.clearMonsterEntourage(req.user.userId);
res.json({ success: true }); res.json({ success: true });
} catch (err) { } catch (err) {
console.error('Create character error:', err); console.error('Create character error:', err);
@ -1078,7 +1083,8 @@ app.get('/api/spawn-settings', (req, res) => {
homeRegenPercent: JSON.parse(db.getSetting('homeRegenPercent') || '5'), homeRegenPercent: JSON.parse(db.getSetting('homeRegenPercent') || '5'),
homeBaseRadius: JSON.parse(db.getSetting('homeBaseRadius') || '20'), homeBaseRadius: JSON.parse(db.getSetting('homeBaseRadius') || '20'),
inactivityTimeout: JSON.parse(db.getSetting('inactivityTimeout') || '600000'), // 10 minutes default inactivityTimeout: JSON.parse(db.getSetting('inactivityTimeout') || '600000'), // 10 minutes default
inactivityWarningTime: JSON.parse(db.getSetting('inactivityWarningTime') || '60000') // 60 seconds default
inactivityWarningTime: JSON.parse(db.getSetting('inactivityWarningTime') || '60000'), // 60 seconds default
combatIconScale: JSON.parse(db.getSetting('combatIconScale') || '0.7') // Scale for combat monster icons (0.3 - 1.5), default 70% for mobile
}; };
res.json(settings); res.json(settings);
} catch (err) { } catch (err) {
@ -1331,6 +1337,7 @@ app.get('/api/skills', (req, res) => {
accuracy: s.accuracy, accuracy: s.accuracy,
hitCount: s.hit_count, hitCount: s.hit_count,
target: s.target, target: s.target,
targeting_mode: s.targeting_mode || 'same_target',
statusEffect: s.status_effect ? JSON.parse(s.status_effect) : null, statusEffect: s.status_effect ? JSON.parse(s.status_effect) : null,
playerUsable: !!s.player_usable, playerUsable: !!s.player_usable,
monsterUsable: !!s.monster_usable monsterUsable: !!s.monster_usable
@ -1343,9 +1350,10 @@ app.get('/api/skills', (req, res) => {
}); });
// Get all class skill names (public endpoint) // Get all class skill names (public endpoint)
// Now reads from class_skills table (what admin panel edits) instead of legacy class_skill_names table
app.get('/api/class-skill-names', (req, res) => { app.get('/api/class-skill-names', (req, res) => {
try { try {
const names = db.getAllClassSkillNames();
const names = db.getAllClassSkillNamesFromClassSkills();
// Convert snake_case to camelCase // Convert snake_case to camelCase
const formatted = names.map(n => ({ const formatted = names.map(n => ({
id: n.id, id: n.id,
@ -1395,7 +1403,14 @@ app.get('/api/monster-types/:id/skills', (req, res) => {
// Get monster entourage for current user // Get monster entourage for current user
app.get('/api/user/monsters', authenticateToken, (req, res) => { app.get('/api/user/monsters', authenticateToken, (req, res) => {
try { try {
// Prevent caching - user-specific data must always be fresh
res.set('Cache-Control', 'no-store, no-cache, must-revalidate, private');
res.set('Pragma', 'no-cache');
res.set('Expires', '0');
console.log(`Loading monsters for user ${req.user.userId} (${req.user.username})`);
const monsters = db.getMonsterEntourage(req.user.userId); const monsters = db.getMonsterEntourage(req.user.userId);
console.log(`Found ${monsters.length} monsters for user ${req.user.userId}`);
// Convert snake_case to camelCase for client // Convert snake_case to camelCase for client
const formatted = monsters.map(m => ({ const formatted = monsters.map(m => ({
id: m.id, id: m.id,
@ -1662,6 +1677,30 @@ app.delete('/api/admin/users/:id/home-base', adminOnly, (req, res) => {
} }
}); });
// Delete user completely
app.delete('/api/admin/users/:id', adminOnly, (req, res) => {
try {
const targetUserId = parseInt(req.params.id);
// Prevent deleting yourself
if (targetUserId === req.user.userId) {
return res.status(400).json({ error: 'Cannot delete your own account' });
}
// Force logout the user if they're connected
sendToAuthUser(targetUserId, { type: 'force_logout', reason: 'Account deleted by admin' });
// Delete the user and all their data
db.deleteUser(targetUserId);
console.log(`Admin ${req.user.username} deleted user ${targetUserId}`);
res.json({ success: true });
} catch (err) {
console.error('Admin delete user error:', err);
res.status(500).json({ error: 'Failed to delete user' });
}
});
// Get game settings // Get game settings
app.get('/api/admin/settings', adminOnly, (req, res) => { app.get('/api/admin/settings', adminOnly, (req, res) => {
try { try {
@ -1717,6 +1756,7 @@ app.get('/api/admin/skills', adminOnly, (req, res) => {
accuracy: s.accuracy, accuracy: s.accuracy,
hit_count: s.hit_count, hit_count: s.hit_count,
target: s.target, target: s.target,
targeting_mode: s.targeting_mode || 'same_target',
status_effect: s.status_effect, status_effect: s.status_effect,
player_usable: !!s.player_usable, player_usable: !!s.player_usable,
monster_usable: !!s.monster_usable, monster_usable: !!s.monster_usable,

2
service-worker.js

@ -1,6 +1,6 @@
// HikeMap Service Worker // HikeMap Service Worker
// Increment version to force cache refresh // Increment version to force cache refresh
const CACHE_NAME = 'hikemap-v1.0.2';
const CACHE_NAME = 'hikemap-v1.0.8';
const urlsToCache = [ const urlsToCache = [
'/', '/',
'/index.html', '/index.html',

Loading…
Cancel
Save