gspace 0.1.2 → 0.2.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/lib/bootstrap.js +27 -5
- package/package.json +1 -1
- package/release.json +1 -1
package/lib/bootstrap.js
CHANGED
|
@@ -9,7 +9,7 @@ import { Readable } from 'stream';
|
|
|
9
9
|
import { requestHTTPS, cancelBody } from './https.js';
|
|
10
10
|
import { extractBundle, validateFiles, verifyBundle } from './bundle.js';
|
|
11
11
|
|
|
12
|
-
const VERSION = '0.
|
|
12
|
+
const VERSION = '0.2.0';
|
|
13
13
|
const DAY = 24 * 60 * 60 * 1000;
|
|
14
14
|
const MAX_ARTIFACT = 256 * 1024 * 1024;
|
|
15
15
|
const nonce = () => randomBytes(12).toString('hex');
|
|
@@ -161,6 +161,11 @@ function artifact(value, source) {
|
|
|
161
161
|
const url = new URL(value.url, source);
|
|
162
162
|
if (source.protocol === 'https:' && url.protocol !== 'https:') throw new Error('Remote manifests cannot reference local or insecure artifacts.');
|
|
163
163
|
if (!['https:', 'file:'].includes(url.protocol)) throw new Error('Unsupported artifact URL.');
|
|
164
|
+
if (value.mirrors !== undefined && (!Array.isArray(value.mirrors) || value.mirrors.length > 3)) throw new Error('Invalid artifact mirrors.');
|
|
165
|
+
for (const mirror of value.mirrors || []) {
|
|
166
|
+
const parsed = new URL(mirror);
|
|
167
|
+
if (parsed.protocol !== 'https:' || parsed.username || parsed.password) throw new Error('Mirrors require HTTPS without credentials.');
|
|
168
|
+
}
|
|
164
169
|
return { ...value, url: url.href };
|
|
165
170
|
}
|
|
166
171
|
|
|
@@ -222,6 +227,15 @@ async function downloadRanges(value, handle, first, request) {
|
|
|
222
227
|
}
|
|
223
228
|
|
|
224
229
|
export async function downloadVerified(value, destination, transport = requestHTTPS) {
|
|
230
|
+
let failure;
|
|
231
|
+
for (const url of [value.url, ...(value.mirrors || [])]) {
|
|
232
|
+
try { return await downloadFromSource({ ...value, url }, destination, transport); }
|
|
233
|
+
catch (error) { failure = error; }
|
|
234
|
+
}
|
|
235
|
+
throw failure;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
async function downloadFromSource(value, destination, transport) {
|
|
225
239
|
if (!Number.isSafeInteger(value.size) || value.size <= 0 || value.size > MAX_ARTIFACT || !/^[a-f0-9]{64}$/.test(value.sha256)) throw new Error('Invalid release artifact metadata.');
|
|
226
240
|
const url = new URL(value.url);
|
|
227
241
|
const temporary = `${destination}.download-${nonce()}`;
|
|
@@ -367,7 +381,8 @@ export async function main(args, env = process.env) {
|
|
|
367
381
|
releaseLock = await lock(context.root);
|
|
368
382
|
runtime = await currentRuntime(context.root);
|
|
369
383
|
const config = JSON.parse(await fs.readFile(new URL('../release.json', import.meta.url), 'utf8'));
|
|
370
|
-
const
|
|
384
|
+
const locations = env.GSPACE_RELEASE_MANIFEST ? [env.GSPACE_RELEASE_MANIFEST] : [config.manifest, ...(config.fallbacks || [])].filter(Boolean);
|
|
385
|
+
const location = locations[0];
|
|
371
386
|
const forceUpdate = args[0] === '--update';
|
|
372
387
|
if (forceUpdate) args = args.slice(1);
|
|
373
388
|
const cacheFile = path.join(context.root, 'runtime', 'update.json');
|
|
@@ -377,9 +392,16 @@ export async function main(args, env = process.env) {
|
|
|
377
392
|
if (!location && !runtime) throw new Error('No release source configured. Set GSPACE_RELEASE_MANIFEST to a local manifest.json or HTTPS URL, or use GSPACE_CORE for a development build.');
|
|
378
393
|
if (location) {
|
|
379
394
|
try {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
395
|
+
let source, raw, manifest, sourceError;
|
|
396
|
+
for (const candidate of locations) {
|
|
397
|
+
try {
|
|
398
|
+
source = asURL(candidate);
|
|
399
|
+
raw = await fetchBytes(source, 1024 * 1024);
|
|
400
|
+
manifest = validateManifest(JSON.parse(raw.toString('utf8')), source);
|
|
401
|
+
break;
|
|
402
|
+
} catch (error) { sourceError = error; }
|
|
403
|
+
}
|
|
404
|
+
if (!manifest) throw sourceError;
|
|
383
405
|
const hash = createHash('sha256').update(raw).digest('hex');
|
|
384
406
|
if (!runtime || runtime.manifest_hash !== hash) {
|
|
385
407
|
if (!runtime) console.error(`Gspace is not installed on this workstation.\nUsing ${context.goinfre}`);
|
package/package.json
CHANGED
package/release.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"manifest":
|
|
1
|
+
{"manifest":"https://gspace-downloads.pages.dev/manifest.json","fallbacks":["https://github.com/Seraph919/gspace-releases/releases/latest/download/manifest.json"]}
|