signalk-backup 0.5.0 → 0.6.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 +35 -27
- package/package.json +4 -2
- package/plugin/config/image-tag.d.ts +1 -1
- package/plugin/config/image-tag.d.ts.map +1 -1
- package/plugin/config/image-tag.js +6 -13
- package/plugin/config/image-tag.js.map +1 -1
- package/plugin/config/schema.js +1 -1
- package/plugin/config/schema.js.map +1 -1
- package/plugin/database-export/staging-routes.d.ts +19 -0
- package/plugin/database-export/staging-routes.d.ts.map +1 -0
- package/plugin/database-export/staging-routes.js +205 -0
- package/plugin/database-export/staging-routes.js.map +1 -0
- package/plugin/index.d.ts.map +1 -1
- package/plugin/index.js +32 -2
- package/plugin/index.js.map +1 -1
- package/plugin/restore-host-write.d.ts +26 -0
- package/plugin/restore-host-write.d.ts.map +1 -0
- package/plugin/restore-host-write.js +363 -0
- package/plugin/restore-host-write.js.map +1 -0
- package/public/assets/{index-BbZnGesz.js → index-C8j20cZ-.js} +2 -2
- package/public/assets/{index-BbZnGesz.js.map → index-C8j20cZ-.js.map} +1 -1
- package/public/assets/main-B53J3gmZ.js +11 -0
- package/public/assets/main-B53J3gmZ.js.map +1 -0
- package/public/index.html +1 -1
- package/public/assets/main-Bb6YhYnz.js +0 -11
- package/public/assets/main-Bb6YhYnz.js.map +0 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { IRouter } from 'express';
|
|
2
|
+
export interface RestoreHostWriteOptions {
|
|
3
|
+
getUpstreamBase: () => string | null;
|
|
4
|
+
log?: (msg: string) => void;
|
|
5
|
+
}
|
|
6
|
+
export interface HostRestoreStatus {
|
|
7
|
+
state: 'idle' | 'preparing' | 'streaming' | 'extracting' | 'completed' | 'failed' | 'rolling_back' | 'rolled_back';
|
|
8
|
+
progress: number;
|
|
9
|
+
statusMessage: string;
|
|
10
|
+
error?: string;
|
|
11
|
+
backupId?: string;
|
|
12
|
+
sourcePath?: string;
|
|
13
|
+
targetPath?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function registerHostRestoreRoutes(router: IRouter, opts: RestoreHostWriteOptions): void;
|
|
16
|
+
interface ResolvedHostTarget {
|
|
17
|
+
/** Absolute path the bytes land at on disk. */
|
|
18
|
+
absoluteTarget: string;
|
|
19
|
+
/** Sibling path that holds the existing target during the rename
|
|
20
|
+
* swap; cleaned up on success, restored on failure. */
|
|
21
|
+
safetyPath: string;
|
|
22
|
+
}
|
|
23
|
+
export declare function resolveHostTarget(customPath: string, _isDir: boolean, sourcePath: string): ResolvedHostTarget;
|
|
24
|
+
export declare function resolveZipEntryPath(entryPath: string, targetDir: string): string | null;
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=restore-host-write.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restore-host-write.d.ts","sourceRoot":"","sources":["../src/restore-host-write.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAA;AAGzD,MAAM,WAAW,uBAAuB;IAEtC,eAAe,EAAE,MAAM,MAAM,GAAG,IAAI,CAAA;IACpC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAC5B;AAGD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EACD,MAAM,GACN,WAAW,GACX,WAAW,GACX,YAAY,GACZ,WAAW,GACX,QAAQ,GACR,cAAc,GACd,aAAa,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;IACrB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AA6BD,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,uBAAuB,GAAG,IAAI,CAqL9F;AAED,UAAU,kBAAkB;IAC1B,+CAA+C;IAC/C,cAAc,EAAE,MAAM,CAAA;IACtB;4DACwD;IACxD,UAAU,EAAE,MAAM,CAAA;CACnB;AAKD,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,OAAO,EACf,UAAU,EAAE,MAAM,GACjB,kBAAkB,CAWpB;AAqID,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASvF"}
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
// Plugin-side host-write restore — bypasses the container so the user can target paths it can't see.
|
|
2
|
+
import { createWriteStream } from 'node:fs';
|
|
3
|
+
import { mkdir, rename, rm, stat } from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { pipeline } from 'node:stream/promises';
|
|
6
|
+
import { Readable } from 'node:stream';
|
|
7
|
+
import unzipper from 'unzipper';
|
|
8
|
+
class HostRestoreState {
|
|
9
|
+
status = {
|
|
10
|
+
state: 'idle',
|
|
11
|
+
progress: 0,
|
|
12
|
+
statusMessage: ''
|
|
13
|
+
};
|
|
14
|
+
reset() {
|
|
15
|
+
this.status = { state: 'idle', progress: 0, statusMessage: '' };
|
|
16
|
+
}
|
|
17
|
+
isRunning() {
|
|
18
|
+
return ['preparing', 'streaming', 'extracting', 'rolling_back'].includes(this.status.state);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const state = new HostRestoreState();
|
|
22
|
+
export function registerHostRestoreRoutes(router, opts) {
|
|
23
|
+
router.get('/api/restore-partial-host/status', (_req, res) => {
|
|
24
|
+
res.json({
|
|
25
|
+
success: true,
|
|
26
|
+
data: state.status,
|
|
27
|
+
timestamp: new Date().toISOString()
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
router.post('/api/restore-partial-host/reset', (_req, res) => {
|
|
31
|
+
// Refuse to reset mid-flight — would clear the single-flight slot
|
|
32
|
+
// and let a second restore start while the first still has files
|
|
33
|
+
// open. Caller has to wait for the active restore to terminate.
|
|
34
|
+
if (state.isRunning()) {
|
|
35
|
+
res.status(409).json({
|
|
36
|
+
success: false,
|
|
37
|
+
error: {
|
|
38
|
+
code: 'RESTORE_IN_PROGRESS',
|
|
39
|
+
message: 'Cannot reset while a host-restore is in progress'
|
|
40
|
+
},
|
|
41
|
+
timestamp: new Date().toISOString()
|
|
42
|
+
});
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
state.reset();
|
|
46
|
+
res.json({
|
|
47
|
+
success: true,
|
|
48
|
+
data: { message: 'Host-restore state reset' },
|
|
49
|
+
timestamp: new Date().toISOString()
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
router.post('/api/restore-partial-host', async (req, res) => {
|
|
53
|
+
const body = req.body;
|
|
54
|
+
if (typeof body.backupId !== 'string' ||
|
|
55
|
+
typeof body.sourcePath !== 'string' ||
|
|
56
|
+
typeof body.customPath !== 'string' ||
|
|
57
|
+
typeof body.isDir !== 'boolean') {
|
|
58
|
+
res.status(400).json({
|
|
59
|
+
success: false,
|
|
60
|
+
error: {
|
|
61
|
+
code: 'INVALID_INPUT',
|
|
62
|
+
message: 'backupId, sourcePath, customPath, isDir are required'
|
|
63
|
+
},
|
|
64
|
+
timestamp: new Date().toISOString()
|
|
65
|
+
});
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// Reject empty customPath up front — an empty string would silently
|
|
69
|
+
// resolve to process.cwd() and write somewhere the user didn't ask.
|
|
70
|
+
if (body.customPath.trim().length === 0) {
|
|
71
|
+
res.status(400).json({
|
|
72
|
+
success: false,
|
|
73
|
+
error: { code: 'INVALID_INPUT', message: 'customPath must not be empty' },
|
|
74
|
+
timestamp: new Date().toISOString()
|
|
75
|
+
});
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
// Type-check confirmOverwrite if present: a non-boolean truthy
|
|
79
|
+
// value (e.g. the string "false" from a misbuilt form) would
|
|
80
|
+
// otherwise bypass the conflict probe and silently overwrite.
|
|
81
|
+
if ('confirmOverwrite' in body && typeof body.confirmOverwrite !== 'boolean') {
|
|
82
|
+
res.status(400).json({
|
|
83
|
+
success: false,
|
|
84
|
+
error: {
|
|
85
|
+
code: 'INVALID_INPUT',
|
|
86
|
+
message: 'confirmOverwrite must be a boolean when provided'
|
|
87
|
+
},
|
|
88
|
+
timestamp: new Date().toISOString()
|
|
89
|
+
});
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const { backupId, sourcePath, customPath, isDir, confirmOverwrite } = body;
|
|
93
|
+
// sourcePath safety: reject `..` segments and NUL bytes. No reject-list
|
|
94
|
+
// (package.json etc.) — the explicit point of host-restore is "copy
|
|
95
|
+
// anywhere I can write", so the in-container side-effect concerns
|
|
96
|
+
// don't apply.
|
|
97
|
+
if (sourcePath.includes('\0') || customPath.includes('\0')) {
|
|
98
|
+
res.status(400).json({
|
|
99
|
+
success: false,
|
|
100
|
+
error: { code: 'INVALID_INPUT', message: 'paths must not contain NUL bytes' },
|
|
101
|
+
timestamp: new Date().toISOString()
|
|
102
|
+
});
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (sourcePath.split('/').some((p) => p === '..')) {
|
|
106
|
+
res.status(400).json({
|
|
107
|
+
success: false,
|
|
108
|
+
error: { code: 'INVALID_INPUT', message: 'sourcePath must not contain ".." segments' },
|
|
109
|
+
timestamp: new Date().toISOString()
|
|
110
|
+
});
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (state.isRunning()) {
|
|
114
|
+
res.status(409).json({
|
|
115
|
+
success: false,
|
|
116
|
+
error: {
|
|
117
|
+
code: 'RESTORE_IN_PROGRESS',
|
|
118
|
+
message: 'A host-restore is already in progress'
|
|
119
|
+
},
|
|
120
|
+
timestamp: new Date().toISOString()
|
|
121
|
+
});
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const target = resolveHostTarget(customPath, isDir, sourcePath);
|
|
125
|
+
// Reserve the single-flight slot synchronously so a concurrent
|
|
126
|
+
// POST sees state.isRunning() === true before either request hits
|
|
127
|
+
// its first await. Any early-return path below clears the slot
|
|
128
|
+
// via state.reset() so the user can retry.
|
|
129
|
+
state.status = {
|
|
130
|
+
state: 'preparing',
|
|
131
|
+
progress: 0,
|
|
132
|
+
statusMessage: 'Preparing host-restore…',
|
|
133
|
+
backupId,
|
|
134
|
+
sourcePath,
|
|
135
|
+
targetPath: target.absoluteTarget
|
|
136
|
+
};
|
|
137
|
+
// Conflict probe — surface the existing entry so the UI shows a diff.
|
|
138
|
+
if (!confirmOverwrite) {
|
|
139
|
+
const existing = await safeStat(target.absoluteTarget);
|
|
140
|
+
if (existing) {
|
|
141
|
+
state.reset();
|
|
142
|
+
res.status(409).json({
|
|
143
|
+
success: false,
|
|
144
|
+
error: {
|
|
145
|
+
code: 'TARGET_EXISTS',
|
|
146
|
+
message: `Target '${target.absoluteTarget}' already exists; resubmit with confirmOverwrite=true to proceed`
|
|
147
|
+
},
|
|
148
|
+
data: {
|
|
149
|
+
conflict: {
|
|
150
|
+
targetPath: target.absoluteTarget,
|
|
151
|
+
mtime: existing.mtime.toISOString(),
|
|
152
|
+
size: existing.size
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
timestamp: new Date().toISOString()
|
|
156
|
+
});
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const base = opts.getUpstreamBase();
|
|
161
|
+
if (!base) {
|
|
162
|
+
state.reset();
|
|
163
|
+
res.status(503).json({
|
|
164
|
+
success: false,
|
|
165
|
+
error: { code: 'UPSTREAM_NOT_READY', message: 'backup-server not ready' },
|
|
166
|
+
timestamp: new Date().toISOString()
|
|
167
|
+
});
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
res.status(202).json({
|
|
171
|
+
success: true,
|
|
172
|
+
data: { started: true },
|
|
173
|
+
timestamp: new Date().toISOString()
|
|
174
|
+
});
|
|
175
|
+
runRestore({
|
|
176
|
+
backupId,
|
|
177
|
+
sourcePath,
|
|
178
|
+
isDir,
|
|
179
|
+
target,
|
|
180
|
+
upstreamBase: base,
|
|
181
|
+
log: opts.log
|
|
182
|
+
}).catch((err) => {
|
|
183
|
+
opts.log?.(`host-restore failed: ${errMsg(err)}`);
|
|
184
|
+
state.status = {
|
|
185
|
+
...state.status,
|
|
186
|
+
state: 'failed',
|
|
187
|
+
error: errMsg(err),
|
|
188
|
+
statusMessage: 'Host-restore failed'
|
|
189
|
+
};
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
// Mirror of the server's trailing-slash interpretation: if the user
|
|
194
|
+
// types `tmp/` the source basename is appended so a file restore lands
|
|
195
|
+
// at `tmp/<filename>` instead of overwriting `tmp` as a file.
|
|
196
|
+
export function resolveHostTarget(customPath, _isDir, sourcePath) {
|
|
197
|
+
const explicitDir = /[/\\]$/.test(customPath);
|
|
198
|
+
const stripped = explicitDir ? customPath.replace(/[/\\]+$/, '') : customPath;
|
|
199
|
+
const baseCustom = explicitDir && stripped === '' && path.isAbsolute(customPath) ? customPath : stripped;
|
|
200
|
+
const joined = path.isAbsolute(baseCustom) ? baseCustom : path.resolve(baseCustom);
|
|
201
|
+
const absoluteTarget = explicitDir ? path.join(joined, path.basename(sourcePath)) : joined;
|
|
202
|
+
return {
|
|
203
|
+
absoluteTarget,
|
|
204
|
+
safetyPath: makeSafetyPath(absoluteTarget)
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
function makeSafetyPath(targetAbs) {
|
|
208
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
209
|
+
return `${targetAbs}.partial-restore-backup-${stamp}`;
|
|
210
|
+
}
|
|
211
|
+
async function runRestore(ctx) {
|
|
212
|
+
let safetyStashed = null;
|
|
213
|
+
try {
|
|
214
|
+
// Stash any existing target so a failure mid-write can be rolled
|
|
215
|
+
// back. Same sibling-rename pattern as the server's partial-restore-
|
|
216
|
+
// service — atomic on the same filesystem.
|
|
217
|
+
const existing = await safeStat(ctx.target.absoluteTarget);
|
|
218
|
+
if (existing) {
|
|
219
|
+
await rename(ctx.target.absoluteTarget, ctx.target.safetyPath);
|
|
220
|
+
safetyStashed = ctx.target.safetyPath;
|
|
221
|
+
}
|
|
222
|
+
state.status = {
|
|
223
|
+
...state.status,
|
|
224
|
+
state: 'streaming',
|
|
225
|
+
progress: 25,
|
|
226
|
+
statusMessage: 'Downloading from backup-server…'
|
|
227
|
+
};
|
|
228
|
+
const url = ctx.upstreamBase.replace(/\/$/, '') +
|
|
229
|
+
`/api/backups/${encodeURIComponent(ctx.backupId)}/download-subtree?path=${encodeURIComponent(ctx.sourcePath)}`;
|
|
230
|
+
const upstream = await fetch(url);
|
|
231
|
+
if (!upstream.ok || !upstream.body) {
|
|
232
|
+
const text = await upstream.text().catch(() => '');
|
|
233
|
+
throw new Error(`upstream ${upstream.status}: ${text.slice(0, 200)}`);
|
|
234
|
+
}
|
|
235
|
+
const nodeStream = Readable.fromWeb(upstream.body);
|
|
236
|
+
if (ctx.isDir) {
|
|
237
|
+
state.status = {
|
|
238
|
+
...state.status,
|
|
239
|
+
state: 'extracting',
|
|
240
|
+
progress: 60,
|
|
241
|
+
statusMessage: 'Extracting ZIP…'
|
|
242
|
+
};
|
|
243
|
+
await mkdir(ctx.target.absoluteTarget, { recursive: true });
|
|
244
|
+
// Per-entry path-traversal guard: unzipper.Extract uses a string
|
|
245
|
+
// prefix check that doesn't catch ../ sequences inside an entry
|
|
246
|
+
// name. Parse the ZIP and resolve each entry against the target;
|
|
247
|
+
// reject anything that escapes via path.relative starting with '..'.
|
|
248
|
+
await extractZipSafely(nodeStream, ctx.target.absoluteTarget);
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
state.status = {
|
|
252
|
+
...state.status,
|
|
253
|
+
state: 'streaming',
|
|
254
|
+
progress: 60,
|
|
255
|
+
statusMessage: 'Writing file…'
|
|
256
|
+
};
|
|
257
|
+
// Single-file source. Make sure the parent exists; absolute or
|
|
258
|
+
// relative the user gave us, the dirname may not.
|
|
259
|
+
await mkdir(path.dirname(ctx.target.absoluteTarget), { recursive: true });
|
|
260
|
+
await pipeline(nodeStream, createWriteStream(ctx.target.absoluteTarget));
|
|
261
|
+
}
|
|
262
|
+
state.status = {
|
|
263
|
+
...state.status,
|
|
264
|
+
state: 'completed',
|
|
265
|
+
progress: 100,
|
|
266
|
+
statusMessage: 'Host-restore complete'
|
|
267
|
+
};
|
|
268
|
+
// Clean up the safety stash on success — best-effort.
|
|
269
|
+
if (safetyStashed) {
|
|
270
|
+
await rm(safetyStashed, { recursive: true, force: true }).catch(() => undefined);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
catch (err) {
|
|
274
|
+
const message = errMsg(err);
|
|
275
|
+
ctx.log?.(`host-restore error: ${message}`);
|
|
276
|
+
// Scrub partial output unconditionally — a failed fresh-target restore would otherwise leak bytes.
|
|
277
|
+
await rm(ctx.target.absoluteTarget, { recursive: true, force: true }).catch(() => undefined);
|
|
278
|
+
if (safetyStashed) {
|
|
279
|
+
state.status = {
|
|
280
|
+
...state.status,
|
|
281
|
+
state: 'rolling_back',
|
|
282
|
+
statusMessage: 'Rolling back…'
|
|
283
|
+
};
|
|
284
|
+
try {
|
|
285
|
+
await rename(safetyStashed, ctx.target.absoluteTarget);
|
|
286
|
+
state.status = {
|
|
287
|
+
...state.status,
|
|
288
|
+
state: 'rolled_back',
|
|
289
|
+
error: message,
|
|
290
|
+
statusMessage: 'Rolled back to previous target'
|
|
291
|
+
};
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
catch (rollbackErr) {
|
|
295
|
+
ctx.log?.(`host-restore rollback failed: ${errMsg(rollbackErr)}`);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
state.status = {
|
|
299
|
+
...state.status,
|
|
300
|
+
state: 'failed',
|
|
301
|
+
error: message,
|
|
302
|
+
statusMessage: 'Host-restore failed'
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
async function safeStat(p) {
|
|
307
|
+
try {
|
|
308
|
+
const s = await stat(p);
|
|
309
|
+
return { mtime: s.mtime, size: s.size };
|
|
310
|
+
}
|
|
311
|
+
catch {
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
// Resolve a ZIP entry path against the target directory. Returns the
|
|
316
|
+
// absolute destination when the entry is contained inside targetDir,
|
|
317
|
+
// or null when the entry name is empty, contains '..' segments, or
|
|
318
|
+
// the resolved path otherwise escapes via path.relative. We reject
|
|
319
|
+
// '..' outright (rather than silently dropping it) so a malicious
|
|
320
|
+
// snapshot can't smuggle data into unintended locations under the
|
|
321
|
+
// target — even if the resolved path stays inside the root, the
|
|
322
|
+
// shape of the entry path is suspicious enough to refuse.
|
|
323
|
+
export function resolveZipEntryPath(entryPath, targetDir) {
|
|
324
|
+
const resolvedTarget = path.resolve(targetDir);
|
|
325
|
+
const parts = entryPath.split(/[/\\]/).filter((p) => p.length > 0);
|
|
326
|
+
if (parts.length === 0)
|
|
327
|
+
return null;
|
|
328
|
+
if (parts.some((p) => p === '..'))
|
|
329
|
+
return null;
|
|
330
|
+
const dest = path.resolve(resolvedTarget, parts.join('/'));
|
|
331
|
+
const rel = path.relative(resolvedTarget, dest);
|
|
332
|
+
if (rel.startsWith('..') || path.isAbsolute(rel))
|
|
333
|
+
return null;
|
|
334
|
+
return dest;
|
|
335
|
+
}
|
|
336
|
+
// Per-entry path validation while extracting the server's directory
|
|
337
|
+
// ZIP. unzipper.Extract uses a string-prefix check that doesn't catch
|
|
338
|
+
// `../` inside entry names; consume entries through Parse so we can
|
|
339
|
+
// resolve each path ourselves and reject anything that escapes.
|
|
340
|
+
async function extractZipSafely(input, targetDir) {
|
|
341
|
+
const resolvedTarget = path.resolve(targetDir);
|
|
342
|
+
await pipeline(input, unzipper.Parse(), async (parsed) => {
|
|
343
|
+
for await (const entry of parsed) {
|
|
344
|
+
const dest = resolveZipEntryPath(entry.path, resolvedTarget);
|
|
345
|
+
if (!dest) {
|
|
346
|
+
entry.autodrain();
|
|
347
|
+
throw new Error(`ZIP entry "${entry.path}" escapes the target directory`);
|
|
348
|
+
}
|
|
349
|
+
if (entry.type === 'Directory') {
|
|
350
|
+
await mkdir(dest, { recursive: true });
|
|
351
|
+
entry.autodrain();
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
await mkdir(path.dirname(dest), { recursive: true });
|
|
355
|
+
await pipeline(entry, createWriteStream(dest));
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
function errMsg(err) {
|
|
361
|
+
return err instanceof Error ? err.message : String(err);
|
|
362
|
+
}
|
|
363
|
+
//# sourceMappingURL=restore-host-write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restore-host-write.js","sourceRoot":"","sources":["../src/restore-host-write.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var e=`modulepreload`,t=function(e){return`/signalk-backup/`+e},n={},r=function(r,i,a){let o=Promise.resolve();if(i&&i.length>0){let r=document.getElementsByTagName(`link`),s=document.querySelector(`meta[property=csp-nonce]`),c=s?.nonce||s?.getAttribute(`nonce`);function l(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}o=l(i.map(i=>{if(i=t(i,a),i in n)return;n[i]=!0;let o=i.endsWith(`.css`),s=o?`[rel="stylesheet"]`:``;if(a)for(let e=r.length-1;e>=0;e--){let t=r[e];if(t.href===i&&(!o||t.rel===`stylesheet`))return}else if(document.querySelector(`link[href="${i}"]${s}`))return;let l=document.createElement(`link`);if(l.rel=o?`stylesheet`:e,o||(l.as=`script`),l.crossOrigin=``,l.href=i,c&&l.setAttribute(`nonce`,c),document.head.appendChild(l),o)return new Promise((e,t)=>{l.addEventListener(`load`,e),l.addEventListener(`error`,()=>t(Error(`Unable to preload CSS for ${i}`)))})}))}function s(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return o.then(e=>{for(let t of e||[])t.status===`rejected`&&s(t.reason);return r().catch(s)})};async function i(){let e=await fetch(`/admin/.vite/manifest.json`);if(!e.ok)return;let t=await e.json(),n=new Set;for(let e of Object.values(t))if(e){for(let t of e.css??[])n.add(t);typeof e.file==`string`&&e.file.endsWith(`.css`)&&n.add(e.file)}await Promise.all([...n].map(e=>new Promise(t=>{let n=document.createElement(`link`);n.rel=`stylesheet`,n.href=`/admin/`+e,n.onload=t,n.onerror=t,document.head.appendChild(n)})))}try{await i()}catch(e){console.warn(`signalk-backup: admin CSS not available`,e)}finally{await r(()=>import(`./main-
|
|
2
|
-
//# sourceMappingURL=index-
|
|
1
|
+
(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var e=`modulepreload`,t=function(e){return`/signalk-backup/`+e},n={},r=function(r,i,a){let o=Promise.resolve();if(i&&i.length>0){let r=document.getElementsByTagName(`link`),s=document.querySelector(`meta[property=csp-nonce]`),c=s?.nonce||s?.getAttribute(`nonce`);function l(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}o=l(i.map(i=>{if(i=t(i,a),i in n)return;n[i]=!0;let o=i.endsWith(`.css`),s=o?`[rel="stylesheet"]`:``;if(a)for(let e=r.length-1;e>=0;e--){let t=r[e];if(t.href===i&&(!o||t.rel===`stylesheet`))return}else if(document.querySelector(`link[href="${i}"]${s}`))return;let l=document.createElement(`link`);if(l.rel=o?`stylesheet`:e,o||(l.as=`script`),l.crossOrigin=``,l.href=i,c&&l.setAttribute(`nonce`,c),document.head.appendChild(l),o)return new Promise((e,t)=>{l.addEventListener(`load`,e),l.addEventListener(`error`,()=>t(Error(`Unable to preload CSS for ${i}`)))})}))}function s(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return o.then(e=>{for(let t of e||[])t.status===`rejected`&&s(t.reason);return r().catch(s)})};async function i(){let e=await fetch(`/admin/.vite/manifest.json`);if(!e.ok)return;let t=await e.json(),n=new Set;for(let e of Object.values(t))if(e){for(let t of e.css??[])n.add(t);typeof e.file==`string`&&e.file.endsWith(`.css`)&&n.add(e.file)}await Promise.all([...n].map(e=>new Promise(t=>{let n=document.createElement(`link`);n.rel=`stylesheet`,n.href=`/admin/`+e,n.onload=t,n.onerror=t,document.head.appendChild(n)})))}try{await i()}catch(e){console.warn(`signalk-backup: admin CSS not available`,e)}finally{await r(()=>import(`./main-B53J3gmZ.js`),[])}
|
|
2
|
+
//# sourceMappingURL=index-C8j20cZ-.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"mappings":"m2DACM,eAAe,GAAiB,CAC9B,IAAM,EAAM,MAAM,MAAM,4BAA4B,EACpD,GAAI,CAAC,EAAI,GAAI,OACb,IAAM,EAAW,MAAM,EAAI,KAAK,EAC1B,EAAW,IAAI,IAMrB,IAAK,IAAM,KAAS,OAAO,OAAO,CAAQ,EACnC,KACL,KAAK,IAAM,KAAO,EAAM,KAAO,CAAC,EAAG,EAAS,IAAI,CAAG,EAC/C,OAAO,EAAM,MAAS,UAAY,EAAM,KAAK,SAAS,MAAM,GAC9D,EAAS,IAAI,EAAM,IAAI,CAF0B,CAKrD,MAAM,QAAQ,IACZ,CAAC,GAAG,CAAQ,EAAE,IACX,GACC,IAAI,QAAS,GAAY,CACvB,IAAM,EAAO,SAAS,cAAc,MAAM,EAC1C,EAAK,IAAM,aACX,EAAK,KAAO,UAAY,EACxB,EAAK,OAAS,EACd,EAAK,QAAU,EACf,SAAS,KAAK,YAAY,CAAI,CAChC,CAAC,CACL,CACF,CACF,CAEA,GAAI,CACF,MAAM,EAAe,CACvB,OAAS,EAAK,CACZ,QAAQ,KAAK,0CAA2C,CAAG,CAC7D,QAAU,CACR,YAAM,OAAO,yBACf","names":[],"ignoreList":[],"sources":["../../webapp/index.html?html-proxy&index=0.js"],"sourcesContent":["\n async function injectAdminCss() {\n const res = await fetch('/admin/.vite/manifest.json')\n if (!res.ok) return\n const manifest = await res.json()\n const cssFiles = new Set()\n // Two shapes are common: an entry whose `css` array lists its\n // stylesheet imports, OR a top-level entry whose `file` itself\n // ends in `.css` (when Vite extracts a global stylesheet). The\n // current SignalK admin uses the second shape; older builds and\n // the docs example use the first. Cover both.\n for (const entry of Object.values(manifest)) {\n if (!entry) continue\n for (const css of entry.css ?? []) cssFiles.add(css)\n if (typeof entry.file === 'string' && entry.file.endsWith('.css')) {\n cssFiles.add(entry.file)\n }\n }\n await Promise.all(\n [...cssFiles].map(\n (css) =>\n new Promise((resolve) => {\n const link = document.createElement('link')\n link.rel = 'stylesheet'\n link.href = '/admin/' + css\n link.onload = resolve\n link.onerror = resolve\n document.head.appendChild(link)\n })\n )\n )\n }\n\n try {\n await injectAdminCss()\n } catch (err) {\n console.warn('signalk-backup: admin CSS not available', err)\n } finally {\n await import('./src/main.tsx')\n }\n "],"file":"index-
|
|
1
|
+
{"version":3,"mappings":"m2DACM,eAAe,GAAiB,CAC9B,IAAM,EAAM,MAAM,MAAM,4BAA4B,EACpD,GAAI,CAAC,EAAI,GAAI,OACb,IAAM,EAAW,MAAM,EAAI,KAAK,EAC1B,EAAW,IAAI,IAMrB,IAAK,IAAM,KAAS,OAAO,OAAO,CAAQ,EACnC,KACL,KAAK,IAAM,KAAO,EAAM,KAAO,CAAC,EAAG,EAAS,IAAI,CAAG,EAC/C,OAAO,EAAM,MAAS,UAAY,EAAM,KAAK,SAAS,MAAM,GAC9D,EAAS,IAAI,EAAM,IAAI,CAF0B,CAKrD,MAAM,QAAQ,IACZ,CAAC,GAAG,CAAQ,EAAE,IACX,GACC,IAAI,QAAS,GAAY,CACvB,IAAM,EAAO,SAAS,cAAc,MAAM,EAC1C,EAAK,IAAM,aACX,EAAK,KAAO,UAAY,EACxB,EAAK,OAAS,EACd,EAAK,QAAU,EACf,SAAS,KAAK,YAAY,CAAI,CAChC,CAAC,CACL,CACF,CACF,CAEA,GAAI,CACF,MAAM,EAAe,CACvB,OAAS,EAAK,CACZ,QAAQ,KAAK,0CAA2C,CAAG,CAC7D,QAAU,CACR,YAAM,OAAO,yBACf","names":[],"ignoreList":[],"sources":["../../webapp/index.html?html-proxy&index=0.js"],"sourcesContent":["\n async function injectAdminCss() {\n const res = await fetch('/admin/.vite/manifest.json')\n if (!res.ok) return\n const manifest = await res.json()\n const cssFiles = new Set()\n // Two shapes are common: an entry whose `css` array lists its\n // stylesheet imports, OR a top-level entry whose `file` itself\n // ends in `.css` (when Vite extracts a global stylesheet). The\n // current SignalK admin uses the second shape; older builds and\n // the docs example use the first. Cover both.\n for (const entry of Object.values(manifest)) {\n if (!entry) continue\n for (const css of entry.css ?? []) cssFiles.add(css)\n if (typeof entry.file === 'string' && entry.file.endsWith('.css')) {\n cssFiles.add(entry.file)\n }\n }\n await Promise.all(\n [...cssFiles].map(\n (css) =>\n new Promise((resolve) => {\n const link = document.createElement('link')\n link.rel = 'stylesheet'\n link.href = '/admin/' + css\n link.onload = resolve\n link.onerror = resolve\n document.head.appendChild(link)\n })\n )\n )\n }\n\n try {\n await injectAdminCss()\n } catch (err) {\n console.warn('signalk-backup: admin CSS not available', err)\n } finally {\n await import('./src/main.tsx')\n }\n "],"file":"index-C8j20cZ-.js"}
|