@try-works/dsh-model-as-tool 0.3.6 → 0.4.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/client/client.model-tools.js +22 -0
- package/client/index.js +40 -2
- package/lib/extension-dependencies.d.ts +129 -1
- package/lib/extension-dependencies.d.ts.map +1 -1
- package/lib/extension-dependencies.js +489 -0
- package/lib/extensions-api.d.ts +4 -0
- package/lib/extensions-api.d.ts.map +1 -1
- package/lib/extensions-service.d.ts +43 -10
- package/lib/extensions-service.d.ts.map +1 -1
- package/lib/extensions-service.js +215 -39
- package/lib/index.d.ts +21 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +19 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/index.d.ts +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/index.d.ts.map +1 -1
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/index.js +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/archive.d.ts.map +1 -1
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/archive.js +12 -6
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/tar-gzip-source.d.ts +44 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/tar-gzip-source.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/tar-gzip-source.js +243 -0
- package/package.json +1 -1
- package/remote/spec.mjs +24 -1
|
@@ -47,6 +47,10 @@ import AdmZip from 'adm-zip';
|
|
|
47
47
|
import { createZipArchiveSource, DEFAULT_ARCHIVE_LIMITS, digestInstalledContent, ManagementError, refuseInstallScripts, } from '@try-works/tool-mode-extension-sdk';
|
|
48
48
|
/** A package identity: one optional scope segment, then one name segment. */
|
|
49
49
|
const PACKAGE_ID = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/i;
|
|
50
|
+
/** A message from an arbitrary thrown value. */
|
|
51
|
+
function messageOf(error) {
|
|
52
|
+
return error instanceof Error ? error.message : String(error);
|
|
53
|
+
}
|
|
50
54
|
/**
|
|
51
55
|
* The dependency archive byte cap.
|
|
52
56
|
*
|
|
@@ -366,4 +370,489 @@ export function createFirstPartyDependencyGraph(options) {
|
|
|
366
370
|
}
|
|
367
371
|
/** Re-export for callers that want the size bound wording. */
|
|
368
372
|
export { DEFAULT_ARCHIVE_LIMITS };
|
|
373
|
+
// ============================================================================
|
|
374
|
+
// npm registry installs (task-104)
|
|
375
|
+
// ============================================================================
|
|
376
|
+
/** The default npm registry. */
|
|
377
|
+
export const DEFAULT_REGISTRY_URL = 'https://registry.npmjs.org/';
|
|
378
|
+
/** Metadata response cap (a packument is JSON; 16 MiB is generous for one package). */
|
|
379
|
+
const MAX_REGISTRY_METADATA_BYTES = 16 * 1024 * 1024;
|
|
380
|
+
/** A named registry failure. */
|
|
381
|
+
export class RegistryError extends Error {
|
|
382
|
+
name = 'RegistryError';
|
|
383
|
+
code;
|
|
384
|
+
/** Whether a directory fallback may be considered under `auto`. */
|
|
385
|
+
transport;
|
|
386
|
+
constructor(code, message, options) {
|
|
387
|
+
super(message, options?.cause === undefined ? undefined : { cause: options.cause });
|
|
388
|
+
this.code = code;
|
|
389
|
+
this.transport = options?.transport === true;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
/** Normalize a registry base URL, or '' when unconfigured. */
|
|
393
|
+
function normalizeRegistryUrl(url) {
|
|
394
|
+
const trimmed = url.trim();
|
|
395
|
+
if (trimmed.length === 0)
|
|
396
|
+
return '';
|
|
397
|
+
return trimmed.endsWith('/') ? trimmed.slice(0, -1) : trimmed;
|
|
398
|
+
}
|
|
399
|
+
/** Encode a package name for the registry path (`@scope%2fname`). */
|
|
400
|
+
function encodePackageName(name) {
|
|
401
|
+
// npm encodes scoped names' slash as %2f and leaves the leading @ readable.
|
|
402
|
+
return name.startsWith('@') ? name.replace('/', '%2f') : encodeURIComponent(name);
|
|
403
|
+
}
|
|
404
|
+
/** Read a response body with a hard byte cap enforced BEFORE allocation grows unbounded. */
|
|
405
|
+
async function readBoundedBody(response, maxBytes) {
|
|
406
|
+
const declared = Number(response.headers.get('content-length') ?? Number.NaN);
|
|
407
|
+
if (Number.isFinite(declared) && declared > maxBytes) {
|
|
408
|
+
await response.body?.cancel();
|
|
409
|
+
throw new RegistryError('registry-tarball-too-large', `the response declares ${declared} bytes, over the ${maxBytes}-byte cap`);
|
|
410
|
+
}
|
|
411
|
+
if (response.body === null) {
|
|
412
|
+
const buffer = new Uint8Array(await response.arrayBuffer());
|
|
413
|
+
if (buffer.byteLength > maxBytes)
|
|
414
|
+
throw new RegistryError('registry-tarball-too-large', `the response is ${buffer.byteLength} bytes, over the ${maxBytes}-byte cap`);
|
|
415
|
+
return buffer;
|
|
416
|
+
}
|
|
417
|
+
const reader = response.body.getReader();
|
|
418
|
+
const chunks = [];
|
|
419
|
+
let total = 0;
|
|
420
|
+
for (;;) {
|
|
421
|
+
const { done, value } = await reader.read();
|
|
422
|
+
if (done)
|
|
423
|
+
break;
|
|
424
|
+
total += value.byteLength;
|
|
425
|
+
if (total > maxBytes) {
|
|
426
|
+
await reader.cancel();
|
|
427
|
+
throw new RegistryError('registry-tarball-too-large', `the response is over the ${maxBytes}-byte cap`);
|
|
428
|
+
}
|
|
429
|
+
chunks.push(value);
|
|
430
|
+
}
|
|
431
|
+
const joined = new Uint8Array(total);
|
|
432
|
+
let offset = 0;
|
|
433
|
+
for (const chunk of chunks) {
|
|
434
|
+
joined.set(chunk, offset);
|
|
435
|
+
offset += chunk.byteLength;
|
|
436
|
+
}
|
|
437
|
+
return joined;
|
|
438
|
+
}
|
|
439
|
+
/** Parse `1.2.3`, `v1.2.3`, `1.2.3-rc.1`, tolerating a build suffix. */
|
|
440
|
+
function parseVersion(text) {
|
|
441
|
+
const match = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(text.trim());
|
|
442
|
+
if (match === null)
|
|
443
|
+
return undefined;
|
|
444
|
+
const prerelease = match[4] === undefined
|
|
445
|
+
? []
|
|
446
|
+
: match[4].split('.').map(part => (/^\d+$/.test(part) ? Number(part) : part));
|
|
447
|
+
return {
|
|
448
|
+
major: Number(match[1]),
|
|
449
|
+
minor: Number(match[2]),
|
|
450
|
+
patch: Number(match[3]),
|
|
451
|
+
prerelease,
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
/** Compare two parsed versions by semver precedence. */
|
|
455
|
+
function compareVersions(left, right) {
|
|
456
|
+
for (const key of ['major', 'minor', 'patch']) {
|
|
457
|
+
if (left[key] !== right[key])
|
|
458
|
+
return left[key] < right[key] ? -1 : 1;
|
|
459
|
+
}
|
|
460
|
+
if (left.prerelease.length === 0 && right.prerelease.length === 0)
|
|
461
|
+
return 0;
|
|
462
|
+
if (left.prerelease.length === 0)
|
|
463
|
+
return 1;
|
|
464
|
+
if (right.prerelease.length === 0)
|
|
465
|
+
return -1;
|
|
466
|
+
for (let index = 0; index < Math.max(left.prerelease.length, right.prerelease.length); index += 1) {
|
|
467
|
+
const leftPart = left.prerelease[index];
|
|
468
|
+
const rightPart = right.prerelease[index];
|
|
469
|
+
if (leftPart === undefined)
|
|
470
|
+
return -1;
|
|
471
|
+
if (rightPart === undefined)
|
|
472
|
+
return 1;
|
|
473
|
+
if (leftPart === rightPart)
|
|
474
|
+
continue;
|
|
475
|
+
if (typeof leftPart === 'number' && typeof rightPart === 'number')
|
|
476
|
+
return leftPart < rightPart ? -1 : 1;
|
|
477
|
+
if (typeof leftPart === 'number')
|
|
478
|
+
return -1;
|
|
479
|
+
if (typeof rightPart === 'number')
|
|
480
|
+
return 1;
|
|
481
|
+
return leftPart < rightPart ? -1 : 1;
|
|
482
|
+
}
|
|
483
|
+
return 0;
|
|
484
|
+
}
|
|
485
|
+
/** Build a comparator at an exact position, or undefined when the version is not numeric. */
|
|
486
|
+
function comparatorAt(operator, major, minor = 0, patch = 0) {
|
|
487
|
+
return { operator, version: { major, minor, patch, prerelease: [] } };
|
|
488
|
+
}
|
|
489
|
+
/** Parse the numeric parts of a range token; `undefined` marks a wildcard part. */
|
|
490
|
+
function parsePartial(text) {
|
|
491
|
+
const parts = text.split('.');
|
|
492
|
+
if (parts.length > 3)
|
|
493
|
+
return undefined;
|
|
494
|
+
const numbers = [];
|
|
495
|
+
for (const part of parts) {
|
|
496
|
+
if (part === '' || part === 'x' || part === 'X' || part === '*') {
|
|
497
|
+
numbers.push(undefined);
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
if (!/^\d+$/.test(part))
|
|
501
|
+
return undefined;
|
|
502
|
+
numbers.push(Number(part));
|
|
503
|
+
}
|
|
504
|
+
return { major: numbers[0], minor: numbers[1], patch: numbers[2] };
|
|
505
|
+
}
|
|
506
|
+
/** Expand one range token into comparators, or undefined when it cannot be parsed. */
|
|
507
|
+
function expandToken(token) {
|
|
508
|
+
const match = /^(>=|<=|>|<|=|\^|~)?(.*)$/.exec(token);
|
|
509
|
+
if (match === null)
|
|
510
|
+
return undefined;
|
|
511
|
+
// SAFETY: the only strings the capture group can contain are the three prefix
|
|
512
|
+
// characters matched by the pattern, listed in the union below.
|
|
513
|
+
const operator = (match[1] ?? '');
|
|
514
|
+
const rest = match[2] ?? '';
|
|
515
|
+
if (rest === '' || rest === '*' || rest === 'x' || rest === 'X' || rest === 'latest') {
|
|
516
|
+
return operator === '' || operator === '=' ? [] : undefined;
|
|
517
|
+
}
|
|
518
|
+
const partial = parsePartial(rest);
|
|
519
|
+
if (partial === undefined)
|
|
520
|
+
return undefined;
|
|
521
|
+
const { major, minor, patch } = partial;
|
|
522
|
+
if (major === undefined)
|
|
523
|
+
return []; // wildcard major
|
|
524
|
+
if (operator === '^') {
|
|
525
|
+
if (minor === undefined || (minor === 0 && patch === undefined)) {
|
|
526
|
+
return major === 0
|
|
527
|
+
? [comparatorAt('>=', 0, 0, 0), comparatorAt('<', 0, 1, 0)]
|
|
528
|
+
: [comparatorAt('>=', major, 0, 0), comparatorAt('<', major + 1, 0, 0)];
|
|
529
|
+
}
|
|
530
|
+
if (patch === undefined) {
|
|
531
|
+
return major === 0
|
|
532
|
+
? [comparatorAt('>=', 0, minor, 0), comparatorAt('<', 0, minor + 1, 0)]
|
|
533
|
+
: [comparatorAt('>=', major, minor, 0), comparatorAt('<', major + 1, 0, 0)];
|
|
534
|
+
}
|
|
535
|
+
const lower = comparatorAt('>=', major, minor, patch);
|
|
536
|
+
if (major > 0)
|
|
537
|
+
return [lower, comparatorAt('<', major + 1, 0, 0)];
|
|
538
|
+
if (minor > 0)
|
|
539
|
+
return [lower, comparatorAt('<', 0, minor + 1, 0)];
|
|
540
|
+
return [lower, comparatorAt('<', 0, 0, patch + 1)];
|
|
541
|
+
}
|
|
542
|
+
if (operator === '~') {
|
|
543
|
+
if (minor === undefined)
|
|
544
|
+
return [comparatorAt('>=', major, 0, 0), comparatorAt('<', major + 1, 0, 0)];
|
|
545
|
+
return [comparatorAt('>=', major, minor, patch ?? 0), comparatorAt('<', major, minor + 1, 0)];
|
|
546
|
+
}
|
|
547
|
+
if (operator === '' || operator === '=') {
|
|
548
|
+
if (patch !== undefined)
|
|
549
|
+
return [comparatorAt('=', major, minor ?? 0, patch)];
|
|
550
|
+
if (minor !== undefined)
|
|
551
|
+
return [comparatorAt('>=', major, minor, 0), comparatorAt('<', major, minor + 1, 0)];
|
|
552
|
+
return [comparatorAt('>=', major, 0, 0), comparatorAt('<', major + 1, 0, 0)];
|
|
553
|
+
}
|
|
554
|
+
if (patch !== undefined)
|
|
555
|
+
return [comparatorAt(operator, major, minor ?? 0, patch)];
|
|
556
|
+
if (minor !== undefined) {
|
|
557
|
+
if (operator === '>')
|
|
558
|
+
return [comparatorAt('>=', major, minor + 1, 0)];
|
|
559
|
+
if (operator === '<=')
|
|
560
|
+
return [comparatorAt('<', major, minor + 1, 0)];
|
|
561
|
+
return [comparatorAt(operator, major, minor, 0)];
|
|
562
|
+
}
|
|
563
|
+
if (operator === '>')
|
|
564
|
+
return [comparatorAt('>=', major + 1, 0, 0)];
|
|
565
|
+
if (operator === '<=')
|
|
566
|
+
return [comparatorAt('<', major + 1, 0, 0)];
|
|
567
|
+
return [comparatorAt(operator, major, 0, 0)];
|
|
568
|
+
}
|
|
569
|
+
/** Expand one `||` alternative of a range into comparators. */
|
|
570
|
+
function expandRange(alternative) {
|
|
571
|
+
const hyphen = /^\s*(\S+)\s+-\s+(\S+)\s*$/.exec(alternative);
|
|
572
|
+
if (hyphen !== null) {
|
|
573
|
+
const lower = parsePartial(hyphen[1] ?? '');
|
|
574
|
+
const upper = parsePartial(hyphen[2] ?? '');
|
|
575
|
+
if (lower === undefined || upper === undefined || lower.major === undefined || upper.major === undefined)
|
|
576
|
+
return undefined;
|
|
577
|
+
const comparators = [
|
|
578
|
+
comparatorAt('>=', lower.major, lower.minor ?? 0, lower.patch ?? 0),
|
|
579
|
+
];
|
|
580
|
+
if (upper.patch !== undefined)
|
|
581
|
+
comparators.push(comparatorAt('<=', upper.major, upper.minor ?? 0, upper.patch));
|
|
582
|
+
else if (upper.minor !== undefined)
|
|
583
|
+
comparators.push(comparatorAt('<', upper.major, upper.minor + 1, 0));
|
|
584
|
+
else
|
|
585
|
+
comparators.push(comparatorAt('<', upper.major + 1, 0, 0));
|
|
586
|
+
return comparators;
|
|
587
|
+
}
|
|
588
|
+
const comparators = [];
|
|
589
|
+
for (const token of alternative.split(/\s+/).filter(part => part.length > 0)) {
|
|
590
|
+
const expanded = expandToken(token);
|
|
591
|
+
if (expanded === undefined)
|
|
592
|
+
return undefined;
|
|
593
|
+
comparators.push(...expanded);
|
|
594
|
+
}
|
|
595
|
+
return comparators;
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Whether one published version satisfies a semver range.
|
|
599
|
+
*
|
|
600
|
+
* Supported: exact versions, `^`, `~`, x-ranges (`1.x`, `1.2`), comparison
|
|
601
|
+
* operators (`>=`, `>`, `<=`, `<`, `=`), hyphen ranges, `||`, and `*`. NOT
|
|
602
|
+
* supported (refused rather than guessed): prerelease-only ranges and npm's
|
|
603
|
+
* `tag:` protocol. A prerelease version only matches a range that itself names a
|
|
604
|
+
* prerelease.
|
|
605
|
+
* @param versionText - the published version.
|
|
606
|
+
* @param rangeText - the requested range.
|
|
607
|
+
* @returns whether the version satisfies the range.
|
|
608
|
+
*/
|
|
609
|
+
export function satisfiesRegistryRange(versionText, rangeText) {
|
|
610
|
+
const version = parseVersion(versionText);
|
|
611
|
+
if (version === undefined)
|
|
612
|
+
return false;
|
|
613
|
+
if (version.prerelease.length > 0 && !/\d+\.\d+\.\d+-/.test(rangeText))
|
|
614
|
+
return false;
|
|
615
|
+
const alternatives = rangeText.split('||').map(part => part.trim()).filter(part => part.length > 0);
|
|
616
|
+
const effective = alternatives.length === 0 ? ['*'] : alternatives;
|
|
617
|
+
return effective.some(alternative => {
|
|
618
|
+
if (alternative === '*' || alternative === 'x' || alternative === 'X' || alternative === 'latest')
|
|
619
|
+
return true;
|
|
620
|
+
const comparators = expandRange(alternative);
|
|
621
|
+
if (comparators === undefined)
|
|
622
|
+
return false;
|
|
623
|
+
return comparators.every(comparator => {
|
|
624
|
+
const comparison = compareVersions(version, comparator.version);
|
|
625
|
+
switch (comparator.operator) {
|
|
626
|
+
case '=': return comparison === 0;
|
|
627
|
+
case '>': return comparison > 0;
|
|
628
|
+
case '>=': return comparison >= 0;
|
|
629
|
+
case '<': return comparison < 0;
|
|
630
|
+
case '<=': return comparison <= 0;
|
|
631
|
+
default: return false;
|
|
632
|
+
}
|
|
633
|
+
});
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* The highest published version satisfying a range.
|
|
638
|
+
* @param versions - the published version strings.
|
|
639
|
+
* @param rangeText - the requested range.
|
|
640
|
+
* @returns the highest satisfying version exactly as published, or undefined.
|
|
641
|
+
*/
|
|
642
|
+
export function highestSatisfyingVersion(versions, rangeText) {
|
|
643
|
+
let best;
|
|
644
|
+
for (const text of versions) {
|
|
645
|
+
const parsed = parseVersion(text);
|
|
646
|
+
if (parsed === undefined)
|
|
647
|
+
continue;
|
|
648
|
+
if (!satisfiesRegistryRange(text, rangeText))
|
|
649
|
+
continue;
|
|
650
|
+
if (best === undefined || compareVersions(parsed, best.parsed) > 0)
|
|
651
|
+
best = { text, parsed };
|
|
652
|
+
}
|
|
653
|
+
return best?.text;
|
|
654
|
+
}
|
|
655
|
+
/** Read one version's `dist` or throw the named refusal. */
|
|
656
|
+
function readDist(name, version, raw) {
|
|
657
|
+
if (typeof raw !== 'object' || raw === null) {
|
|
658
|
+
throw new RegistryError('registry-invalid-metadata', `${name}@${version} has no dist object in the registry metadata`);
|
|
659
|
+
}
|
|
660
|
+
// SAFETY: JSON.parse output was checked to be a non-null object; every field is
|
|
661
|
+
// validated below, and a non-string/missing value is a named refusal.
|
|
662
|
+
const dist = raw;
|
|
663
|
+
const tarball = dist.tarball;
|
|
664
|
+
if (typeof tarball !== 'string' || !/^https?:\/\//i.test(tarball)) {
|
|
665
|
+
throw new RegistryError('registry-invalid-metadata', `${name}@${version} has no http(s) dist.tarball in the registry metadata`);
|
|
666
|
+
}
|
|
667
|
+
const integrity = dist.integrity;
|
|
668
|
+
if (typeof integrity !== 'string' || !/^sha512-/i.test(integrity)) {
|
|
669
|
+
throw new RegistryError('registry-integrity-missing', `${name}@${version} declares no sha512 dist.integrity; unverified bytes are never installed`, { cause: undefined });
|
|
670
|
+
}
|
|
671
|
+
return { tarball, integrity };
|
|
672
|
+
}
|
|
673
|
+
/** Validate the packument shape this client can trust. */
|
|
674
|
+
function readPackument(name, raw) {
|
|
675
|
+
if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
|
|
676
|
+
throw new RegistryError('registry-invalid-metadata', `the registry metadata for ${name} is not a JSON object`);
|
|
677
|
+
}
|
|
678
|
+
// SAFETY: JSON.parse output was checked to be a non-null non-array object; the
|
|
679
|
+
// two fields read from it are validated before use.
|
|
680
|
+
const document = raw;
|
|
681
|
+
const versions = document.versions;
|
|
682
|
+
if (typeof versions !== 'object' || versions === null || Array.isArray(versions)) {
|
|
683
|
+
throw new RegistryError('registry-invalid-metadata', `the registry metadata for ${name} declares no versions object`);
|
|
684
|
+
}
|
|
685
|
+
const distTags = {};
|
|
686
|
+
const rawTags = document['dist-tags'];
|
|
687
|
+
if (typeof rawTags === 'object' && rawTags !== null) {
|
|
688
|
+
// SAFETY: the dist-tags container was checked to be a non-null object; only
|
|
689
|
+
// string tag targets are kept, so an unexpected shape contributes nothing.
|
|
690
|
+
for (const [tag, value] of Object.entries(rawTags)) {
|
|
691
|
+
if (typeof value === 'string')
|
|
692
|
+
distTags[tag] = value;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
// SAFETY: the versions container was checked to be a non-null non-array object;
|
|
696
|
+
// each entry is parsed defensively by readDist before it is trusted.
|
|
697
|
+
return { distTags, versions: versions };
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Resolve which published version one spec names.
|
|
701
|
+
* @param name - the package name.
|
|
702
|
+
* @param spec - dist-tag, exact version, or range; empty means `latest`.
|
|
703
|
+
* @param packument - the validated metadata.
|
|
704
|
+
* @returns the exact version string.
|
|
705
|
+
*/
|
|
706
|
+
function selectPublishedVersion(name, spec, packument) {
|
|
707
|
+
const requested = spec.trim();
|
|
708
|
+
if (requested.length === 0 || requested === 'latest') {
|
|
709
|
+
const latest = packument.distTags['latest'];
|
|
710
|
+
if (latest === undefined) {
|
|
711
|
+
throw new RegistryError('registry-not-found', `${name} has no latest dist-tag in the registry metadata`);
|
|
712
|
+
}
|
|
713
|
+
return { version: latest, distTag: 'latest' };
|
|
714
|
+
}
|
|
715
|
+
const tagged = packument.distTags[requested];
|
|
716
|
+
if (tagged !== undefined)
|
|
717
|
+
return { version: tagged, distTag: requested };
|
|
718
|
+
if (Object.hasOwn(packument.versions, requested))
|
|
719
|
+
return { version: requested };
|
|
720
|
+
const best = highestSatisfyingVersion(Object.keys(packument.versions), requested);
|
|
721
|
+
if (best === undefined) {
|
|
722
|
+
throw new RegistryError('registry-no-matching-version', `${name} has no published version satisfying ${JSON.stringify(requested)}`);
|
|
723
|
+
}
|
|
724
|
+
return { version: best };
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Create a registry session over one npm registry.
|
|
728
|
+
*
|
|
729
|
+
* The same session serves the extension package and every runtime dependency, so
|
|
730
|
+
* the tarball map (key → URL) the resolver registers is the map the archive
|
|
731
|
+
* fetches through. Nothing is downloaded until a caller fetches; nothing is
|
|
732
|
+
* verified here (the SDK verifies the sha512 before extraction, and this module
|
|
733
|
+
* refuses metadata without one).
|
|
734
|
+
* @param options - registry URL, archive factory, bounds and fetch seam.
|
|
735
|
+
* @returns the session.
|
|
736
|
+
*/
|
|
737
|
+
export function createRegistrySession(options) {
|
|
738
|
+
const registryUrl = normalizeRegistryUrl(options.registryUrl);
|
|
739
|
+
const maxTarballBytes = options.maxTarballBytes ?? MAX_DEPENDENCY_ARCHIVE_BYTES;
|
|
740
|
+
const timeoutMs = options.timeoutMs ?? 30_000;
|
|
741
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
742
|
+
/** tarball URL per `name@version` key, registered by resolve(). */
|
|
743
|
+
const tarballs = new Map();
|
|
744
|
+
const timed = (signal) => signal === undefined
|
|
745
|
+
? AbortSignal.timeout(timeoutMs)
|
|
746
|
+
: AbortSignal.any([signal, AbortSignal.timeout(timeoutMs)]);
|
|
747
|
+
const requireRegistry = () => {
|
|
748
|
+
if (registryUrl === '') {
|
|
749
|
+
throw new RegistryError('registry-not-configured', 'no npm registry is configured (config.extensionRegistry)');
|
|
750
|
+
}
|
|
751
|
+
return registryUrl;
|
|
752
|
+
};
|
|
753
|
+
const session = {
|
|
754
|
+
registryUrl,
|
|
755
|
+
archive: options.archiveFactory(source => session.download(source)),
|
|
756
|
+
async resolve(name, spec, signal) {
|
|
757
|
+
assertUsableName(name);
|
|
758
|
+
const base = requireRegistry();
|
|
759
|
+
const url = `${base}/${encodePackageName(name)}`;
|
|
760
|
+
let response;
|
|
761
|
+
try {
|
|
762
|
+
response = await fetchImpl(url, {
|
|
763
|
+
headers: { accept: 'application/vnd.npm.install-v1+json, application/json' },
|
|
764
|
+
signal: timed(signal),
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
catch (error) {
|
|
768
|
+
throw new RegistryError('registry-unavailable', `the npm registry ${base} could not be reached: ${messageOf(error)}`, { cause: error, transport: true });
|
|
769
|
+
}
|
|
770
|
+
if (!response.ok) {
|
|
771
|
+
await response.body?.cancel();
|
|
772
|
+
if (response.status === 404) {
|
|
773
|
+
throw new RegistryError('registry-not-found', `${name} was not found on the npm registry ${base} (HTTP 404)`);
|
|
774
|
+
}
|
|
775
|
+
if (response.status >= 500) {
|
|
776
|
+
throw new RegistryError('registry-unavailable', `the npm registry ${base} answered HTTP ${response.status} for ${name}`, { transport: true });
|
|
777
|
+
}
|
|
778
|
+
throw new RegistryError('registry-invalid-metadata', `the npm registry ${base} refused ${name} with HTTP ${response.status}`);
|
|
779
|
+
}
|
|
780
|
+
const metadata = await readBoundedBody(response, MAX_REGISTRY_METADATA_BYTES);
|
|
781
|
+
let parsed;
|
|
782
|
+
try {
|
|
783
|
+
parsed = JSON.parse(new TextDecoder().decode(metadata));
|
|
784
|
+
}
|
|
785
|
+
catch (error) {
|
|
786
|
+
throw new RegistryError('registry-invalid-metadata', `the npm registry returned unparseable metadata for ${name}: ${messageOf(error)}`, { cause: error });
|
|
787
|
+
}
|
|
788
|
+
const packument = readPackument(name, parsed);
|
|
789
|
+
const selected = selectPublishedVersion(name, spec, packument);
|
|
790
|
+
const versionEntry = packument.versions[selected.version];
|
|
791
|
+
if (typeof versionEntry !== 'object' || versionEntry === null) {
|
|
792
|
+
throw new RegistryError('registry-invalid-metadata', `${name}@${selected.version} has no version object in the registry metadata`);
|
|
793
|
+
}
|
|
794
|
+
// SAFETY: the version object was checked above; `dist` is read defensively by
|
|
795
|
+
// readDist, which refuses a missing/non-http tarball and a missing sha512.
|
|
796
|
+
const dist = readDist(name, selected.version, versionEntry.dist);
|
|
797
|
+
const key = `${name}@${selected.version}`;
|
|
798
|
+
tarballs.set(key, dist.tarball);
|
|
799
|
+
const published = { name, version: selected.version, tarball: dist.tarball, integrity: dist.integrity };
|
|
800
|
+
return selected.distTag === undefined ? published : { ...published, distTag: selected.distTag };
|
|
801
|
+
},
|
|
802
|
+
async download(source, signal) {
|
|
803
|
+
const url = tarballs.get(source.requested);
|
|
804
|
+
if (url === undefined) {
|
|
805
|
+
// A tarball for a package that was never resolved: the graph contract says
|
|
806
|
+
// resolve-then-fetch, so this is a programming error, not a package refusal.
|
|
807
|
+
throw new RegistryError('registry-invalid-metadata', `the registry tarball ${source.requested} was not resolved by this session`);
|
|
808
|
+
}
|
|
809
|
+
let response;
|
|
810
|
+
try {
|
|
811
|
+
response = await fetchImpl(url, { signal: timed(signal) });
|
|
812
|
+
}
|
|
813
|
+
catch (error) {
|
|
814
|
+
throw new RegistryError('registry-tarball-fetch-failed', `the tarball for ${source.requested} could not be downloaded: ${messageOf(error)}`, { cause: error });
|
|
815
|
+
}
|
|
816
|
+
if (!response.ok) {
|
|
817
|
+
await response.body?.cancel();
|
|
818
|
+
throw new RegistryError('registry-tarball-fetch-failed', `the tarball for ${source.requested} answered HTTP ${response.status}`);
|
|
819
|
+
}
|
|
820
|
+
try {
|
|
821
|
+
return await readBoundedBody(response, maxTarballBytes);
|
|
822
|
+
}
|
|
823
|
+
catch (error) {
|
|
824
|
+
if (error instanceof RegistryError)
|
|
825
|
+
throw error;
|
|
826
|
+
throw new RegistryError('registry-tarball-fetch-failed', `the tarball for ${source.requested} could not be read: ${messageOf(error)}`, { cause: error });
|
|
827
|
+
}
|
|
828
|
+
},
|
|
829
|
+
};
|
|
830
|
+
return session;
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* Wire a registry session into the SDK dependency-graph contract.
|
|
834
|
+
*
|
|
835
|
+
* Every declared dependency is resolved to one exact published version with its
|
|
836
|
+
* sha512 integrity; the SAME session archive fetches the bytes, so the manifest
|
|
837
|
+
* the graph verifies is the manifest that was resolved. EXT-10's script refusal is
|
|
838
|
+
* the SDK's own, unchanged.
|
|
839
|
+
* @param session - the registry session.
|
|
840
|
+
* @returns the install-dependency graph.
|
|
841
|
+
*/
|
|
842
|
+
export function createRegistryDependencyGraph(session) {
|
|
843
|
+
return {
|
|
844
|
+
resolver: {
|
|
845
|
+
async resolve(name, range) {
|
|
846
|
+
const resolved = await session.resolve(name, range);
|
|
847
|
+
return {
|
|
848
|
+
name: resolved.name,
|
|
849
|
+
version: resolved.version,
|
|
850
|
+
tarball: { kind: 'registry', requested: `${resolved.name}@${resolved.version}` },
|
|
851
|
+
integrity: resolved.integrity,
|
|
852
|
+
};
|
|
853
|
+
},
|
|
854
|
+
},
|
|
855
|
+
archive: session.archive,
|
|
856
|
+
};
|
|
857
|
+
}
|
|
369
858
|
//# sourceMappingURL=extension-dependencies.js.map
|
package/lib/extensions-api.d.ts
CHANGED
|
@@ -78,6 +78,10 @@ export interface ExtensionInstallResult {
|
|
|
78
78
|
readonly version: string;
|
|
79
79
|
/** Installation is not activation: `active` is false until it is enabled. */
|
|
80
80
|
readonly active: boolean;
|
|
81
|
+
/** Which route actually supplied the installed bytes. */
|
|
82
|
+
readonly source: 'registry' | 'directory';
|
|
83
|
+
/** The exact version the request resolved to (equals `version` today). */
|
|
84
|
+
readonly resolvedVersion: string;
|
|
81
85
|
}
|
|
82
86
|
/** The result of an enable/disable request. */
|
|
83
87
|
export interface ExtensionToggleResult {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extensions-api.d.ts","sourceRoot":"","sources":["../src/extensions-api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,yCAAyC;AACzC,yEAAyE;AACzE,MAAM,MAAM,wBAAwB,GAChC,OAAO,GACP,QAAQ,GACR,cAAc,GACd,QAAQ,GACR,YAAY,GACZ,eAAe,GACf,UAAU,GACV,WAAW,GACX,YAAY,CAAA;AAEhB,oFAAoF;AACpF,MAAM,MAAM,0BAA0B,GAClC,SAAS,GACT,SAAS,GACT,QAAQ,GACR,QAAQ,GACR,MAAM,CAAA;AAEV;;;;;;;;GAQG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAA;IACvC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,0EAA0E;IAC1E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,0BAA0B,CAAA;CAC5C;AAED,MAAM,WAAW,cAAc;IAC7B,iFAAiF;IACjF,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,iEAAiE;IACjE,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,iEAAiE;IACjE,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,iDAAiD;IACjD,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,iDAAiD;IACjD,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,kDAAkD;IAClD,QAAQ,CAAC,SAAS,EAAE,WAAW,GAAG,SAAS,GAAG,SAAS,CAAA;IACvD,oDAAoD;IACpD,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,gEAAgE;IAChE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,oEAAoE;IACpE,QAAQ,CAAC,YAAY,EAAE,SAAS,oBAAoB,EAAE,CAAA;IACtD;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAC1B;AAED,0CAA0C;AAC1C,MAAM,WAAW,wBAAwB;IACvC,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,yEAAyE;IACzE,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,kDAAkD;IAClD,QAAQ,CAAC,UAAU,EAAE,SAAS,cAAc,EAAE,CAAA;CAC/C;AAED,wCAAwC;AACxC,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"extensions-api.d.ts","sourceRoot":"","sources":["../src/extensions-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -112,6 +112,20 @@ export type ExtensionsServiceErrorCode =
|
|
|
112
112
|
| 'extension-preparation-failed'
|
|
113
113
|
/** A prerequisite the deployment cannot satisfy blocks activation before any lifecycle call. */
|
|
114
114
|
| 'extension-requirement-unmet'
|
|
115
|
+
/** Registry mode was selected but no registry URL is configured. */
|
|
116
|
+
| 'extension-registry-unconfigured'
|
|
117
|
+
/** The registry has no such package, version, or dist-tag (HTTP 404 / no matching version). */
|
|
118
|
+
| 'extension-registry-not-found'
|
|
119
|
+
/** The registry metadata has no sha512 `dist.integrity`; unverified bytes are never installed. */
|
|
120
|
+
| 'extension-registry-integrity-missing'
|
|
121
|
+
/** The registry metadata or tarball URL does not have the shape this host can verify. */
|
|
122
|
+
| 'extension-registry-invalid-metadata'
|
|
123
|
+
/** The tarball could not be downloaded, or exceeds the configured byte cap. */
|
|
124
|
+
| 'extension-registry-fetch-failed'
|
|
125
|
+
/** Transport failure or 5xx: the registry did not answer usefully. */
|
|
126
|
+
| 'extension-registry-unavailable'
|
|
127
|
+
/** The fetched tarball does not hash to the registry-declared sha512. */
|
|
128
|
+
| 'extension-registry-integrity-mismatch'
|
|
115
129
|
/** `deactivate` refused or failed; the SDK's named error is carried in the message. */
|
|
116
130
|
| 'extension-deactivation-failed'
|
|
117
131
|
/** The host's disabled-list writer rejected the new list after the action landed. */
|
|
@@ -160,6 +174,22 @@ export interface ExtensionsServiceOptions {
|
|
|
160
174
|
readonly lifecycle?: () => ExtensionActivation | undefined;
|
|
161
175
|
/** Declare that this host cannot write the store (read-only mount). */
|
|
162
176
|
readonly readOnly?: boolean;
|
|
177
|
+
/**
|
|
178
|
+
* How an install without an explicit source directory is sourced.
|
|
179
|
+
*
|
|
180
|
+
* - `registry` (and `auto`, the default) resolve the package from the npm registry.
|
|
181
|
+
* - `directory` keeps the developer-mode source-directory path.
|
|
182
|
+
* - `auto` additionally falls back to the directory ONLY for a TRANSPORT-level
|
|
183
|
+
* registry failure (unreachable/timeout/5xx) and only when
|
|
184
|
+
* `allowSourceDirectories` is on; a package-level refusal (404, missing
|
|
185
|
+
* integrity, bad tarball, digest mismatch) is always named and never retried
|
|
186
|
+
* against a local directory.
|
|
187
|
+
*/
|
|
188
|
+
readonly installSource?: 'registry' | 'directory' | 'auto';
|
|
189
|
+
/** The npm registry base URL; defaults to the public npm registry. */
|
|
190
|
+
readonly registryUrl?: string;
|
|
191
|
+
/** Hard cap on one registry package tarball; defaults to the SDK archive bound (256 MiB). */
|
|
192
|
+
readonly registryTarballMaxBytes?: number;
|
|
163
193
|
/** INTERNAL TEST SEAM: the directory installer, defaulting to the SDK's staged path. */
|
|
164
194
|
readonly installDirectory?: DirectoryInstaller;
|
|
165
195
|
/** INTERNAL TEST SEAM: the content digest, defaulting to the SDK's installed-content digest. */
|
|
@@ -259,20 +289,23 @@ export declare class ExtensionsService implements ModelToolsRemote {
|
|
|
259
289
|
*/
|
|
260
290
|
describe(signal?: AbortSignal): Promise<ExtensionsDescribeResult>;
|
|
261
291
|
/**
|
|
262
|
-
* Install one extension
|
|
292
|
+
* Install one extension, choosing the route from the operator configuration.
|
|
263
293
|
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
*
|
|
294
|
+
* - An EXPLICIT `source` path is always a developer-mode directory install (the
|
|
295
|
+
* existing source-directory gate and refusals apply).
|
|
296
|
+
* - Otherwise `installSource` decides. `registry` resolves `id@latest` from the
|
|
297
|
+
* npm registry. `directory` uses the configured source directory. `auto` (the
|
|
298
|
+
* default) prefers the registry and falls back to the directory ONLY for a
|
|
299
|
+
* transport-level registry failure (unreachable/timeout/5xx) when directory
|
|
300
|
+
* installs are allowed — a package-level refusal (404, missing integrity, bad
|
|
301
|
+
* tarball, digest mismatch) is always named and never retried locally.
|
|
270
302
|
*
|
|
271
|
-
* INSTALLATION IS NOT ACTIVATION: the result is always `active: false
|
|
303
|
+
* INSTALLATION IS NOT ACTIVATION: the result is always `active: false`, and it
|
|
304
|
+
* names the route that actually supplied the bytes.
|
|
272
305
|
* @param extensionId - the package identity to install.
|
|
273
|
-
* @param source - an explicit source directory, or absent
|
|
306
|
+
* @param source - an explicit source directory (developer override), or absent.
|
|
274
307
|
* @param signal - cancellation.
|
|
275
|
-
* @returns the installed identity and
|
|
308
|
+
* @returns the installed identity, version and route.
|
|
276
309
|
* @throws ExtensionsServiceError for every refusal and failure.
|
|
277
310
|
*/
|
|
278
311
|
install(extensionId: string, source?: string, signal?: AbortSignal): Promise<ExtensionInstallResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extensions-service.d.ts","sourceRoot":"","sources":["../src/extensions-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAIH,OAAO,
|
|
1
|
+
{"version":3,"file":"extensions-service.d.ts","sourceRoot":"","sources":["../src/extensions-service.ts"],"names":[],"mappings":"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"}
|