@orkestrel/scaffold 0.0.14 → 0.0.16

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.
@@ -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
  *
@@ -1041,6 +1049,7 @@ export declare class Sync implements SyncInterface {
1041
1049
  #private;
1042
1050
  constructor(options?: SyncOptions);
1043
1051
  get emitter(): EmitterInterface<SyncEventMap>;
1052
+ lookup(names: readonly string[]): Promise<readonly VersionLookup[]>;
1044
1053
  guides(deps: readonly Dependency[], current?: Readonly<Record<string, string>>): Promise<readonly GuideSync[]>;
1045
1054
  versions(deps: readonly Dependency[]): Promise<readonly VersionSync[]>;
1046
1055
  /**
@@ -1121,6 +1130,7 @@ export declare function syncGuideOptionsShape(): ObjectShape<{
1121
1130
  */
1122
1131
  export declare interface SyncInterface {
1123
1132
  readonly emitter: EmitterInterface<SyncEventMap>;
1133
+ lookup(names: readonly string[]): Promise<readonly VersionLookup[]>;
1124
1134
  guides(deps: readonly Dependency[], current?: Readonly<Record<string, string>>): Promise<readonly GuideSync[]>;
1125
1135
  versions(deps: readonly Dependency[]): Promise<readonly VersionSync[]>;
1126
1136
  catalog(): Promise<readonly CatalogEntry[]>;
@@ -1282,6 +1292,17 @@ export declare function validateWriteTarget(transaction: WriteTransaction, owned
1282
1292
  */
1283
1293
  export declare function vendoredPruneSet(host: string, directory: string): ReadonlySet<string>;
1284
1294
 
1295
+ /** One bare-name registry lookup, without a caller-invented declaration range. */
1296
+ export declare type VersionLookup = {
1297
+ readonly name: string;
1298
+ readonly latest: string;
1299
+ readonly freshness: 'behind';
1300
+ } | {
1301
+ readonly name: string;
1302
+ readonly freshness: 'missing' | 'failed';
1303
+ readonly note: string;
1304
+ };
1305
+
1285
1306
  /** Exact SHA-256 digest accepted by write preconditions. */
1286
1307
  export declare const WRITE_DIGEST_PATTERN: RegExp;
1287
1308
 
@@ -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
  *
@@ -1041,6 +1049,7 @@ export declare class Sync implements SyncInterface {
1041
1049
  #private;
1042
1050
  constructor(options?: SyncOptions);
1043
1051
  get emitter(): EmitterInterface<SyncEventMap>;
1052
+ lookup(names: readonly string[]): Promise<readonly VersionLookup[]>;
1044
1053
  guides(deps: readonly Dependency[], current?: Readonly<Record<string, string>>): Promise<readonly GuideSync[]>;
1045
1054
  versions(deps: readonly Dependency[]): Promise<readonly VersionSync[]>;
1046
1055
  /**
@@ -1121,6 +1130,7 @@ export declare function syncGuideOptionsShape(): ObjectShape<{
1121
1130
  */
1122
1131
  export declare interface SyncInterface {
1123
1132
  readonly emitter: EmitterInterface<SyncEventMap>;
1133
+ lookup(names: readonly string[]): Promise<readonly VersionLookup[]>;
1124
1134
  guides(deps: readonly Dependency[], current?: Readonly<Record<string, string>>): Promise<readonly GuideSync[]>;
1125
1135
  versions(deps: readonly Dependency[]): Promise<readonly VersionSync[]>;
1126
1136
  catalog(): Promise<readonly CatalogEntry[]>;
@@ -1282,6 +1292,17 @@ export declare function validateWriteTarget(transaction: WriteTransaction, owned
1282
1292
  */
1283
1293
  export declare function vendoredPruneSet(host: string, directory: string): ReadonlySet<string>;
1284
1294
 
1295
+ /** One bare-name registry lookup, without a caller-invented declaration range. */
1296
+ export declare type VersionLookup = {
1297
+ readonly name: string;
1298
+ readonly latest: string;
1299
+ readonly freshness: 'behind';
1300
+ } | {
1301
+ readonly name: string;
1302
+ readonly freshness: 'missing' | 'failed';
1303
+ readonly note: string;
1304
+ };
1305
+
1285
1306
  /** Exact SHA-256 digest accepted by write preconditions. */
1286
1307
  export declare const WRITE_DIGEST_PATTERN: RegExp;
1287
1308
 
@@ -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(() => {
@@ -3540,6 +3568,10 @@ var Sync = class Sync {
3540
3568
  get emitter() {
3541
3569
  return this.#emitter;
3542
3570
  }
3571
+ async lookup(names) {
3572
+ this.#ensureAlive();
3573
+ return this.#lookup(names, Float64Array.of(this.#budget));
3574
+ }
3543
3575
  async guides(deps, current) {
3544
3576
  this.#ensureAlive();
3545
3577
  return this.#guides(deps, current, Float64Array.of(this.#budget));
@@ -3569,21 +3601,33 @@ var Sync = class Sync {
3569
3601
  return guide;
3570
3602
  });
3571
3603
  }
3572
- #versions(deps, allowance) {
3604
+ async #versions(deps, allowance) {
3573
3605
  const parsed = parseSyncDependencies(deps, true);
3606
+ const lookups = await this.#lookup(parsed.map((dependency) => dependency.name), allowance);
3607
+ const versions = [];
3608
+ for (let index = 0; index < parsed.length; index += 1) {
3609
+ const dep = parsed[index];
3610
+ const lookup = lookups[index];
3611
+ if (dep === void 0 || lookup === void 0) throw new ScaffoldError("INVALID", "Sync version lookup result is incomplete");
3612
+ versions.push(Sync.#toVersionSync(dep, lookup));
3613
+ }
3614
+ return Object.freeze(versions);
3615
+ }
3616
+ #lookup(names, allowance) {
3617
+ const parsed = parseSyncNames(names);
3574
3618
  if (parsed.length > this.#items) throw new ScaffoldError("INVALID", "Sync dependency count exceeds its item limit", {
3575
3619
  items: parsed.length,
3576
3620
  limit: this.#items
3577
3621
  });
3578
- return Sync.#runPool(parsed, this.#concurrency, async (dep) => {
3579
- const url = this.#registryUrl(dep.name);
3622
+ return Sync.#runPool(parsed, this.#concurrency, async (name) => {
3623
+ const url = this.#registryUrl(name);
3580
3624
  const outcome = await Sync.#fetchText(url, this.#registryTimeout, this.#retries, this.#limit, allowance, this.#controller.signal);
3581
- const version = Sync.#toVersionSync(dep, outcome);
3625
+ const version = Sync.#toVersionLookup(name, outcome);
3582
3626
  if (outcome.kind === "failed") this.#emitter.emit("error", outcome.error);
3583
- this.#emitter.emit("version", dep.name);
3627
+ this.#emitter.emit("version", name);
3584
3628
  if (this.#strict && (version.freshness === "missing" || version.freshness === "failed")) throw new ScaffoldError("FETCH", `Failed to fetch registry version at ${url}`, {
3585
3629
  url,
3586
- name: dep.name
3630
+ name
3587
3631
  });
3588
3632
  return version;
3589
3633
  });
@@ -3924,34 +3968,42 @@ var Sync = class Sync {
3924
3968
  ...baseline === void 0 ? {} : { baseline }
3925
3969
  };
3926
3970
  }
3927
- static #toVersionSync(dep, outcome) {
3971
+ static #toVersionLookup(name, outcome) {
3928
3972
  if (outcome.kind === "missing") return {
3929
- name: dep.name,
3930
- range: dep.range,
3931
- latest: "",
3973
+ name,
3932
3974
  freshness: "missing",
3933
3975
  note: "HTTP 404"
3934
3976
  };
3935
3977
  if (outcome.kind === "failed") return {
3936
- name: dep.name,
3937
- range: dep.range,
3938
- latest: "",
3978
+ name,
3939
3979
  freshness: "failed",
3940
3980
  note: outcome.note
3941
3981
  };
3942
3982
  const latest = Sync.#parseLatest(outcome.text);
3943
3983
  if (latest === void 0) return {
3984
+ name,
3985
+ freshness: "failed",
3986
+ note: "malformed registry response (missing dist-tags.latest)"
3987
+ };
3988
+ return {
3989
+ name,
3990
+ latest,
3991
+ freshness: "behind"
3992
+ };
3993
+ }
3994
+ static #toVersionSync(dep, lookup) {
3995
+ if (lookup.freshness !== "behind") return {
3944
3996
  name: dep.name,
3945
3997
  range: dep.range,
3946
3998
  latest: "",
3947
- freshness: "failed",
3948
- note: "malformed registry response (missing dist-tags.latest)"
3999
+ freshness: lookup.freshness,
4000
+ note: lookup.note
3949
4001
  };
3950
4002
  return {
3951
4003
  name: dep.name,
3952
4004
  range: dep.range,
3953
- latest,
3954
- freshness: rangeToFreshness(dep.range, latest)
4005
+ latest: lookup.latest,
4006
+ freshness: rangeToFreshness(dep.range, lookup.latest)
3955
4007
  };
3956
4008
  }
3957
4009
  static #toOrgPackages(outcome, url) {
@@ -4075,6 +4127,6 @@ function createSync(options) {
4075
4127
  return new Sync(options);
4076
4128
  }
4077
4129
  //#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 };
4130
+ 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
4131
 
4080
4132
  //# sourceMappingURL=index.js.map