termbeam 1.15.2 → 1.17.0
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/README.md +3 -0
- package/package.json +2 -1
- package/public/assets/{_basePickBy-BSIbg2Hw.js → _basePickBy-Crmlna7W.js} +1 -1
- package/public/assets/{_baseUniq-CYmx81nY.js → _baseUniq-h6HY8nD4.js} +1 -1
- package/public/assets/{arc-CDJcNcKc.js → arc-BI4RNUD8.js} +1 -1
- package/public/assets/{architectureDiagram-2XIMDMQ5-C1qauSxh.js → architectureDiagram-2XIMDMQ5-C2PAl3D6.js} +1 -1
- package/public/assets/{blockDiagram-WCTKOSBZ-nTHCaU6g.js → blockDiagram-WCTKOSBZ-CADYyoNx.js} +1 -1
- package/public/assets/{c4Diagram-IC4MRINW-CdGuCZNN.js → c4Diagram-IC4MRINW-CQtNNlqT.js} +1 -1
- package/public/assets/channel-DlFJ0YtH.js +1 -0
- package/public/assets/{chunk-4BX2VUAB-IxfdQ8zN.js → chunk-4BX2VUAB-BZhBHL2q.js} +1 -1
- package/public/assets/{chunk-55IACEB6-mjdLMPLu.js → chunk-55IACEB6-DaOODotQ.js} +1 -1
- package/public/assets/{chunk-FMBD7UC4-B-QgE8A5.js → chunk-FMBD7UC4-D7ZUE2Qt.js} +1 -1
- package/public/assets/{chunk-JSJVCQXG-BlBtV3cx.js → chunk-JSJVCQXG-Cr7LmD49.js} +1 -1
- package/public/assets/{chunk-KX2RTZJC-ByLbXYtr.js → chunk-KX2RTZJC-mSzu7V0i.js} +1 -1
- package/public/assets/{chunk-NQ4KR5QH-DdgKg6ac.js → chunk-NQ4KR5QH-UNIo7K3P.js} +1 -1
- package/public/assets/{chunk-QZHKN3VN-DK0sNhO7.js → chunk-QZHKN3VN-D8pHtVTR.js} +1 -1
- package/public/assets/{chunk-WL4C6EOR-CMhwM8MW.js → chunk-WL4C6EOR-CKtSBmtm.js} +1 -1
- package/public/assets/classDiagram-VBA2DB6C-Uh272C_T.js +1 -0
- package/public/assets/classDiagram-v2-RAHNMMFH-Uh272C_T.js +1 -0
- package/public/assets/clone-BiOpyrvc.js +1 -0
- package/public/assets/{cose-bilkent-S5V4N54A-C4J5lbLg.js → cose-bilkent-S5V4N54A-C73dVsDU.js} +1 -1
- package/public/assets/{dagre-KLK3FWXG-CmPYo_iW.js → dagre-KLK3FWXG-CGtdO-e6.js} +1 -1
- package/public/assets/{diagram-E7M64L7V-BSDHjD_1.js → diagram-E7M64L7V-B3RnL1-2.js} +1 -1
- package/public/assets/{diagram-IFDJBPK2-DZFEThmE.js → diagram-IFDJBPK2-BhT13Y--.js} +1 -1
- package/public/assets/{diagram-P4PSJMXO-D2vA458R.js → diagram-P4PSJMXO-w4ta5qzj.js} +1 -1
- package/public/assets/{erDiagram-INFDFZHY-CqngKW80.js → erDiagram-INFDFZHY-p_XdulXc.js} +1 -1
- package/public/assets/{flowDiagram-PKNHOUZH-2ndb8I08.js → flowDiagram-PKNHOUZH-cKD9roCC.js} +1 -1
- package/public/assets/{ganttDiagram-A5KZAMGK-DGH9iwxm.js → ganttDiagram-A5KZAMGK-kRLcbnHy.js} +1 -1
- package/public/assets/{gitGraphDiagram-K3NZZRJ6-DBszyq19.js → gitGraphDiagram-K3NZZRJ6-CfqReYYJ.js} +1 -1
- package/public/assets/{graph-B-VDztTg.js → graph-2Z05uqaC.js} +1 -1
- package/public/assets/index-Bpz9aDGB.css +32 -0
- package/public/assets/index-Cvxh0Fjh.js +394 -0
- package/public/assets/{infoDiagram-LFFYTUFH-BQYostn9.js → infoDiagram-LFFYTUFH-D2bxFvYS.js} +1 -1
- package/public/assets/{ishikawaDiagram-PHBUUO56-BF9SDQjL.js → ishikawaDiagram-PHBUUO56-olWTIvNJ.js} +1 -1
- package/public/assets/{journeyDiagram-4ABVD52K-BVygcg_3.js → journeyDiagram-4ABVD52K-T_3LhARU.js} +1 -1
- package/public/assets/{kanban-definition-K7BYSVSG-C360CZ_M.js → kanban-definition-K7BYSVSG-BCmUNdAK.js} +1 -1
- package/public/assets/{layout-D1dS_Xae.js → layout-BuQ9md8V.js} +1 -1
- package/public/assets/{linear-DSiHoSbJ.js → linear-BGGATdCH.js} +1 -1
- package/public/assets/{mindmap-definition-YRQLILUH-DW7C3qtv.js → mindmap-definition-YRQLILUH-Bz_sgl78.js} +1 -1
- package/public/assets/{pieDiagram-SKSYHLDU-C8vfomtz.js → pieDiagram-SKSYHLDU-wxt-R3l5.js} +1 -1
- package/public/assets/{quadrantDiagram-337W2JSQ-DXT_qKk-.js → quadrantDiagram-337W2JSQ-0yTHkNo0.js} +1 -1
- package/public/assets/{requirementDiagram-Z7DCOOCP-Dj2MzFq3.js → requirementDiagram-Z7DCOOCP-CLqLwKcJ.js} +1 -1
- package/public/assets/{sankeyDiagram-WA2Y5GQK-YfmbQXg2.js → sankeyDiagram-WA2Y5GQK-CV2OX87k.js} +1 -1
- package/public/assets/{sequenceDiagram-2WXFIKYE-Bp9hgUSv.js → sequenceDiagram-2WXFIKYE-DaQifS2p.js} +1 -1
- package/public/assets/{stateDiagram-RAJIS63D-D8VgKzZe.js → stateDiagram-RAJIS63D-Bi5e4H5H.js} +1 -1
- package/public/assets/stateDiagram-v2-FVOUBMTO-D2d2wuS-.js +1 -0
- package/public/assets/{timeline-definition-YZTLITO2-3ErXxqpK.js → timeline-definition-YZTLITO2-Bu0j_UbL.js} +1 -1
- package/public/assets/{treemap-KZPCXAKY-D3-uSz_K.js → treemap-KZPCXAKY-BreHb2Q6.js} +1 -1
- package/public/assets/{vennDiagram-LZ73GAT5-D7Isk6A4.js → vennDiagram-LZ73GAT5-C5vHpUCv.js} +1 -1
- package/public/assets/{xychartDiagram-JWTSCODW-CpuvGwXM.js → xychartDiagram-JWTSCODW-DEN428FH.js} +1 -1
- package/public/index.html +2 -2
- package/public/sw.js +2 -2
- package/src/server/index.js +35 -4
- package/src/server/push.js +118 -0
- package/src/server/routes.js +350 -5
- package/src/server/sessions.js +144 -0
- package/src/server/websocket.js +21 -2
- package/src/utils/git.js +338 -1
- package/src/utils/update-check.js +139 -9
- package/src/utils/update-executor.js +340 -0
- package/src/utils/vapid.js +45 -0
- package/public/assets/channel-Bh_CZXn-.js +0 -1
- package/public/assets/classDiagram-VBA2DB6C-CSkcpaag.js +0 -1
- package/public/assets/classDiagram-v2-RAHNMMFH-CSkcpaag.js +0 -1
- package/public/assets/clone-BR1se3-G.js +0 -1
- package/public/assets/index-BWUfRdC9.js +0 -391
- package/public/assets/index-D_1GL6a5.css +0 -32
- package/public/assets/stateDiagram-v2-FVOUBMTO-By5luAVT.js +0 -1
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
const { execFile } = require('child_process');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const log = require('./logger');
|
|
6
|
+
|
|
7
|
+
const INSTALL_TIMEOUT_MS = 120_000; // 2 minutes for npm install
|
|
8
|
+
const VERIFY_TIMEOUT_MS = 5_000;
|
|
9
|
+
|
|
10
|
+
function getConfigDir() {
|
|
11
|
+
return process.env.TERMBEAM_CONFIG_DIR || path.join(os.homedir(), '.termbeam');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function getUpdateResultPath() {
|
|
15
|
+
return path.join(getConfigDir(), 'update-result.json');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// ── State Machine ────────────────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @typedef {'idle'|'checking-permissions'|'installing'|'verifying'|'restarting'|'complete'|'failed'} UpdateStatus
|
|
22
|
+
* @typedef {{
|
|
23
|
+
* status: UpdateStatus,
|
|
24
|
+
* phase: string|null,
|
|
25
|
+
* progress: string|null,
|
|
26
|
+
* error: string|null,
|
|
27
|
+
* fromVersion: string|null,
|
|
28
|
+
* toVersion: string|null,
|
|
29
|
+
* startedAt: number|null,
|
|
30
|
+
* restartStrategy: string|null,
|
|
31
|
+
* }} UpdateState
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/** @type {UpdateState} */
|
|
35
|
+
const updateState = {
|
|
36
|
+
status: 'idle',
|
|
37
|
+
phase: null,
|
|
38
|
+
progress: null,
|
|
39
|
+
error: null,
|
|
40
|
+
fromVersion: null,
|
|
41
|
+
toVersion: null,
|
|
42
|
+
startedAt: null,
|
|
43
|
+
restartStrategy: null,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
function getUpdateState() {
|
|
47
|
+
return { ...updateState };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function setState(updates) {
|
|
51
|
+
Object.assign(updateState, updates);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function resetState() {
|
|
55
|
+
setState({
|
|
56
|
+
status: 'idle',
|
|
57
|
+
phase: null,
|
|
58
|
+
progress: null,
|
|
59
|
+
error: null,
|
|
60
|
+
fromVersion: null,
|
|
61
|
+
toVersion: null,
|
|
62
|
+
startedAt: null,
|
|
63
|
+
restartStrategy: null,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ── Permission Check ─────────────────────────────────────────────────────────
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Check if we can write to the npm global prefix directory.
|
|
71
|
+
* Returns { canUpdate, reason } — if canUpdate is false, reason explains why.
|
|
72
|
+
*/
|
|
73
|
+
async function checkPermissions(method) {
|
|
74
|
+
const cmd = method === 'yarn' ? 'yarn' : method === 'pnpm' ? 'pnpm' : 'npm';
|
|
75
|
+
|
|
76
|
+
// Check if the package manager is available by running it directly
|
|
77
|
+
try {
|
|
78
|
+
await execFilePromise(cmd, ['--version'], { timeout: VERIFY_TIMEOUT_MS });
|
|
79
|
+
} catch {
|
|
80
|
+
return { canUpdate: false, reason: `${cmd} not found on PATH` };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Check if npm global directory is writable (only for npm — yarn/pnpm have different paths)
|
|
84
|
+
if (cmd === 'npm') {
|
|
85
|
+
try {
|
|
86
|
+
// Use `npm root -g` for the actual global node_modules path (cross-platform)
|
|
87
|
+
const globalRoot = (
|
|
88
|
+
await execFilePromise('npm', ['root', '-g'], { timeout: VERIFY_TIMEOUT_MS })
|
|
89
|
+
).stdout.trim();
|
|
90
|
+
await fs.promises.access(globalRoot, fs.constants.W_OK);
|
|
91
|
+
} catch {
|
|
92
|
+
return {
|
|
93
|
+
canUpdate: false,
|
|
94
|
+
reason: 'npm global directory is not writable (may need sudo)',
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return { canUpdate: true, reason: null };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ── Update Execution ─────────────────────────────────────────────────────────
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Execute the update process. Calls onProgress for real-time status updates.
|
|
106
|
+
*
|
|
107
|
+
* @param {object} options
|
|
108
|
+
* @param {string} options.currentVersion - Version before update
|
|
109
|
+
* @param {string} options.installCmd - The executable to run (e.g. "npm")
|
|
110
|
+
* @param {string[]} options.installArgs - Arguments for the install command
|
|
111
|
+
* @param {string} options.command - Display string for the full command
|
|
112
|
+
* @param {string} options.method - Package manager (npm/yarn/pnpm)
|
|
113
|
+
* @param {string} options.restartStrategy - 'pm2' or 'exit'
|
|
114
|
+
* @param {(state: UpdateState) => void} [options.onProgress] - Progress callback
|
|
115
|
+
* @param {() => Promise<void>} [options.performRestart] - Called to execute restart
|
|
116
|
+
* @returns {Promise<UpdateState>}
|
|
117
|
+
*/
|
|
118
|
+
async function executeUpdate({
|
|
119
|
+
currentVersion,
|
|
120
|
+
installCmd,
|
|
121
|
+
installArgs,
|
|
122
|
+
command,
|
|
123
|
+
method,
|
|
124
|
+
restartStrategy,
|
|
125
|
+
onProgress,
|
|
126
|
+
performRestart,
|
|
127
|
+
}) {
|
|
128
|
+
if (updateState.status !== 'idle' && updateState.status !== 'failed') {
|
|
129
|
+
return { ...updateState, error: 'Update already in progress' };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const notify = (updates) => {
|
|
133
|
+
setState(updates);
|
|
134
|
+
if (onProgress) {
|
|
135
|
+
try {
|
|
136
|
+
onProgress(getUpdateState());
|
|
137
|
+
} catch {
|
|
138
|
+
// Don't let callback errors break the update
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
setState({
|
|
144
|
+
status: 'checking-permissions',
|
|
145
|
+
phase: 'Checking permissions...',
|
|
146
|
+
progress: null,
|
|
147
|
+
error: null,
|
|
148
|
+
fromVersion: currentVersion,
|
|
149
|
+
toVersion: null,
|
|
150
|
+
startedAt: Date.now(),
|
|
151
|
+
restartStrategy,
|
|
152
|
+
});
|
|
153
|
+
notify({});
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
// Step 1: Permission check
|
|
157
|
+
const { canUpdate, reason } = await checkPermissions(method);
|
|
158
|
+
if (!canUpdate) {
|
|
159
|
+
notify({ status: 'failed', phase: 'Permission check failed', error: reason });
|
|
160
|
+
return getUpdateState();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Step 2: Install
|
|
164
|
+
notify({ status: 'installing', phase: 'Installing update...', progress: '' });
|
|
165
|
+
|
|
166
|
+
log.info(`Executing update: ${command}`);
|
|
167
|
+
|
|
168
|
+
const { stdout, stderr } = await execFilePromise(installCmd, installArgs, {
|
|
169
|
+
timeout: INSTALL_TIMEOUT_MS,
|
|
170
|
+
maxBuffer: 10 * 1024 * 1024, // 10 MB — package manager installs can be verbose
|
|
171
|
+
env: { ...process.env, NO_UPDATE_NOTIFIER: '1' },
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const output = (stdout + '\n' + stderr).trim();
|
|
175
|
+
notify({ progress: output.slice(-500) }); // Keep last 500 chars
|
|
176
|
+
log.debug(`Install output: ${output.slice(0, 200)}`);
|
|
177
|
+
|
|
178
|
+
// Step 3: Verify
|
|
179
|
+
notify({ status: 'verifying', phase: 'Verifying update...' });
|
|
180
|
+
|
|
181
|
+
const newVersion = await verifyInstalledVersion(method);
|
|
182
|
+
if (!newVersion) {
|
|
183
|
+
notify({
|
|
184
|
+
status: 'failed',
|
|
185
|
+
phase: 'Verification failed',
|
|
186
|
+
error: 'Could not determine new version after install',
|
|
187
|
+
});
|
|
188
|
+
return getUpdateState();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const { isNewerVersion } = require('./update-check');
|
|
192
|
+
if (newVersion === currentVersion) {
|
|
193
|
+
// Same version reinstalled (cache, registry delay) — treat as success
|
|
194
|
+
log.info(`Update reinstalled same version (${newVersion})`);
|
|
195
|
+
} else if (!isNewerVersion(currentVersion, newVersion)) {
|
|
196
|
+
notify({
|
|
197
|
+
status: 'failed',
|
|
198
|
+
phase: 'Verification failed',
|
|
199
|
+
error: `Unexpected version after update: ${newVersion} (was ${currentVersion})`,
|
|
200
|
+
});
|
|
201
|
+
return getUpdateState();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
notify({ toVersion: newVersion });
|
|
205
|
+
|
|
206
|
+
// Step 4: Write result marker for post-restart verification
|
|
207
|
+
writeUpdateResult({ fromVersion: currentVersion, toVersion: newVersion });
|
|
208
|
+
|
|
209
|
+
// Step 5: Restart
|
|
210
|
+
notify({ status: 'restarting', phase: `Update to v${newVersion} complete. Restarting...` });
|
|
211
|
+
|
|
212
|
+
if (performRestart) {
|
|
213
|
+
// Give clients a moment to receive the status update
|
|
214
|
+
await sleep(500);
|
|
215
|
+
await performRestart();
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
notify({ status: 'complete', phase: `Updated to v${newVersion}` });
|
|
219
|
+
return getUpdateState();
|
|
220
|
+
} catch (err) {
|
|
221
|
+
log.error(`Update failed: ${err.message}`);
|
|
222
|
+
notify({
|
|
223
|
+
status: 'failed',
|
|
224
|
+
phase: 'Update failed',
|
|
225
|
+
error: err.message,
|
|
226
|
+
});
|
|
227
|
+
return getUpdateState();
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// ── Version Verification ─────────────────────────────────────────────────────
|
|
232
|
+
|
|
233
|
+
async function verifyInstalledVersion(method) {
|
|
234
|
+
const cmd = method === 'yarn' ? 'yarn' : method === 'pnpm' ? 'pnpm' : 'npm';
|
|
235
|
+
try {
|
|
236
|
+
// Use npm/yarn/pnpm to read the installed version
|
|
237
|
+
let args;
|
|
238
|
+
if (cmd === 'npm') {
|
|
239
|
+
args = ['ls', '-g', 'termbeam', '--depth=0', '--json'];
|
|
240
|
+
} else if (cmd === 'yarn') {
|
|
241
|
+
args = ['global', 'list', '--json', '--pattern', 'termbeam'];
|
|
242
|
+
} else {
|
|
243
|
+
args = ['list', '-g', 'termbeam', '--json'];
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const { stdout } = await execFilePromise(cmd, args, { timeout: VERIFY_TIMEOUT_MS });
|
|
247
|
+
|
|
248
|
+
if (cmd === 'npm') {
|
|
249
|
+
const data = JSON.parse(stdout);
|
|
250
|
+
const deps = data.dependencies || {};
|
|
251
|
+
if (deps.termbeam && deps.termbeam.version) {
|
|
252
|
+
return deps.termbeam.version;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Fallback: try parsing version from output
|
|
257
|
+
const match = stdout.match(/termbeam@(\d+\.\d+\.\d+)/);
|
|
258
|
+
if (match) return match[1];
|
|
259
|
+
} catch (err) {
|
|
260
|
+
log.debug(`Version verification via ${cmd} failed: ${err.message}`);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Fallback: try running the new termbeam binary directly
|
|
264
|
+
try {
|
|
265
|
+
const { stdout } = await execFilePromise('termbeam', ['--version'], {
|
|
266
|
+
timeout: VERIFY_TIMEOUT_MS,
|
|
267
|
+
});
|
|
268
|
+
const match = stdout.trim().match(/(\d+\.\d+\.\d+)/);
|
|
269
|
+
if (match) return match[1];
|
|
270
|
+
} catch {
|
|
271
|
+
log.debug('Version verification via termbeam --version failed');
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// ── Update Result Marker ─────────────────────────────────────────────────────
|
|
278
|
+
|
|
279
|
+
function writeUpdateResult({ fromVersion, toVersion }) {
|
|
280
|
+
try {
|
|
281
|
+
const resultPath = getUpdateResultPath();
|
|
282
|
+
fs.mkdirSync(path.dirname(resultPath), { recursive: true });
|
|
283
|
+
fs.writeFileSync(
|
|
284
|
+
resultPath,
|
|
285
|
+
JSON.stringify({ fromVersion, toVersion, updatedAt: Date.now() }) + '\n',
|
|
286
|
+
{ mode: 0o600 },
|
|
287
|
+
);
|
|
288
|
+
} catch (err) {
|
|
289
|
+
log.debug(`Could not write update result: ${err.message}`);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function readUpdateResult() {
|
|
294
|
+
try {
|
|
295
|
+
const data = JSON.parse(fs.readFileSync(getUpdateResultPath(), 'utf8'));
|
|
296
|
+
if (data && data.fromVersion && data.toVersion) return data;
|
|
297
|
+
} catch {
|
|
298
|
+
// No result or corrupt
|
|
299
|
+
}
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function clearUpdateResult() {
|
|
304
|
+
try {
|
|
305
|
+
fs.unlinkSync(getUpdateResultPath());
|
|
306
|
+
} catch {
|
|
307
|
+
// Already gone
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
312
|
+
|
|
313
|
+
function execFilePromise(cmd, args, options = {}) {
|
|
314
|
+
return new Promise((resolve, reject) => {
|
|
315
|
+
execFile(cmd, args, { encoding: 'utf8', ...options }, (err, stdout, stderr) => {
|
|
316
|
+
if (err) {
|
|
317
|
+
err.stdout = stdout;
|
|
318
|
+
err.stderr = stderr;
|
|
319
|
+
reject(err);
|
|
320
|
+
} else {
|
|
321
|
+
resolve({ stdout, stderr });
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function sleep(ms) {
|
|
328
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
module.exports = {
|
|
332
|
+
getUpdateState,
|
|
333
|
+
resetState,
|
|
334
|
+
executeUpdate,
|
|
335
|
+
checkPermissions,
|
|
336
|
+
verifyInstalledVersion,
|
|
337
|
+
writeUpdateResult,
|
|
338
|
+
readUpdateResult,
|
|
339
|
+
clearUpdateResult,
|
|
340
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const webpush = require('web-push');
|
|
4
|
+
const log = require('./logger');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Load existing VAPID keys from configDir/vapid.json or generate new ones.
|
|
8
|
+
* Keys are persisted so they survive server restarts.
|
|
9
|
+
* @param {string} configDir - Directory to store vapid.json
|
|
10
|
+
* @returns {{ publicKey: string, privateKey: string, subject: string }}
|
|
11
|
+
*/
|
|
12
|
+
function getOrCreateVapidKeys(configDir) {
|
|
13
|
+
const vapidPath = path.join(configDir, 'vapid.json');
|
|
14
|
+
const subject = 'https://termbeam.dev';
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
const raw = fs.readFileSync(vapidPath, 'utf8');
|
|
18
|
+
const keys = JSON.parse(raw);
|
|
19
|
+
if (keys.publicKey && keys.privateKey) {
|
|
20
|
+
log.debug('Loaded existing VAPID keys');
|
|
21
|
+
return { publicKey: keys.publicKey, privateKey: keys.privateKey, subject };
|
|
22
|
+
}
|
|
23
|
+
} catch {
|
|
24
|
+
// File doesn't exist or is invalid — generate new keys
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
log.info('Generating new VAPID keys');
|
|
28
|
+
const keys = webpush.generateVAPIDKeys();
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
32
|
+
fs.writeFileSync(
|
|
33
|
+
vapidPath,
|
|
34
|
+
JSON.stringify({ publicKey: keys.publicKey, privateKey: keys.privateKey }, null, 2),
|
|
35
|
+
{ mode: 0o600 },
|
|
36
|
+
);
|
|
37
|
+
log.debug(`VAPID keys saved to ${vapidPath}`);
|
|
38
|
+
} catch (err) {
|
|
39
|
+
log.warn(`Could not save VAPID keys to ${vapidPath}: ${err.message}`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return { publicKey: keys.publicKey, privateKey: keys.privateKey, subject };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
module.exports = { getOrCreateVapidKeys };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{aq as o,ar as n}from"./index-BWUfRdC9.js";const t=(r,a)=>o.lang.round(n.parse(r)[a]);export{t as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as e,C as t}from"./chunk-WL4C6EOR-CMhwM8MW.js";import{_ as i}from"./index-BWUfRdC9.js";import"./chunk-FMBD7UC4-B-QgE8A5.js";import"./chunk-JSJVCQXG-BlBtV3cx.js";import"./chunk-55IACEB6-mjdLMPLu.js";import"./chunk-KX2RTZJC-ByLbXYtr.js";var u={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{u as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as e,C as t}from"./chunk-WL4C6EOR-CMhwM8MW.js";import{_ as i}from"./index-BWUfRdC9.js";import"./chunk-FMBD7UC4-B-QgE8A5.js";import"./chunk-JSJVCQXG-BlBtV3cx.js";import"./chunk-55IACEB6-mjdLMPLu.js";import"./chunk-KX2RTZJC-ByLbXYtr.js";var u={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{u as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{b as r}from"./_baseUniq-CYmx81nY.js";var e=4;function a(o){return r(o,e)}export{a as c};
|