@orkestrel/scaffold 0.0.15 → 0.0.17
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 +13 -3
- package/dist/bin/scaffold.js +73 -34
- package/dist/bin/scaffold.js.map +1 -1
- package/dist/host/claude/agents/orkestrel.md +14 -14
- package/dist/host/guides/src/scaffold.md +78 -30
- package/dist/src/core/index.cjs +173 -37
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +3 -3
- package/dist/src/core/index.d.ts +3 -3
- package/dist/src/core/index.js +173 -37
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +119 -48
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +31 -6
- package/dist/src/server/index.d.ts +31 -6
- package/dist/src/server/index.js +120 -50
- package/dist/src/server/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -705,6 +705,14 @@ export declare function parseSyncCurrent(value: Readonly<Record<string, string>>
|
|
|
705
705
|
/** Parse and semantically validate dependency data before Sync performs network I/O. */
|
|
706
706
|
export declare function parseSyncDependencies(value: unknown, external: boolean): readonly Dependency[];
|
|
707
707
|
|
|
708
|
+
/**
|
|
709
|
+
* Parse and semantically validate bare registry package names before Sync performs network I/O.
|
|
710
|
+
*
|
|
711
|
+
* @param value - Untrusted package-name collection.
|
|
712
|
+
* @returns A frozen owned snapshot of valid unique npm package names.
|
|
713
|
+
*/
|
|
714
|
+
export declare function parseSyncNames(value: unknown): readonly string[];
|
|
715
|
+
|
|
708
716
|
/**
|
|
709
717
|
* Parse the exact bounded `SyncOptions` boundary before allocating resources.
|
|
710
718
|
*
|
|
@@ -779,13 +787,13 @@ export declare function readFileHex(root: string, path: string, code: ScaffoldEr
|
|
|
779
787
|
export declare function readFileText(root: string, path: string, code: ScaffoldErrorCode, boundary: string, limit?: number): string;
|
|
780
788
|
|
|
781
789
|
/**
|
|
782
|
-
* Read bounded physical local guide mirrors for
|
|
790
|
+
* Read bounded physical local guide mirrors for package names.
|
|
783
791
|
*
|
|
784
792
|
* @param target - The package root.
|
|
785
|
-
* @param
|
|
786
|
-
* @returns Existing guide content keyed by
|
|
793
|
+
* @param names - The package names whose mirrors are eligible.
|
|
794
|
+
* @returns Existing guide content keyed by package name.
|
|
787
795
|
*/
|
|
788
|
-
export declare function readGuideReferences(target: string,
|
|
796
|
+
export declare function readGuideReferences(target: string, names: readonly string[]): Readonly<Record<string, string>>;
|
|
789
797
|
|
|
790
798
|
/**
|
|
791
799
|
* Read and validate a vendored host root's `manifest.json`, when present.
|
|
@@ -1020,8 +1028,10 @@ export declare function storagePath(path: string): string;
|
|
|
1020
1028
|
* map, a fetched guide byte-equal to its entry verdicts `current`, anything
|
|
1021
1029
|
* differing or absent from the map verdicts `behind`; WITHOUT the map, every
|
|
1022
1030
|
* successful fetch verdicts `behind` (no reference means it needs syncing).
|
|
1023
|
-
* `pull` builds that map itself from the TARGET's
|
|
1024
|
-
*
|
|
1031
|
+
* `pull` builds that map itself from the TARGET's declared dependency mirrors;
|
|
1032
|
+
* `mirror` builds it from the registry's exact organization package list,
|
|
1033
|
+
* excluding the target's own guide and issuing no registry version reads. Both
|
|
1034
|
+
* verdicts are target-relative; `write` commits only the
|
|
1025
1035
|
* `behind` guides (never `current`, `missing`, or `failed`, which carries no
|
|
1026
1036
|
* trustworthy content) under the same realpath-anchored containment law
|
|
1027
1037
|
* `Materializer` enforces. After `destroy()` every method throws `DESTROYED`;
|
|
@@ -1041,6 +1051,7 @@ export declare class Sync implements SyncInterface {
|
|
|
1041
1051
|
#private;
|
|
1042
1052
|
constructor(options?: SyncOptions);
|
|
1043
1053
|
get emitter(): EmitterInterface<SyncEventMap>;
|
|
1054
|
+
lookup(names: readonly string[]): Promise<readonly VersionLookup[]>;
|
|
1044
1055
|
guides(deps: readonly Dependency[], current?: Readonly<Record<string, string>>): Promise<readonly GuideSync[]>;
|
|
1045
1056
|
versions(deps: readonly Dependency[]): Promise<readonly VersionSync[]>;
|
|
1046
1057
|
/**
|
|
@@ -1071,6 +1082,7 @@ export declare class Sync implements SyncInterface {
|
|
|
1071
1082
|
*/
|
|
1072
1083
|
catalog(): Promise<readonly CatalogEntry[]>;
|
|
1073
1084
|
pull(target: string, dependencies?: readonly Dependency[]): Promise<SyncReport>;
|
|
1085
|
+
mirror(target: string): Promise<SyncReport>;
|
|
1074
1086
|
write(report: SyncReport, target: string): Promise<readonly string[]>;
|
|
1075
1087
|
destroy(): void;
|
|
1076
1088
|
}
|
|
@@ -1121,10 +1133,12 @@ export declare function syncGuideOptionsShape(): ObjectShape<{
|
|
|
1121
1133
|
*/
|
|
1122
1134
|
export declare interface SyncInterface {
|
|
1123
1135
|
readonly emitter: EmitterInterface<SyncEventMap>;
|
|
1136
|
+
lookup(names: readonly string[]): Promise<readonly VersionLookup[]>;
|
|
1124
1137
|
guides(deps: readonly Dependency[], current?: Readonly<Record<string, string>>): Promise<readonly GuideSync[]>;
|
|
1125
1138
|
versions(deps: readonly Dependency[]): Promise<readonly VersionSync[]>;
|
|
1126
1139
|
catalog(): Promise<readonly CatalogEntry[]>;
|
|
1127
1140
|
pull(target: string, dependencies?: readonly Dependency[]): Promise<SyncReport>;
|
|
1141
|
+
mirror(target: string): Promise<SyncReport>;
|
|
1128
1142
|
write(report: SyncReport, target: string): Promise<readonly string[]>;
|
|
1129
1143
|
destroy(): void;
|
|
1130
1144
|
}
|
|
@@ -1282,6 +1296,17 @@ export declare function validateWriteTarget(transaction: WriteTransaction, owned
|
|
|
1282
1296
|
*/
|
|
1283
1297
|
export declare function vendoredPruneSet(host: string, directory: string): ReadonlySet<string>;
|
|
1284
1298
|
|
|
1299
|
+
/** One bare-name registry lookup, without a caller-invented declaration range. */
|
|
1300
|
+
export declare type VersionLookup = {
|
|
1301
|
+
readonly name: string;
|
|
1302
|
+
readonly latest: string;
|
|
1303
|
+
readonly freshness: 'behind';
|
|
1304
|
+
} | {
|
|
1305
|
+
readonly name: string;
|
|
1306
|
+
readonly freshness: 'missing' | 'failed';
|
|
1307
|
+
readonly note: string;
|
|
1308
|
+
};
|
|
1309
|
+
|
|
1285
1310
|
/** Exact SHA-256 digest accepted by write preconditions. */
|
|
1286
1311
|
export declare const WRITE_DIGEST_PATTERN: RegExp;
|
|
1287
1312
|
|
|
@@ -705,6 +705,14 @@ export declare function parseSyncCurrent(value: Readonly<Record<string, string>>
|
|
|
705
705
|
/** Parse and semantically validate dependency data before Sync performs network I/O. */
|
|
706
706
|
export declare function parseSyncDependencies(value: unknown, external: boolean): readonly Dependency[];
|
|
707
707
|
|
|
708
|
+
/**
|
|
709
|
+
* Parse and semantically validate bare registry package names before Sync performs network I/O.
|
|
710
|
+
*
|
|
711
|
+
* @param value - Untrusted package-name collection.
|
|
712
|
+
* @returns A frozen owned snapshot of valid unique npm package names.
|
|
713
|
+
*/
|
|
714
|
+
export declare function parseSyncNames(value: unknown): readonly string[];
|
|
715
|
+
|
|
708
716
|
/**
|
|
709
717
|
* Parse the exact bounded `SyncOptions` boundary before allocating resources.
|
|
710
718
|
*
|
|
@@ -779,13 +787,13 @@ export declare function readFileHex(root: string, path: string, code: ScaffoldEr
|
|
|
779
787
|
export declare function readFileText(root: string, path: string, code: ScaffoldErrorCode, boundary: string, limit?: number): string;
|
|
780
788
|
|
|
781
789
|
/**
|
|
782
|
-
* Read bounded physical local guide mirrors for
|
|
790
|
+
* Read bounded physical local guide mirrors for package names.
|
|
783
791
|
*
|
|
784
792
|
* @param target - The package root.
|
|
785
|
-
* @param
|
|
786
|
-
* @returns Existing guide content keyed by
|
|
793
|
+
* @param names - The package names whose mirrors are eligible.
|
|
794
|
+
* @returns Existing guide content keyed by package name.
|
|
787
795
|
*/
|
|
788
|
-
export declare function readGuideReferences(target: string,
|
|
796
|
+
export declare function readGuideReferences(target: string, names: readonly string[]): Readonly<Record<string, string>>;
|
|
789
797
|
|
|
790
798
|
/**
|
|
791
799
|
* Read and validate a vendored host root's `manifest.json`, when present.
|
|
@@ -1020,8 +1028,10 @@ export declare function storagePath(path: string): string;
|
|
|
1020
1028
|
* map, a fetched guide byte-equal to its entry verdicts `current`, anything
|
|
1021
1029
|
* differing or absent from the map verdicts `behind`; WITHOUT the map, every
|
|
1022
1030
|
* successful fetch verdicts `behind` (no reference means it needs syncing).
|
|
1023
|
-
* `pull` builds that map itself from the TARGET's
|
|
1024
|
-
*
|
|
1031
|
+
* `pull` builds that map itself from the TARGET's declared dependency mirrors;
|
|
1032
|
+
* `mirror` builds it from the registry's exact organization package list,
|
|
1033
|
+
* excluding the target's own guide and issuing no registry version reads. Both
|
|
1034
|
+
* verdicts are target-relative; `write` commits only the
|
|
1025
1035
|
* `behind` guides (never `current`, `missing`, or `failed`, which carries no
|
|
1026
1036
|
* trustworthy content) under the same realpath-anchored containment law
|
|
1027
1037
|
* `Materializer` enforces. After `destroy()` every method throws `DESTROYED`;
|
|
@@ -1041,6 +1051,7 @@ export declare class Sync implements SyncInterface {
|
|
|
1041
1051
|
#private;
|
|
1042
1052
|
constructor(options?: SyncOptions);
|
|
1043
1053
|
get emitter(): EmitterInterface<SyncEventMap>;
|
|
1054
|
+
lookup(names: readonly string[]): Promise<readonly VersionLookup[]>;
|
|
1044
1055
|
guides(deps: readonly Dependency[], current?: Readonly<Record<string, string>>): Promise<readonly GuideSync[]>;
|
|
1045
1056
|
versions(deps: readonly Dependency[]): Promise<readonly VersionSync[]>;
|
|
1046
1057
|
/**
|
|
@@ -1071,6 +1082,7 @@ export declare class Sync implements SyncInterface {
|
|
|
1071
1082
|
*/
|
|
1072
1083
|
catalog(): Promise<readonly CatalogEntry[]>;
|
|
1073
1084
|
pull(target: string, dependencies?: readonly Dependency[]): Promise<SyncReport>;
|
|
1085
|
+
mirror(target: string): Promise<SyncReport>;
|
|
1074
1086
|
write(report: SyncReport, target: string): Promise<readonly string[]>;
|
|
1075
1087
|
destroy(): void;
|
|
1076
1088
|
}
|
|
@@ -1121,10 +1133,12 @@ export declare function syncGuideOptionsShape(): ObjectShape<{
|
|
|
1121
1133
|
*/
|
|
1122
1134
|
export declare interface SyncInterface {
|
|
1123
1135
|
readonly emitter: EmitterInterface<SyncEventMap>;
|
|
1136
|
+
lookup(names: readonly string[]): Promise<readonly VersionLookup[]>;
|
|
1124
1137
|
guides(deps: readonly Dependency[], current?: Readonly<Record<string, string>>): Promise<readonly GuideSync[]>;
|
|
1125
1138
|
versions(deps: readonly Dependency[]): Promise<readonly VersionSync[]>;
|
|
1126
1139
|
catalog(): Promise<readonly CatalogEntry[]>;
|
|
1127
1140
|
pull(target: string, dependencies?: readonly Dependency[]): Promise<SyncReport>;
|
|
1141
|
+
mirror(target: string): Promise<SyncReport>;
|
|
1128
1142
|
write(report: SyncReport, target: string): Promise<readonly string[]>;
|
|
1129
1143
|
destroy(): void;
|
|
1130
1144
|
}
|
|
@@ -1282,6 +1296,17 @@ export declare function validateWriteTarget(transaction: WriteTransaction, owned
|
|
|
1282
1296
|
*/
|
|
1283
1297
|
export declare function vendoredPruneSet(host: string, directory: string): ReadonlySet<string>;
|
|
1284
1298
|
|
|
1299
|
+
/** One bare-name registry lookup, without a caller-invented declaration range. */
|
|
1300
|
+
export declare type VersionLookup = {
|
|
1301
|
+
readonly name: string;
|
|
1302
|
+
readonly latest: string;
|
|
1303
|
+
readonly freshness: 'behind';
|
|
1304
|
+
} | {
|
|
1305
|
+
readonly name: string;
|
|
1306
|
+
readonly freshness: 'missing' | 'failed';
|
|
1307
|
+
readonly note: string;
|
|
1308
|
+
};
|
|
1309
|
+
|
|
1285
1310
|
/** Exact SHA-256 digest accepted by write preconditions. */
|
|
1286
1311
|
export declare const WRITE_DIGEST_PATTERN: RegExp;
|
|
1287
1312
|
|
package/dist/src/server/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CONTROL_CHARACTER_PATTERN, DEFAULT_ENGINES, DEFAULT_VERSION, DEPENDENCY_NAME_PATTERN, ENVIRONMENTS, GLOBAL_SETUP_PATH, HEX_PATTERN, HOST_PATHS, INVALID_PATH_CHARACTER_PATTERN, MAX_ARTIFACT_BYTES, MAX_ARTIFACT_HEX_LENGTH, MAX_COLLECTION_ITEMS, MAX_MANIFEST_BYTES, MAX_PATH_LENGTH, MAX_TOTAL_ARTIFACT_BYTES, SERVICE_SCRIPT_PATH, SYNC_BASELINE_PATTERN, ScaffoldError, VERSION_PATTERN, blueprint, bytesToHex, contentByteLength, devDependenciesFor, diffPlan, findFileConflict, findPathConflict, hasOnlyDataProperties, hasValidAuditBytes, hasValidSnapshotBytes, isDenseDataArray, isDependency, isEmitterErrorHandler, isPlan, isSyncReport, isWorkspaceName, manifestToDependencies, manifestToName, ownDataValue, parsePlan, parseSyncReport, rangeToFreshness, snapshotPlan, validateDependencyArray, validatePlan } from "../core/index.js";
|
|
1
|
+
import { CONTROL_CHARACTER_PATTERN, DEFAULT_ENGINES, DEFAULT_VERSION, DEPENDENCY_NAME_PATTERN, ENVIRONMENTS, EXTRA_NAME_PATTERN, GLOBAL_SETUP_PATH, HEX_PATTERN, HOST_PATHS, INVALID_PATH_CHARACTER_PATTERN, MAX_ARTIFACT_BYTES, MAX_ARTIFACT_HEX_LENGTH, MAX_COLLECTION_ITEMS, MAX_DEPENDENCY_NAME_LENGTH, MAX_MANIFEST_BYTES, MAX_PATH_LENGTH, MAX_TOTAL_ARTIFACT_BYTES, SERVICE_SCRIPT_PATH, SYNC_BASELINE_PATTERN, ScaffoldError, VERSION_PATTERN, blueprint, bytesToHex, contentByteLength, devDependenciesFor, diffPlan, findFileConflict, findPathConflict, hasOnlyDataProperties, hasValidAuditBytes, hasValidSnapshotBytes, isDenseDataArray, isDependency, isEmitterErrorHandler, isPlan, isSyncReport, isWorkspaceName, manifestToDependencies, manifestToName, ownDataValue, parsePlan, parseSyncReport, rangeToFreshness, snapshotPlan, validateDependencyArray, validatePlan } from "../core/index.js";
|
|
2
2
|
import { attempt, booleanShape, createContract, integerShape, isError, isFunction, isRecord, isString, objectShape, optionalShape, parseJSON, parseJSONAs, stringShape } from "@orkestrel/contract";
|
|
3
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
4
4
|
import { chmodSync, closeSync, constants, copyFileSync, existsSync, fstatSync, linkSync, lstatSync, mkdirSync, openSync, opendirSync, readSync, readdirSync, realpathSync, renameSync, rmSync, rmdirSync, writeFileSync } from "node:fs";
|
|
@@ -295,6 +295,34 @@ function isMaterializerEventHooks(value) {
|
|
|
295
295
|
}
|
|
296
296
|
//#endregion
|
|
297
297
|
//#region src/server/parsers.ts
|
|
298
|
+
/**
|
|
299
|
+
* Parse and semantically validate bare registry package names before Sync performs network I/O.
|
|
300
|
+
*
|
|
301
|
+
* @param value - Untrusted package-name collection.
|
|
302
|
+
* @returns A frozen owned snapshot of valid unique npm package names.
|
|
303
|
+
*/
|
|
304
|
+
function parseSyncNames(value) {
|
|
305
|
+
const owned = attempt(() => {
|
|
306
|
+
if (!isDenseDataArray(value, 1e3, (candidate) => typeof candidate === "string")) throw new Error("package names are malformed");
|
|
307
|
+
const length = Reflect.getOwnPropertyDescriptor(value, "length")?.value;
|
|
308
|
+
if (typeof length !== "number" || !Number.isSafeInteger(length) || length < 0 || length > 1e3) throw new Error("package name length is malformed");
|
|
309
|
+
const names = [];
|
|
310
|
+
for (let index = 0; index < length; index += 1) {
|
|
311
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(value, String(index));
|
|
312
|
+
if (descriptor === void 0 || !Reflect.has(descriptor, "value") || typeof descriptor.value !== "string") throw new Error("package name is malformed");
|
|
313
|
+
names.push(descriptor.value);
|
|
314
|
+
}
|
|
315
|
+
return Object.freeze(names);
|
|
316
|
+
});
|
|
317
|
+
if (!owned.success) throw new ScaffoldError("INVALID", "Sync package names are malformed", { error: owned.error });
|
|
318
|
+
const snapshot = owned.value;
|
|
319
|
+
const seen = /* @__PURE__ */ new Set();
|
|
320
|
+
for (const name of snapshot) {
|
|
321
|
+
if (name.length === 0 || name.length > MAX_DEPENDENCY_NAME_LENGTH || !EXTRA_NAME_PATTERN.test(name) || seen.has(name)) throw new ScaffoldError("INVALID", "Sync package names are invalid", { name });
|
|
322
|
+
seen.add(name);
|
|
323
|
+
}
|
|
324
|
+
return snapshot;
|
|
325
|
+
}
|
|
298
326
|
/** Parse and semantically validate dependency data before Sync performs network I/O. */
|
|
299
327
|
function parseSyncDependencies(value, external) {
|
|
300
328
|
const owned = attempt(() => {
|
|
@@ -928,16 +956,16 @@ function packageShortName(name) {
|
|
|
928
956
|
return name.startsWith("@orkestrel/") ? name.slice(11) : name;
|
|
929
957
|
}
|
|
930
958
|
/**
|
|
931
|
-
* Read bounded physical local guide mirrors for
|
|
959
|
+
* Read bounded physical local guide mirrors for package names.
|
|
932
960
|
*
|
|
933
961
|
* @param target - The package root.
|
|
934
|
-
* @param
|
|
935
|
-
* @returns Existing guide content keyed by
|
|
962
|
+
* @param names - The package names whose mirrors are eligible.
|
|
963
|
+
* @returns Existing guide content keyed by package name.
|
|
936
964
|
*/
|
|
937
|
-
function readGuideReferences(target,
|
|
965
|
+
function readGuideReferences(target, names) {
|
|
938
966
|
const current = {};
|
|
939
|
-
for (const
|
|
940
|
-
const path = `guides/src/${packageShortName(
|
|
967
|
+
for (const name of names) {
|
|
968
|
+
const path = `guides/src/${packageShortName(name)}.md`;
|
|
941
969
|
const full = resolvePhysicalPath(target, path, "TARGET", "target");
|
|
942
970
|
const status = attempt(() => lstatSync(full));
|
|
943
971
|
if (!status.success) {
|
|
@@ -948,7 +976,7 @@ function readGuideReferences(target, dependencies) {
|
|
|
948
976
|
});
|
|
949
977
|
}
|
|
950
978
|
if (!status.value.isFile() || status.value.isSymbolicLink() || status.value.nlink !== 1) throw new ScaffoldError("TARGET", `Local guide is not a physical file at ${path}`, { path });
|
|
951
|
-
current[
|
|
979
|
+
current[name] = readFileText(target, path, "TARGET", "target");
|
|
952
980
|
}
|
|
953
981
|
return Object.freeze(current);
|
|
954
982
|
}
|
|
@@ -3487,8 +3515,10 @@ var Materializer = class {
|
|
|
3487
3515
|
* map, a fetched guide byte-equal to its entry verdicts `current`, anything
|
|
3488
3516
|
* differing or absent from the map verdicts `behind`; WITHOUT the map, every
|
|
3489
3517
|
* successful fetch verdicts `behind` (no reference means it needs syncing).
|
|
3490
|
-
* `pull` builds that map itself from the TARGET's
|
|
3491
|
-
*
|
|
3518
|
+
* `pull` builds that map itself from the TARGET's declared dependency mirrors;
|
|
3519
|
+
* `mirror` builds it from the registry's exact organization package list,
|
|
3520
|
+
* excluding the target's own guide and issuing no registry version reads. Both
|
|
3521
|
+
* verdicts are target-relative; `write` commits only the
|
|
3492
3522
|
* `behind` guides (never `current`, `missing`, or `failed`, which carries no
|
|
3493
3523
|
* trustworthy content) under the same realpath-anchored containment law
|
|
3494
3524
|
* `Materializer` enforces. After `destroy()` every method throws `DESTROYED`;
|
|
@@ -3540,50 +3570,67 @@ var Sync = class Sync {
|
|
|
3540
3570
|
get emitter() {
|
|
3541
3571
|
return this.#emitter;
|
|
3542
3572
|
}
|
|
3573
|
+
async lookup(names) {
|
|
3574
|
+
this.#ensureAlive();
|
|
3575
|
+
return this.#lookup(names, Float64Array.of(this.#budget));
|
|
3576
|
+
}
|
|
3543
3577
|
async guides(deps, current) {
|
|
3544
3578
|
this.#ensureAlive();
|
|
3545
|
-
|
|
3579
|
+
const parsed = parseSyncDependencies(deps, false);
|
|
3580
|
+
return this.#guides(parsed.map((dependency) => dependency.name), current, Float64Array.of(this.#budget));
|
|
3546
3581
|
}
|
|
3547
3582
|
async versions(deps) {
|
|
3548
3583
|
this.#ensureAlive();
|
|
3549
3584
|
return this.#versions(deps, Float64Array.of(this.#budget));
|
|
3550
3585
|
}
|
|
3551
|
-
#guides(
|
|
3552
|
-
const parsed =
|
|
3586
|
+
#guides(names, current, allowance) {
|
|
3587
|
+
const parsed = parseSyncNames(names);
|
|
3553
3588
|
if (parsed.length > this.#items) throw new ScaffoldError("INVALID", "Sync dependency count exceeds its item limit", {
|
|
3554
3589
|
items: parsed.length,
|
|
3555
3590
|
limit: this.#items
|
|
3556
3591
|
});
|
|
3557
|
-
const reference = parseSyncCurrent(current, parsed
|
|
3558
|
-
return Sync.#runPool(parsed, this.#concurrency, async (
|
|
3559
|
-
const short = packageShortName(
|
|
3592
|
+
const reference = parseSyncCurrent(current, parsed, this.#budget);
|
|
3593
|
+
return Sync.#runPool(parsed, this.#concurrency, async (name) => {
|
|
3594
|
+
const short = packageShortName(name);
|
|
3560
3595
|
const url = this.#guideUrl(short);
|
|
3561
3596
|
const outcome = await Sync.#fetchText(url, this.#guidesTimeout, this.#retries, this.#limit, allowance, this.#controller.signal);
|
|
3562
|
-
const guide = Sync.#toGuideSync(
|
|
3597
|
+
const guide = Sync.#toGuideSync(name, short, outcome, reference);
|
|
3563
3598
|
if (outcome.kind === "failed") this.#emitter.emit("error", outcome.error);
|
|
3564
|
-
this.#emitter.emit("guide",
|
|
3599
|
+
this.#emitter.emit("guide", name);
|
|
3565
3600
|
if (this.#strict && (guide.freshness === "missing" || guide.freshness === "failed")) throw new ScaffoldError("FETCH", `Failed to fetch guide at ${url}`, {
|
|
3566
3601
|
url,
|
|
3567
|
-
name
|
|
3602
|
+
name
|
|
3568
3603
|
});
|
|
3569
3604
|
return guide;
|
|
3570
3605
|
});
|
|
3571
3606
|
}
|
|
3572
|
-
#versions(deps, allowance) {
|
|
3607
|
+
async #versions(deps, allowance) {
|
|
3573
3608
|
const parsed = parseSyncDependencies(deps, true);
|
|
3609
|
+
const lookups = await this.#lookup(parsed.map((dependency) => dependency.name), allowance);
|
|
3610
|
+
const versions = [];
|
|
3611
|
+
for (let index = 0; index < parsed.length; index += 1) {
|
|
3612
|
+
const dep = parsed[index];
|
|
3613
|
+
const lookup = lookups[index];
|
|
3614
|
+
if (dep === void 0 || lookup === void 0) throw new ScaffoldError("INVALID", "Sync version lookup result is incomplete");
|
|
3615
|
+
versions.push(Sync.#toVersionSync(dep, lookup));
|
|
3616
|
+
}
|
|
3617
|
+
return Object.freeze(versions);
|
|
3618
|
+
}
|
|
3619
|
+
#lookup(names, allowance) {
|
|
3620
|
+
const parsed = parseSyncNames(names);
|
|
3574
3621
|
if (parsed.length > this.#items) throw new ScaffoldError("INVALID", "Sync dependency count exceeds its item limit", {
|
|
3575
3622
|
items: parsed.length,
|
|
3576
3623
|
limit: this.#items
|
|
3577
3624
|
});
|
|
3578
|
-
return Sync.#runPool(parsed, this.#concurrency, async (
|
|
3579
|
-
const url = this.#registryUrl(
|
|
3625
|
+
return Sync.#runPool(parsed, this.#concurrency, async (name) => {
|
|
3626
|
+
const url = this.#registryUrl(name);
|
|
3580
3627
|
const outcome = await Sync.#fetchText(url, this.#registryTimeout, this.#retries, this.#limit, allowance, this.#controller.signal);
|
|
3581
|
-
const version = Sync.#
|
|
3628
|
+
const version = Sync.#toVersionLookup(name, outcome);
|
|
3582
3629
|
if (outcome.kind === "failed") this.#emitter.emit("error", outcome.error);
|
|
3583
|
-
this.#emitter.emit("version",
|
|
3630
|
+
this.#emitter.emit("version", name);
|
|
3584
3631
|
if (this.#strict && (version.freshness === "missing" || version.freshness === "failed")) throw new ScaffoldError("FETCH", `Failed to fetch registry version at ${url}`, {
|
|
3585
3632
|
url,
|
|
3586
|
-
name
|
|
3633
|
+
name
|
|
3587
3634
|
});
|
|
3588
3635
|
return version;
|
|
3589
3636
|
});
|
|
@@ -3616,16 +3663,9 @@ var Sync = class Sync {
|
|
|
3616
3663
|
*/
|
|
3617
3664
|
async catalog() {
|
|
3618
3665
|
this.#ensureAlive();
|
|
3619
|
-
const orgUrl = this.#orgUrl();
|
|
3620
3666
|
const allowance = Float64Array.of(this.#budget);
|
|
3621
|
-
const
|
|
3622
|
-
|
|
3623
|
-
if (names.length > this.#items) throw new ScaffoldError("FETCH", `Package list at ${orgUrl} exceeds the item limit`, {
|
|
3624
|
-
url: orgUrl,
|
|
3625
|
-
items: names.length,
|
|
3626
|
-
limit: this.#items
|
|
3627
|
-
});
|
|
3628
|
-
return [...await Sync.#runPool(names, this.#concurrency, async (name) => {
|
|
3667
|
+
const names = await this.#packages(allowance);
|
|
3668
|
+
return await Sync.#runPool(names, this.#concurrency, async (name) => {
|
|
3629
3669
|
const packumentOutcome = await Sync.#fetchText(this.#registryUrl(name), this.#registryTimeout, this.#retries, this.#limit, allowance, this.#controller.signal);
|
|
3630
3670
|
const packument = Sync.#toPackument(packumentOutcome);
|
|
3631
3671
|
const short = packageShortName(name);
|
|
@@ -3641,7 +3681,7 @@ var Sync = class Sync {
|
|
|
3641
3681
|
version: packument.version,
|
|
3642
3682
|
description
|
|
3643
3683
|
};
|
|
3644
|
-
})
|
|
3684
|
+
});
|
|
3645
3685
|
}
|
|
3646
3686
|
async pull(target, dependencies) {
|
|
3647
3687
|
this.#ensureAlive();
|
|
@@ -3650,10 +3690,21 @@ var Sync = class Sync {
|
|
|
3650
3690
|
const deps = dependencies === void 0 ? declared : parseSyncDependencies(dependencies, false);
|
|
3651
3691
|
if (dependencies !== void 0 && deps.some((dependency) => !declared.some((candidate) => candidate.name === dependency.name && candidate.range === dependency.range))) throw new ScaffoldError("INVALID", "Sync pull selection is not declared by the target");
|
|
3652
3692
|
const name = manifestToName(manifest);
|
|
3653
|
-
const
|
|
3654
|
-
const current = readGuideReferences(target,
|
|
3693
|
+
const guideNames = deps.map((dependency) => dependency.name).filter((dependency) => dependency !== name);
|
|
3694
|
+
const current = readGuideReferences(target, guideNames);
|
|
3655
3695
|
const allowance = Float64Array.of(this.#budget);
|
|
3656
|
-
const report = syncReportOf(target, await this.#guides(
|
|
3696
|
+
const report = syncReportOf(target, await this.#guides(guideNames, current, allowance), await this.#versions(deps, allowance));
|
|
3697
|
+
this.#emitter.emit("done", report);
|
|
3698
|
+
return report;
|
|
3699
|
+
}
|
|
3700
|
+
async mirror(target) {
|
|
3701
|
+
this.#ensureAlive();
|
|
3702
|
+
const manifest = readManifest(target);
|
|
3703
|
+
const name = manifestToName(manifest);
|
|
3704
|
+
const allowance = Float64Array.of(this.#budget);
|
|
3705
|
+
const names = (await this.#packages(allowance)).filter((candidate) => candidate !== name);
|
|
3706
|
+
const current = readGuideReferences(target, names);
|
|
3707
|
+
const report = syncReportOf(target, await this.#guides(names, current, allowance), []);
|
|
3657
3708
|
this.#emitter.emit("done", report);
|
|
3658
3709
|
return report;
|
|
3659
3710
|
}
|
|
@@ -3746,6 +3797,17 @@ var Sync = class Sync {
|
|
|
3746
3797
|
#orgUrl() {
|
|
3747
3798
|
return `${this.#registryBase}/-/org/orkestrel/package`;
|
|
3748
3799
|
}
|
|
3800
|
+
async #packages(allowance) {
|
|
3801
|
+
const url = this.#orgUrl();
|
|
3802
|
+
const outcome = await Sync.#fetchText(url, this.#registryTimeout, this.#retries, this.#limit, allowance, this.#controller.signal);
|
|
3803
|
+
const names = Sync.#toOrgPackages(outcome, url);
|
|
3804
|
+
if (names.length > this.#items) throw new ScaffoldError("FETCH", `Package list at ${url} exceeds the item limit`, {
|
|
3805
|
+
url,
|
|
3806
|
+
items: names.length,
|
|
3807
|
+
limit: this.#items
|
|
3808
|
+
});
|
|
3809
|
+
return [...names].sort((left, right) => left < right ? -1 : left > right ? 1 : 0);
|
|
3810
|
+
}
|
|
3749
3811
|
static async #runPool(items, concurrency, worker) {
|
|
3750
3812
|
const results = new Array(items.length);
|
|
3751
3813
|
const state = {
|
|
@@ -3924,34 +3986,42 @@ var Sync = class Sync {
|
|
|
3924
3986
|
...baseline === void 0 ? {} : { baseline }
|
|
3925
3987
|
};
|
|
3926
3988
|
}
|
|
3927
|
-
static #
|
|
3989
|
+
static #toVersionLookup(name, outcome) {
|
|
3928
3990
|
if (outcome.kind === "missing") return {
|
|
3929
|
-
name
|
|
3930
|
-
range: dep.range,
|
|
3931
|
-
latest: "",
|
|
3991
|
+
name,
|
|
3932
3992
|
freshness: "missing",
|
|
3933
3993
|
note: "HTTP 404"
|
|
3934
3994
|
};
|
|
3935
3995
|
if (outcome.kind === "failed") return {
|
|
3936
|
-
name
|
|
3937
|
-
range: dep.range,
|
|
3938
|
-
latest: "",
|
|
3996
|
+
name,
|
|
3939
3997
|
freshness: "failed",
|
|
3940
3998
|
note: outcome.note
|
|
3941
3999
|
};
|
|
3942
4000
|
const latest = Sync.#parseLatest(outcome.text);
|
|
3943
4001
|
if (latest === void 0) return {
|
|
4002
|
+
name,
|
|
4003
|
+
freshness: "failed",
|
|
4004
|
+
note: "malformed registry response (missing dist-tags.latest)"
|
|
4005
|
+
};
|
|
4006
|
+
return {
|
|
4007
|
+
name,
|
|
4008
|
+
latest,
|
|
4009
|
+
freshness: "behind"
|
|
4010
|
+
};
|
|
4011
|
+
}
|
|
4012
|
+
static #toVersionSync(dep, lookup) {
|
|
4013
|
+
if (lookup.freshness !== "behind") return {
|
|
3944
4014
|
name: dep.name,
|
|
3945
4015
|
range: dep.range,
|
|
3946
4016
|
latest: "",
|
|
3947
|
-
freshness:
|
|
3948
|
-
note:
|
|
4017
|
+
freshness: lookup.freshness,
|
|
4018
|
+
note: lookup.note
|
|
3949
4019
|
};
|
|
3950
4020
|
return {
|
|
3951
4021
|
name: dep.name,
|
|
3952
4022
|
range: dep.range,
|
|
3953
|
-
latest,
|
|
3954
|
-
freshness: rangeToFreshness(dep.range, latest)
|
|
4023
|
+
latest: lookup.latest,
|
|
4024
|
+
freshness: rangeToFreshness(dep.range, lookup.latest)
|
|
3955
4025
|
};
|
|
3956
4026
|
}
|
|
3957
4027
|
static #toOrgPackages(outcome, url) {
|
|
@@ -4075,6 +4145,6 @@ function createSync(options) {
|
|
|
4075
4145
|
return new Sync(options);
|
|
4076
4146
|
}
|
|
4077
4147
|
//#endregion
|
|
4078
|
-
export { DEFAULT_SYNC_BUDGET, DEFAULT_SYNC_CONCURRENCY, DEFAULT_SYNC_ITEMS, DEFAULT_SYNC_LIMIT, DEFAULT_SYNC_TIMEOUT, HOST_MANIFEST_PATH, MAX_CATALOG_DESCRIPTION_LENGTH, MAX_FILESYSTEM_DEPTH, MAX_GUIDE_BYTES, MAX_HOST_DEPTH, MAX_HOST_ENTRIES, MAX_PATH_SEGMENT_BYTES, MAX_SYNC_BASE_LENGTH, MAX_SYNC_BRANCH_LENGTH, MAX_SYNC_BUDGET, MAX_SYNC_CONCURRENCY, MAX_SYNC_ITEMS, MAX_SYNC_LIMIT, MAX_SYNC_RETRIES, MAX_SYNC_TIMEOUT, Materializer, PRUNE_DIRECTORIES, RESERVED_PATH_SEGMENT_PATTERN, RESERVED_TARGET_PATH_PATTERN, SENSITIVE_HOST_PATH_PATTERN, SYNC_BRANCH_PATTERN, Sync, WRITE_DIGEST_PATTERN, WriteTransaction, catalogPackages, commitWriteTransaction, consumeCatalogAllowance, createMaterializer, createSync, createWriteDirectory, deriveBlueprint, digestFile, digestHex, digestText, discardWriteTransaction, discoverPackages, guideStub, guideToDescription, hostRoot, hydratePlan, isCatalogAllowance, isCatalogDescription, isDependencyData, isFilesystemPath, isHostManifest, isManifestEntry, isMaterializerEventHooks, isMissingPathError, isPortablePath, isRealDirectory, isRealFile, isReservedTargetPath, isSensitiveHostPath, isSyncEventHooks, isTerminalText, isVacant, isWritePrecondition, listDirectories, listFiles, locateHostSource, materializerOptionsContract, materializerOptionsShape, packageShortName, parseFilesystemPaths, parseMaterializerOptions, parsePortablePaths, parseSyncBase, parseSyncBranch, parseSyncCurrent, parseSyncDependencies, parseSyncOptions, parseWritePreconditions, pruneTargets, readFileHex, readFileText, readGuideReferences, readHostManifest, readManifest, readTarget, remapArtifactPath, replaceDirectory, resolveContainedPath, resolveGuideWrites, resolvePhysicalPath, resolveRealPath, restoreFiles, selectOrkestrelEntries, stageHost, storagePath, syncGuideOptionsShape, syncOptionsContract, syncOptionsShape, syncRegistryOptionsShape, syncReportOf, validateWriteAnchor, validateWriteDirectories, validateWriteTarget, vendoredPruneSet };
|
|
4148
|
+
export { DEFAULT_SYNC_BUDGET, DEFAULT_SYNC_CONCURRENCY, DEFAULT_SYNC_ITEMS, DEFAULT_SYNC_LIMIT, DEFAULT_SYNC_TIMEOUT, HOST_MANIFEST_PATH, MAX_CATALOG_DESCRIPTION_LENGTH, MAX_FILESYSTEM_DEPTH, MAX_GUIDE_BYTES, MAX_HOST_DEPTH, MAX_HOST_ENTRIES, MAX_PATH_SEGMENT_BYTES, MAX_SYNC_BASE_LENGTH, MAX_SYNC_BRANCH_LENGTH, MAX_SYNC_BUDGET, MAX_SYNC_CONCURRENCY, MAX_SYNC_ITEMS, MAX_SYNC_LIMIT, MAX_SYNC_RETRIES, MAX_SYNC_TIMEOUT, Materializer, PRUNE_DIRECTORIES, RESERVED_PATH_SEGMENT_PATTERN, RESERVED_TARGET_PATH_PATTERN, SENSITIVE_HOST_PATH_PATTERN, SYNC_BRANCH_PATTERN, Sync, WRITE_DIGEST_PATTERN, WriteTransaction, catalogPackages, commitWriteTransaction, consumeCatalogAllowance, createMaterializer, createSync, createWriteDirectory, deriveBlueprint, digestFile, digestHex, digestText, discardWriteTransaction, discoverPackages, guideStub, guideToDescription, hostRoot, hydratePlan, isCatalogAllowance, isCatalogDescription, isDependencyData, isFilesystemPath, isHostManifest, isManifestEntry, isMaterializerEventHooks, isMissingPathError, isPortablePath, isRealDirectory, isRealFile, isReservedTargetPath, isSensitiveHostPath, isSyncEventHooks, isTerminalText, isVacant, isWritePrecondition, listDirectories, listFiles, locateHostSource, materializerOptionsContract, materializerOptionsShape, packageShortName, parseFilesystemPaths, parseMaterializerOptions, parsePortablePaths, parseSyncBase, parseSyncBranch, parseSyncCurrent, parseSyncDependencies, parseSyncNames, parseSyncOptions, parseWritePreconditions, pruneTargets, readFileHex, readFileText, readGuideReferences, readHostManifest, readManifest, readTarget, remapArtifactPath, replaceDirectory, resolveContainedPath, resolveGuideWrites, resolvePhysicalPath, resolveRealPath, restoreFiles, selectOrkestrelEntries, stageHost, storagePath, syncGuideOptionsShape, syncOptionsContract, syncOptionsShape, syncRegistryOptionsShape, syncReportOf, validateWriteAnchor, validateWriteDirectories, validateWriteTarget, vendoredPruneSet };
|
|
4079
4149
|
|
|
4080
4150
|
//# sourceMappingURL=index.js.map
|