@orkestrel/scaffold 0.0.7 → 0.0.8

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.
@@ -139,16 +139,16 @@ export declare const DEFAULT_SYNC_TIMEOUT = 10000;
139
139
  * and the name satisfies `isWorkspaceName`; every other name is a coded
140
140
  * `TARGET` failure. `src` is derived from `src/<environment>/` and `app` from
141
141
  * `app/<environment>/`; a target with no environment on either axis is also a coded
142
- * `TARGET` failure. `dependencies` /
142
+ * `TARGET` failure. The `bin`, `integration`, and `service` facts probe physical
143
+ * directories at `src/bin`, `tests/integration`, and `tests/service`, respectively,
144
+ * never the workspace name. `dependencies` /
143
145
  * `peers` are the `@orkestrel/`-prefixed entries of `manifest.dependencies` /
144
146
  * `manifest.peerDependencies` (a peer flagged `peerDependenciesMeta[name]
145
147
  * .optional === true` carries `optional: true`). `extras` is EVERY entry of
146
148
  * `manifest.devDependencies` (not only `@orkestrel/`-prefixed ones — an
147
- * external extra like `zod` must round-trip too), EXCLUDING the generated
148
- * devDependency baseline (`devDependenciesFor([])`'s keys, which already
149
- * cover `@orkestrel/guide` and `@orkestrel/scaffold`) every scaffolded
150
- * package already carries, never a package-specific extra. A devDependency
151
- * ALSO present in
149
+ * external extra like `zod` must round-trip too), EXCLUDING the complete
150
+ * generated dependency set `devDependenciesFor` emits for the reconstructed
151
+ * blueprint's actual environments and structural axes. A devDependency ALSO present in
152
152
  * `manifest.peerDependencies` or `manifest.dependencies` (e.g. a peer
153
153
  * dev-installed for local testing) is likewise excluded from `extras` — it
154
154
  * already appears as a `peer`/`dependency` above, and double-counting it as
@@ -159,6 +159,8 @@ export declare const DEFAULT_SYNC_TIMEOUT = 10000;
159
159
  * @throws `ScaffoldError('TARGET', …)` when `target`'s manifest is unreadable
160
160
  * (via `readManifest`), is not valid JSON, its name is unsafe for its
161
161
  * publication mode, or `target` carries no source or application environment.
162
+ * @throws `ScaffoldError('TARGET', …)` when `tests/service` exists without the
163
+ * physical companion files `tests/setupService.ts` and `scripts/service.sh`.
162
164
  *
163
165
  * @example
164
166
  * ```ts
@@ -364,6 +366,14 @@ export declare function isPortablePath(value: unknown): value is string;
364
366
  */
365
367
  export declare function isRealDirectory(path: string): boolean;
366
368
 
369
+ /**
370
+ * Whether a path is an existing physical file rather than a directory or link.
371
+ *
372
+ * @param path - The filesystem path to inspect without following links.
373
+ * @returns `true` only for a successful `lstat` reporting a single-link file.
374
+ */
375
+ export declare function isRealFile(path: string): boolean;
376
+
367
377
  /** Determine whether a target-relative path addresses preserved repository metadata. */
368
378
  export declare function isReservedTargetPath(value: string): boolean;
369
379
 
@@ -139,16 +139,16 @@ export declare const DEFAULT_SYNC_TIMEOUT = 10000;
139
139
  * and the name satisfies `isWorkspaceName`; every other name is a coded
140
140
  * `TARGET` failure. `src` is derived from `src/<environment>/` and `app` from
141
141
  * `app/<environment>/`; a target with no environment on either axis is also a coded
142
- * `TARGET` failure. `dependencies` /
142
+ * `TARGET` failure. The `bin`, `integration`, and `service` facts probe physical
143
+ * directories at `src/bin`, `tests/integration`, and `tests/service`, respectively,
144
+ * never the workspace name. `dependencies` /
143
145
  * `peers` are the `@orkestrel/`-prefixed entries of `manifest.dependencies` /
144
146
  * `manifest.peerDependencies` (a peer flagged `peerDependenciesMeta[name]
145
147
  * .optional === true` carries `optional: true`). `extras` is EVERY entry of
146
148
  * `manifest.devDependencies` (not only `@orkestrel/`-prefixed ones — an
147
- * external extra like `zod` must round-trip too), EXCLUDING the generated
148
- * devDependency baseline (`devDependenciesFor([])`'s keys, which already
149
- * cover `@orkestrel/guide` and `@orkestrel/scaffold`) every scaffolded
150
- * package already carries, never a package-specific extra. A devDependency
151
- * ALSO present in
149
+ * external extra like `zod` must round-trip too), EXCLUDING the complete
150
+ * generated dependency set `devDependenciesFor` emits for the reconstructed
151
+ * blueprint's actual environments and structural axes. A devDependency ALSO present in
152
152
  * `manifest.peerDependencies` or `manifest.dependencies` (e.g. a peer
153
153
  * dev-installed for local testing) is likewise excluded from `extras` — it
154
154
  * already appears as a `peer`/`dependency` above, and double-counting it as
@@ -159,6 +159,8 @@ export declare const DEFAULT_SYNC_TIMEOUT = 10000;
159
159
  * @throws `ScaffoldError('TARGET', …)` when `target`'s manifest is unreadable
160
160
  * (via `readManifest`), is not valid JSON, its name is unsafe for its
161
161
  * publication mode, or `target` carries no source or application environment.
162
+ * @throws `ScaffoldError('TARGET', …)` when `tests/service` exists without the
163
+ * physical companion files `tests/setupService.ts` and `scripts/service.sh`.
162
164
  *
163
165
  * @example
164
166
  * ```ts
@@ -364,6 +366,14 @@ export declare function isPortablePath(value: unknown): value is string;
364
366
  */
365
367
  export declare function isRealDirectory(path: string): boolean;
366
368
 
369
+ /**
370
+ * Whether a path is an existing physical file rather than a directory or link.
371
+ *
372
+ * @param path - The filesystem path to inspect without following links.
373
+ * @returns `true` only for a successful `lstat` reporting a single-link file.
374
+ */
375
+ export declare function isRealFile(path: string): boolean;
376
+
367
377
  /** Determine whether a target-relative path addresses preserved repository metadata. */
368
378
  export declare function isReservedTargetPath(value: string): boolean;
369
379
 
@@ -1,4 +1,4 @@
1
- import { CONTROL_CHARACTER_PATTERN, DEFAULT_ENGINES, DEFAULT_VERSION, DEPENDENCY_NAME_PATTERN, ENVIRONMENTS, 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, 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, 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";
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, realpathSync, renameSync, rmSync, rmdirSync, writeFileSync } from "node:fs";
@@ -845,6 +845,16 @@ function isRealDirectory(path) {
845
845
  return status.success && status.value;
846
846
  }
847
847
  /**
848
+ * Whether a path is an existing physical file rather than a directory or link.
849
+ *
850
+ * @param path - The filesystem path to inspect without following links.
851
+ * @returns `true` only for a successful `lstat` reporting a single-link file.
852
+ */
853
+ function isRealFile(path) {
854
+ const status = attempt(() => lstatSync(path));
855
+ return status.success && status.value.isFile() && !status.value.isSymbolicLink() && status.value.nlink === 1;
856
+ }
857
+ /**
848
858
  * Compute a bounded-memory SHA-256 digest for one file.
849
859
  *
850
860
  * @param path - The file to read.
@@ -1733,16 +1743,16 @@ function selectOrkestrelEntries(value) {
1733
1743
  * and the name satisfies `isWorkspaceName`; every other name is a coded
1734
1744
  * `TARGET` failure. `src` is derived from `src/<environment>/` and `app` from
1735
1745
  * `app/<environment>/`; a target with no environment on either axis is also a coded
1736
- * `TARGET` failure. `dependencies` /
1746
+ * `TARGET` failure. The `bin`, `integration`, and `service` facts probe physical
1747
+ * directories at `src/bin`, `tests/integration`, and `tests/service`, respectively,
1748
+ * never the workspace name. `dependencies` /
1737
1749
  * `peers` are the `@orkestrel/`-prefixed entries of `manifest.dependencies` /
1738
1750
  * `manifest.peerDependencies` (a peer flagged `peerDependenciesMeta[name]
1739
1751
  * .optional === true` carries `optional: true`). `extras` is EVERY entry of
1740
1752
  * `manifest.devDependencies` (not only `@orkestrel/`-prefixed ones — an
1741
- * external extra like `zod` must round-trip too), EXCLUDING the generated
1742
- * devDependency baseline (`devDependenciesFor([])`'s keys, which already
1743
- * cover `@orkestrel/guide` and `@orkestrel/scaffold`) every scaffolded
1744
- * package already carries, never a package-specific extra. A devDependency
1745
- * ALSO present in
1753
+ * external extra like `zod` must round-trip too), EXCLUDING the complete
1754
+ * generated dependency set `devDependenciesFor` emits for the reconstructed
1755
+ * blueprint's actual environments and structural axes. A devDependency ALSO present in
1746
1756
  * `manifest.peerDependencies` or `manifest.dependencies` (e.g. a peer
1747
1757
  * dev-installed for local testing) is likewise excluded from `extras` — it
1748
1758
  * already appears as a `peer`/`dependency` above, and double-counting it as
@@ -1753,6 +1763,8 @@ function selectOrkestrelEntries(value) {
1753
1763
  * @throws `ScaffoldError('TARGET', …)` when `target`'s manifest is unreadable
1754
1764
  * (via `readManifest`), is not valid JSON, its name is unsafe for its
1755
1765
  * publication mode, or `target` carries no source or application environment.
1766
+ * @throws `ScaffoldError('TARGET', …)` when `tests/service` exists without the
1767
+ * physical companion files `tests/setupService.ts` and `scripts/service.sh`.
1756
1768
  *
1757
1769
  * @example
1758
1770
  * ```ts
@@ -1762,11 +1774,6 @@ function selectOrkestrelEntries(value) {
1762
1774
  * ```
1763
1775
  */
1764
1776
  function deriveBlueprint(target) {
1765
- const baselineExtras = /* @__PURE__ */ new Set([
1766
- ...Object.keys(devDependenciesFor([])),
1767
- "@orkestrel/guide",
1768
- "@orkestrel/scaffold"
1769
- ]);
1770
1777
  const parsed = parseJSON(readManifest(target));
1771
1778
  if (!isRecord(parsed)) throw new ScaffoldError("TARGET", `Manifest at ${target} is not a valid JSON object`, { target });
1772
1779
  const src = ENVIRONMENTS.filter((environment) => isRealDirectory(join(target, "src", environment)));
@@ -1793,7 +1800,18 @@ function deriveBlueprint(target) {
1793
1800
  const version = typeof rawVersion === "string" ? rawVersion : DEFAULT_VERSION;
1794
1801
  const rawNode = ownDataValue(ownDataValue(parsed, "engines"), "node");
1795
1802
  const engines = typeof rawNode === "string" ? rawNode : DEFAULT_ENGINES;
1796
- const engine = isRealDirectory(join(target, "src", "bin"));
1803
+ const bin = isRealDirectory(join(target, "src", "bin"));
1804
+ const integration = isRealDirectory(join(target, "tests", "integration"));
1805
+ const service = isRealDirectory(join(target, "tests", "service"));
1806
+ if (service) {
1807
+ const missing = [];
1808
+ if (!isRealFile(join(target, "tests", "setupService.ts"))) missing.push("tests/setupService.ts");
1809
+ if (!isRealFile(join(target, SERVICE_SCRIPT_PATH))) missing.push(SERVICE_SCRIPT_PATH);
1810
+ if (missing.length > 0) throw new ScaffoldError("TARGET", `Service tests under ${target} are missing ${missing.join(" and ")}`, {
1811
+ target,
1812
+ missing
1813
+ });
1814
+ }
1797
1815
  const rawDependencies = ownDataValue(parsed, "dependencies");
1798
1816
  const rawPeerDependencies = ownDataValue(parsed, "peerDependencies");
1799
1817
  const dependencies = selectOrkestrelEntries(rawDependencies).map(([depName, range]) => ({
@@ -1814,9 +1832,19 @@ function deriveBlueprint(target) {
1814
1832
  };
1815
1833
  });
1816
1834
  const peerAndDependencyNames = /* @__PURE__ */ new Set([...selectOrkestrelEntries(rawPeerDependencies).map(([depName]) => depName), ...selectOrkestrelEntries(rawDependencies).map(([depName]) => depName)]);
1835
+ const generatedDevDependencies = new Set(Object.keys(devDependenciesFor(blueprint(name, {
1836
+ src,
1837
+ app,
1838
+ dependencies,
1839
+ peers,
1840
+ extras: [],
1841
+ bin,
1842
+ integration,
1843
+ service
1844
+ }))));
1817
1845
  const rawDevDependencies = ownDataValue(parsed, "devDependencies");
1818
1846
  const devDependencies = isRecord(rawDevDependencies) ? rawDevDependencies : {};
1819
- const extras = Object.entries(devDependencies).filter((entry) => typeof entry[1] === "string").filter(([depName]) => !baselineExtras.has(depName) && !peerAndDependencyNames.has(depName)).map(([depName, range]) => ({
1847
+ const extras = Object.entries(devDependencies).filter((entry) => typeof entry[1] === "string").filter(([depName]) => !generatedDevDependencies.has(depName) && !peerAndDependencyNames.has(depName)).map(([depName, range]) => ({
1820
1848
  name: depName,
1821
1849
  range
1822
1850
  }));
@@ -1831,7 +1859,9 @@ function deriveBlueprint(target) {
1831
1859
  version,
1832
1860
  engines,
1833
1861
  overrides: [],
1834
- engine
1862
+ bin,
1863
+ integration,
1864
+ service
1835
1865
  });
1836
1866
  }
1837
1867
  /**
@@ -4033,6 +4063,6 @@ function createSync(options) {
4033
4063
  return new Sync(options);
4034
4064
  }
4035
4065
  //#endregion
4036
- 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, 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 };
4066
+ 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 };
4037
4067
 
4038
4068
  //# sourceMappingURL=index.js.map