1 Commits

Author SHA1 Message Date
josh 2cf797545c chore: bump to version 1.7.0
CI / test (pull_request) Successful in 14s
CI / build-dev (pull_request) Has been skipped
2026-05-29 16:08:18 -04:00
6 changed files with 6 additions and 30 deletions
-2
View File
@@ -539,7 +539,6 @@ function _renderJobConfigFields(key, cfg) {
</div>`;
if (key === 'patchmon_sync' || key === 'semaphore_sync') {
const label = key === 'semaphore_sync' ? 'API Token (Bearer)' : 'API Token (Basic)';
const tokenPlaceholder = key === 'patchmon_sync' ? 'token_key:token_secret' : '';
return `
<div class="form-group">
<label class="form-label" for="job-cfg-api-url">API URL</label>
@@ -549,7 +548,6 @@ function _renderJobConfigFields(key, cfg) {
<div class="form-group">
<label class="form-label" for="job-cfg-api-token">${label}</label>
<input class="form-input" id="job-cfg-api-token" type="password"
placeholder="${tokenPlaceholder}"
value="${esc(cfg.api_token ?? '')}">
</div>`;
}
+1 -1
View File
@@ -1 +1 @@
const VERSION = "1.7.1";
const VERSION = "1.5.0";
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "catalyst",
"version": "1.7.1",
"version": "1.7.0",
"type": "module",
"scripts": {
"start": "node server/server.js",
+1 -7
View File
@@ -41,14 +41,8 @@ async function patchmonSyncHandler(cfg) {
const { api_url, api_token } = cfg;
if (!api_url || !api_token) throw new Error('Patchmon not configured — set API URL and token');
// Accept raw "key:secret" (recommended) or a pre-encoded base64 string.
// ":" cannot appear in a valid base64 string, so it's a reliable discriminator.
const credential = api_token.includes(':')
? Buffer.from(api_token).toString('base64')
: api_token;
const res = await fetch(api_url, {
headers: { Authorization: `Basic ${credential}` },
headers: { Authorization: `Basic ${api_token}` },
});
if (!res.ok) throw new Error(`Patchmon API ${res.status}`);
+3 -7
View File
@@ -112,17 +112,13 @@ router.post('/instances', (req, res) => {
router.put('/instances/:vmid', (req, res) => {
const vmid = parseInt(req.params.vmid, 10);
if (!vmid) return res.status(400).json({ error: 'invalid vmid' });
if (!getInstance(vmid)) return res.status(404).json({ error: 'instance not found' });
const existing = getInstance(vmid);
if (!existing) return res.status(404).json({ error: 'instance not found' });
const merged = { ...existing, ...(req.body ?? {}) };
const errors = validate(merged);
const errors = validate(req.body);
if (errors.length) return res.status(400).json({ errors });
try {
const data = normalise(merged);
const data = normalise(req.body);
updateInstance(vmid, data);
res.json(getInstance(data.vmid));
} catch (e) {
-12
View File
@@ -257,18 +257,6 @@ describe('PUT /api/instances/:vmid', () => {
const res = await request(app).put('/api/instances/100').send({ ...base, vmid: 200 })
expect(res.status).toBe(409)
})
it('accepts a partial body and preserves unspecified fields', async () => {
await request(app).post('/api/instances').send({ ...base, atlas: 1, tailscale_ip: '100.64.0.1' })
const res = await request(app).put('/api/instances/100').send({ state: 'degraded' })
expect(res.status).toBe(200)
expect(res.body.state).toBe('degraded')
expect(res.body.name).toBe(base.name)
expect(res.body.vmid).toBe(100)
expect(res.body.stack).toBe(base.stack)
expect(res.body.atlas).toBe(1)
expect(res.body.tailscale_ip).toBe('100.64.0.1')
})
})
// ── DELETE /api/instances/:vmid ───────────────────────────────────────────────