@sublang/slc 0.1.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/LICENSE +201 -0
- package/README.md +192 -0
- package/dist/app.d.ts +85 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +233 -0
- package/dist/app.js.map +1 -0
- package/dist/artifacts.d.ts +61 -0
- package/dist/artifacts.d.ts.map +1 -0
- package/dist/artifacts.js +97 -0
- package/dist/artifacts.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +26 -0
- package/dist/cli.js.map +1 -0
- package/dist/cligent-agent.d.ts +11 -0
- package/dist/cligent-agent.d.ts.map +1 -0
- package/dist/cligent-agent.js +66 -0
- package/dist/cligent-agent.js.map +1 -0
- package/dist/compiled-executor.d.ts +42 -0
- package/dist/compiled-executor.d.ts.map +1 -0
- package/dist/compiled-executor.js +433 -0
- package/dist/compiled-executor.js.map +1 -0
- package/dist/config-file.d.ts +52 -0
- package/dist/config-file.d.ts.map +1 -0
- package/dist/config-file.js +159 -0
- package/dist/config-file.js.map +1 -0
- package/dist/config.d.ts +82 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +161 -0
- package/dist/config.js.map +1 -0
- package/dist/entry-module.d.ts +22 -0
- package/dist/entry-module.d.ts.map +1 -0
- package/dist/entry-module.js +216 -0
- package/dist/entry-module.js.map +1 -0
- package/dist/execution.d.ts +71 -0
- package/dist/execution.d.ts.map +1 -0
- package/dist/execution.js +207 -0
- package/dist/execution.js.map +1 -0
- package/dist/file-capability.d.ts +46 -0
- package/dist/file-capability.d.ts.map +1 -0
- package/dist/file-capability.js +234 -0
- package/dist/file-capability.js.map +1 -0
- package/dist/file-grants.d.ts +79 -0
- package/dist/file-grants.d.ts.map +1 -0
- package/dist/file-grants.js +133 -0
- package/dist/file-grants.js.map +1 -0
- package/dist/hash.d.ts +14 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +34 -0
- package/dist/hash.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/interpreter.d.ts +48 -0
- package/dist/interpreter.d.ts.map +1 -0
- package/dist/interpreter.js +118 -0
- package/dist/interpreter.js.map +1 -0
- package/dist/invocation.d.ts +64 -0
- package/dist/invocation.d.ts.map +1 -0
- package/dist/invocation.js +148 -0
- package/dist/invocation.js.map +1 -0
- package/dist/link.d.ts +63 -0
- package/dist/link.d.ts.map +1 -0
- package/dist/link.js +172 -0
- package/dist/link.js.map +1 -0
- package/dist/markdown.d.ts +12 -0
- package/dist/markdown.d.ts.map +1 -0
- package/dist/markdown.js +63 -0
- package/dist/markdown.js.map +1 -0
- package/dist/normalize.md +68 -0
- package/dist/phase-runner.d.ts +64 -0
- package/dist/phase-runner.d.ts.map +1 -0
- package/dist/phase-runner.js +322 -0
- package/dist/phase-runner.js.map +1 -0
- package/dist/phase.d.ts +62 -0
- package/dist/phase.d.ts.map +1 -0
- package/dist/phase.js +111 -0
- package/dist/phase.js.map +1 -0
- package/dist/pin-closure.d.ts +19 -0
- package/dist/pin-closure.d.ts.map +1 -0
- package/dist/pin-closure.js +110 -0
- package/dist/pin-closure.js.map +1 -0
- package/dist/pin-currency.d.ts +55 -0
- package/dist/pin-currency.d.ts.map +1 -0
- package/dist/pin-currency.js +435 -0
- package/dist/pin-currency.js.map +1 -0
- package/dist/pin-generate.d.ts +46 -0
- package/dist/pin-generate.d.ts.map +1 -0
- package/dist/pin-generate.js +131 -0
- package/dist/pin-generate.js.map +1 -0
- package/dist/pin-paths.d.ts +11 -0
- package/dist/pin-paths.d.ts.map +1 -0
- package/dist/pin-paths.js +108 -0
- package/dist/pin-paths.js.map +1 -0
- package/dist/pins.d.ts +84 -0
- package/dist/pins.d.ts.map +1 -0
- package/dist/pins.js +265 -0
- package/dist/pins.js.map +1 -0
- package/dist/pipeline.d.ts +61 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +147 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/playbook-contract.d.ts +194 -0
- package/dist/playbook-contract.d.ts.map +1 -0
- package/dist/playbook-contract.js +180 -0
- package/dist/playbook-contract.js.map +1 -0
- package/dist/playbook-ports.d.ts +53 -0
- package/dist/playbook-ports.d.ts.map +1 -0
- package/dist/playbook-ports.js +217 -0
- package/dist/playbook-ports.js.map +1 -0
- package/dist/resolver.d.ts +68 -0
- package/dist/resolver.d.ts.map +1 -0
- package/dist/resolver.js +133 -0
- package/dist/resolver.js.map +1 -0
- package/dist/runner.d.ts +45 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +506 -0
- package/dist/runner.js.map +1 -0
- package/dist/runtime-package.d.ts +7 -0
- package/dist/runtime-package.d.ts.map +1 -0
- package/dist/runtime-package.js +132 -0
- package/dist/runtime-package.js.map +1 -0
- package/dist/slc.config.template.yaml +5 -0
- package/dist/verify-coverage.d.ts +99 -0
- package/dist/verify-coverage.d.ts.map +1 -0
- package/dist/verify-coverage.js +1949 -0
- package/dist/verify-coverage.js.map +1 -0
- package/dist/verify-support.d.ts +10 -0
- package/dist/verify-support.d.ts.map +1 -0
- package/dist/verify-support.js +52 -0
- package/dist/verify-support.js.map +1 -0
- package/dist/verify.d.ts +393 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +1790 -0
- package/dist/verify.js.map +1 -0
- package/package.json +76 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
|
|
3
|
+
/**
|
|
4
|
+
* Pin generation: the explicit build-and-review flow that writes `slc.pins.json`
|
|
5
|
+
* (PIN-15; DR-007).
|
|
6
|
+
*
|
|
7
|
+
* This is the inverse of the currency validator: given a built and reviewed
|
|
8
|
+
* compiled artifact, {@link generatePinRecord} records — over committed bytes —
|
|
9
|
+
* the definition, compiled entry module and reviewed artifact bundle, the
|
|
10
|
+
* semantic-input closure derived from the definition's `## Pin Inputs`, and the
|
|
11
|
+
* link-target identity, so the resulting record validates as current.
|
|
12
|
+
* {@link writePinFile} writes the pin index for a pipeline directory. Generation
|
|
13
|
+
* is invoked only by an explicit build-and-review step, never during an ordinary
|
|
14
|
+
* pipeline run; `slc` does not regenerate or rewrite pins per invocation
|
|
15
|
+
* (DR-007 lifecycle). See specs/dev/pinning.md.
|
|
16
|
+
*/
|
|
17
|
+
import { writeFile } from 'node:fs/promises';
|
|
18
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
19
|
+
import { hashFile } from './hash.js';
|
|
20
|
+
import { deriveClosure } from './pin-closure.js';
|
|
21
|
+
import { artifactBundleLayoutIssue, hashTree } from './pin-currency.js';
|
|
22
|
+
import { resolvePinPath } from './pin-paths.js';
|
|
23
|
+
import { PINS_FILE, PIN_HASH_ALGORITHM, PIN_SCHEMA, PinError, } from './pins.js';
|
|
24
|
+
import { resolveRuntimePackage } from './runtime-package.js';
|
|
25
|
+
/** The default recorded path boundary (the pipeline directory). */
|
|
26
|
+
const BOUNDARY = '.';
|
|
27
|
+
/**
|
|
28
|
+
* Generates a current {@link PinRecord} for one phase from its committed inputs
|
|
29
|
+
* (PIN-15). The definition is recorded separately; the rest of its `## Pin Inputs`
|
|
30
|
+
* closure becomes the enumerated `semanticInputs`.
|
|
31
|
+
*/
|
|
32
|
+
export async function generatePinRecord(pipelineDir, spec, opts = {}) {
|
|
33
|
+
const boundary = opts.boundary ?? BOUNDARY;
|
|
34
|
+
const definitionResolved = resolvePinPath(pipelineDir, boundary, spec.definition, 'definition');
|
|
35
|
+
const closure = await deriveClosure(pipelineDir, boundary, spec.definition);
|
|
36
|
+
const semanticInputs = await Promise.all([...closure]
|
|
37
|
+
.filter((resolved) => resolved !== definitionResolved)
|
|
38
|
+
.sort()
|
|
39
|
+
.map(async (resolved) => {
|
|
40
|
+
const path = toPosix(relative(pipelineDir, resolved));
|
|
41
|
+
const hash = await hashFile(resolved);
|
|
42
|
+
const role = spec.roles?.[path];
|
|
43
|
+
return role === undefined ? { path, hash } : { path, hash, role };
|
|
44
|
+
}));
|
|
45
|
+
const artifactResolved = resolvePinPath(pipelineDir, boundary, spec.artifact, 'artifact');
|
|
46
|
+
const artifactBundleResolved = resolvePinPath(pipelineDir, boundary, spec.artifactBundle, 'artifactBundle');
|
|
47
|
+
const artifactRelative = relative(artifactBundleResolved, artifactResolved);
|
|
48
|
+
if (artifactRelative === '' ||
|
|
49
|
+
artifactRelative === '..' ||
|
|
50
|
+
artifactRelative.startsWith(`..${sep}`) ||
|
|
51
|
+
isAbsolute(artifactRelative) ||
|
|
52
|
+
dirname(artifactRelative) !== '.') {
|
|
53
|
+
throw new PinError('pin-invalid', 'artifact must be a direct child of artifactBundle');
|
|
54
|
+
}
|
|
55
|
+
const bundleLayout = await artifactBundleLayoutIssue(artifactBundleResolved, artifactResolved);
|
|
56
|
+
if (bundleLayout !== null) {
|
|
57
|
+
throw new PinError('pin-invalid', bundleLayout);
|
|
58
|
+
}
|
|
59
|
+
const linkResolved = resolvePinPath(pipelineDir, boundary, spec.linkTarget.locator, 'linkTarget.locator');
|
|
60
|
+
const identity = spec.linkTarget.kind === 'file'
|
|
61
|
+
? await hashFile(linkResolved)
|
|
62
|
+
: await hashTree(linkResolved);
|
|
63
|
+
const runtimeDependencies = await Promise.all((spec.runtimeDependencies ?? []).map(async (dependency) => {
|
|
64
|
+
const resolved = resolvePinPath(pipelineDir, boundary, dependency.locator, 'runtimeDependencies.locator');
|
|
65
|
+
const dependencyIdentity = dependency.kind === 'file'
|
|
66
|
+
? await hashFile(resolved)
|
|
67
|
+
: await hashTree(resolved);
|
|
68
|
+
if (dependency.kind === 'package') {
|
|
69
|
+
if (dependency.specifier === undefined) {
|
|
70
|
+
throw new PinError('pin-invalid', 'package runtime dependency must declare its import specifier');
|
|
71
|
+
}
|
|
72
|
+
let selected;
|
|
73
|
+
try {
|
|
74
|
+
selected = resolveRuntimePackage(artifactResolved, dependency.specifier).root;
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
throw new PinError('pin-invalid', `runtime dependency specifier cannot be resolved: ${messageOf(error)}`);
|
|
78
|
+
}
|
|
79
|
+
if (resolve(selected) !== resolve(resolved)) {
|
|
80
|
+
throw new PinError('pin-invalid', `runtime dependency locator is not the package selected by "${dependency.specifier}"`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return { ...dependency, identity: dependencyIdentity };
|
|
84
|
+
}));
|
|
85
|
+
const linkTarget = {
|
|
86
|
+
kind: spec.linkTarget.kind,
|
|
87
|
+
locator: spec.linkTarget.locator,
|
|
88
|
+
identity,
|
|
89
|
+
...(spec.linkTarget.provenance !== undefined
|
|
90
|
+
? { provenance: spec.linkTarget.provenance }
|
|
91
|
+
: {}),
|
|
92
|
+
};
|
|
93
|
+
return {
|
|
94
|
+
definition: {
|
|
95
|
+
path: spec.definition,
|
|
96
|
+
hash: await hashFile(definitionResolved),
|
|
97
|
+
},
|
|
98
|
+
artifact: { path: spec.artifact, hash: await hashFile(artifactResolved) },
|
|
99
|
+
artifactBundle: {
|
|
100
|
+
path: spec.artifactBundle,
|
|
101
|
+
hash: await hashTree(artifactBundleResolved, { rejectSymlinks: true }),
|
|
102
|
+
},
|
|
103
|
+
semanticInputs,
|
|
104
|
+
externalInputs: [...(spec.externalInputs ?? [])],
|
|
105
|
+
runtimeDependencies,
|
|
106
|
+
linkTarget,
|
|
107
|
+
...(spec.producer !== undefined ? { producer: spec.producer } : {}),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Writes the pin index `<pipelineDir>/slc.pins.json` for the given phase records
|
|
112
|
+
* and returns its path (PIN-15).
|
|
113
|
+
*/
|
|
114
|
+
export async function writePinFile(pipelineDir, pins, opts = {}) {
|
|
115
|
+
const file = {
|
|
116
|
+
schema: PIN_SCHEMA,
|
|
117
|
+
hashAlgorithm: PIN_HASH_ALGORITHM,
|
|
118
|
+
pathBoundary: { path: opts.boundary ?? BOUNDARY },
|
|
119
|
+
pins: { ...pins },
|
|
120
|
+
};
|
|
121
|
+
const path = join(pipelineDir, PINS_FILE);
|
|
122
|
+
await writeFile(path, `${JSON.stringify(file, null, 2)}\n`);
|
|
123
|
+
return path;
|
|
124
|
+
}
|
|
125
|
+
function toPosix(path) {
|
|
126
|
+
return path.split(sep).join('/');
|
|
127
|
+
}
|
|
128
|
+
function messageOf(error) {
|
|
129
|
+
return error instanceof Error ? error.message : String(error);
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=pin-generate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pin-generate.js","sourceRoot":"","sources":["../src/pin-generate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves a relative POSIX `relPath` against `pipelineDir`, requiring it to stay
|
|
3
|
+
* inside `boundary` (also a relative POSIX path from `pipelineDir`) (PIN-2, PIN-5).
|
|
4
|
+
*
|
|
5
|
+
* @returns the resolved absolute host path.
|
|
6
|
+
* @throws {PinError} (`pin-invalid`) when the recorded `boundary` is absolute
|
|
7
|
+
* (naming `pathBoundary.path`), or `relPath` is absolute or escapes the
|
|
8
|
+
* recorded boundary (naming `field`).
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolvePinPath(pipelineDir: string, boundary: string, relPath: string, field: string): string;
|
|
11
|
+
//# sourceMappingURL=pin-paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pin-paths.d.ts","sourceRoot":"","sources":["../src/pin-paths.ts"],"names":[],"mappings":"AA6BA;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,MAAM,CA0BR"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
|
|
3
|
+
/**
|
|
4
|
+
* Pin path-boundary resolution for the pin-currency validator (PIN-2, PIN-5;
|
|
5
|
+
* DR-007).
|
|
6
|
+
*
|
|
7
|
+
* Every pin path is a relative POSIX-style path resolved from the pipeline
|
|
8
|
+
* directory that contains `slc.pins.json`. Absolute paths are rejected. The pin
|
|
9
|
+
* file records one path boundary (a relative POSIX path, defaulting to `.`, the
|
|
10
|
+
* pipeline directory); every local pin path must resolve inside that boundary,
|
|
11
|
+
* so `..` is permitted only when the recorded boundary is wide enough to contain
|
|
12
|
+
* the result. A violation is a {@link PinError} naming the offending field, which
|
|
13
|
+
* the currency engine maps to a malformed verdict. See specs/dev/pinning.md.
|
|
14
|
+
*/
|
|
15
|
+
import { realpathSync } from 'node:fs';
|
|
16
|
+
import { basename, dirname, isAbsolute, relative, resolve, sep, } from 'node:path';
|
|
17
|
+
import { isAbsolute as posixIsAbsolute } from 'node:path/posix';
|
|
18
|
+
import { PinError } from './pins.js';
|
|
19
|
+
/**
|
|
20
|
+
* Resolves a relative POSIX `relPath` against `pipelineDir`, requiring it to stay
|
|
21
|
+
* inside `boundary` (also a relative POSIX path from `pipelineDir`) (PIN-2, PIN-5).
|
|
22
|
+
*
|
|
23
|
+
* @returns the resolved absolute host path.
|
|
24
|
+
* @throws {PinError} (`pin-invalid`) when the recorded `boundary` is absolute
|
|
25
|
+
* (naming `pathBoundary.path`), or `relPath` is absolute or escapes the
|
|
26
|
+
* recorded boundary (naming `field`).
|
|
27
|
+
*/
|
|
28
|
+
export function resolvePinPath(pipelineDir, boundary, relPath, field) {
|
|
29
|
+
requireRelative(boundary, 'pathBoundary.path');
|
|
30
|
+
requireRelative(relPath, field);
|
|
31
|
+
const boundaryRoot = resolve(pipelineDir, ...splitPosix(boundary));
|
|
32
|
+
const resolved = resolve(pipelineDir, ...splitPosix(relPath));
|
|
33
|
+
if (!isInside(boundaryRoot, resolved)) {
|
|
34
|
+
throw new PinError('pin-invalid', `${field} "${relPath}" escapes the path boundary`);
|
|
35
|
+
}
|
|
36
|
+
// Lexical containment is not enough: an in-boundary symlink can resolve to
|
|
37
|
+
// bytes outside the recorded boundary. Resolve the nearest existing
|
|
38
|
+
// ancestors so the check remains fail-closed even for a missing leaf.
|
|
39
|
+
const realBoundary = canonicalProspectivePath(boundaryRoot, 'pathBoundary.path');
|
|
40
|
+
const realResolved = canonicalProspectivePath(resolved, field);
|
|
41
|
+
if (!isInside(realBoundary, realResolved)) {
|
|
42
|
+
throw new PinError('pin-invalid', `${field} "${relPath}" resolves outside the path boundary`);
|
|
43
|
+
}
|
|
44
|
+
return resolved;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Canonicalizes an existing path or its nearest existing ancestor. Resolving
|
|
48
|
+
* the ancestor is load-bearing for missing pinned files: `inside-link/missing`
|
|
49
|
+
* must still be rejected as a symlink escape rather than misreported stale.
|
|
50
|
+
*/
|
|
51
|
+
function canonicalProspectivePath(path, field) {
|
|
52
|
+
const suffix = [];
|
|
53
|
+
let cursor = path;
|
|
54
|
+
while (true) {
|
|
55
|
+
try {
|
|
56
|
+
return resolve(realpathSync.native(cursor), ...suffix.reverse());
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
if (!isAbsentPath(error)) {
|
|
60
|
+
throw new PinError('pin-invalid', `${field} cannot be resolved safely: ${errorCode(error)}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const parent = dirname(cursor);
|
|
64
|
+
if (parent === cursor) {
|
|
65
|
+
throw new PinError('pin-invalid', `${field} cannot be resolved safely: no existing ancestor`);
|
|
66
|
+
}
|
|
67
|
+
suffix.push(basename(cursor));
|
|
68
|
+
cursor = parent;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function isAbsentPath(error) {
|
|
72
|
+
const code = errorCode(error);
|
|
73
|
+
return code === 'ENOENT' || code === 'ENOTDIR';
|
|
74
|
+
}
|
|
75
|
+
function errorCode(error) {
|
|
76
|
+
return typeof error === 'object' &&
|
|
77
|
+
error !== null &&
|
|
78
|
+
'code' in error &&
|
|
79
|
+
typeof error.code === 'string'
|
|
80
|
+
? error.code
|
|
81
|
+
: 'unknown error';
|
|
82
|
+
}
|
|
83
|
+
/** Rejects an absolute (POSIX or Windows) path, naming `field` (PIN-5). */
|
|
84
|
+
function requireRelative(path, field) {
|
|
85
|
+
if (path === '' || path.includes('\\') || path.includes('\0')) {
|
|
86
|
+
throw new PinError('pin-invalid', `${field} must be a non-empty portable POSIX path`);
|
|
87
|
+
}
|
|
88
|
+
if (posixIsAbsolute(path) || isWindowsAbsolute(path)) {
|
|
89
|
+
throw new PinError('pin-invalid', `${field} must be a relative path, got "${path}"`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function splitPosix(path) {
|
|
93
|
+
return path.split('/').filter((segment) => segment.length > 0);
|
|
94
|
+
}
|
|
95
|
+
function isWindowsAbsolute(path) {
|
|
96
|
+
return /^[a-zA-Z]:/.test(path);
|
|
97
|
+
}
|
|
98
|
+
function isInside(boundaryRoot, resolved) {
|
|
99
|
+
if (resolved === boundaryRoot) {
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
const rel = relative(boundaryRoot, resolved);
|
|
103
|
+
return (rel !== '' &&
|
|
104
|
+
!rel.startsWith(`..${sep}`) &&
|
|
105
|
+
rel !== '..' &&
|
|
106
|
+
!isAbsolute(rel));
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=pin-paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pin-paths.js","sourceRoot":"","sources":["../src/pin-paths.ts"],"names":[],"mappings":"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"}
|
package/dist/pins.d.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/** Committed pin-index filename in a pipeline directory (DR-007). */
|
|
2
|
+
export declare const PINS_FILE = "slc.pins.json";
|
|
3
|
+
/** The only supported pin-file schema identifier (DR-007). */
|
|
4
|
+
export declare const PIN_SCHEMA = "sublang.slc.pins.v2";
|
|
5
|
+
/** The only supported pin hash algorithm (DR-007). */
|
|
6
|
+
export declare const PIN_HASH_ALGORITHM = "sha256";
|
|
7
|
+
/** A pinned local file recorded by path and exact-byte hash (DR-007). */
|
|
8
|
+
export interface PinFileRef {
|
|
9
|
+
path: string;
|
|
10
|
+
hash: string;
|
|
11
|
+
}
|
|
12
|
+
/** A semantic-input closure member: a local file plus a descriptive role (DR-007). */
|
|
13
|
+
export interface PinSemanticInput {
|
|
14
|
+
path: string;
|
|
15
|
+
hash: string;
|
|
16
|
+
role?: string;
|
|
17
|
+
}
|
|
18
|
+
/** The immutable identity of the `slc.link` target consumed to produce the artifact (DR-007). */
|
|
19
|
+
export interface PinLinkTarget {
|
|
20
|
+
kind: string;
|
|
21
|
+
locator: string;
|
|
22
|
+
identity: string;
|
|
23
|
+
provenance?: string;
|
|
24
|
+
}
|
|
25
|
+
/** A local executable dependency, optionally bound to package resolution. */
|
|
26
|
+
export interface PinRuntimeDependency extends PinLinkTarget {
|
|
27
|
+
/** Bare import specifier re-resolved from the compiled entry module. */
|
|
28
|
+
specifier?: string;
|
|
29
|
+
}
|
|
30
|
+
/** An immutable content-addressed external input; its field shape is reserved by DR-007. */
|
|
31
|
+
export type PinExternalInput = Record<string, unknown>;
|
|
32
|
+
/** Provenance of the producing meta-pipeline run; never a currency input (DR-007). */
|
|
33
|
+
export interface PinProducer {
|
|
34
|
+
pipeline: string;
|
|
35
|
+
slcVersion?: string;
|
|
36
|
+
metaPipelineRevision?: string;
|
|
37
|
+
}
|
|
38
|
+
/** The pin record for one phase (DR-007). */
|
|
39
|
+
export interface PinRecord {
|
|
40
|
+
artifact: PinFileRef;
|
|
41
|
+
/** Deterministic tree identity for the reviewed files that make up the runnable artifact. */
|
|
42
|
+
artifactBundle: PinFileRef;
|
|
43
|
+
definition: PinFileRef;
|
|
44
|
+
semanticInputs: PinSemanticInput[];
|
|
45
|
+
externalInputs: PinExternalInput[];
|
|
46
|
+
/** Local executable packages/files loaded by the compiled artifact. */
|
|
47
|
+
runtimeDependencies: PinRuntimeDependency[];
|
|
48
|
+
linkTarget: PinLinkTarget;
|
|
49
|
+
producer?: PinProducer;
|
|
50
|
+
}
|
|
51
|
+
/** The recorded path boundary; defaults to the pipeline directory (`.`) (DR-007). */
|
|
52
|
+
export interface PinPathBoundary {
|
|
53
|
+
path: string;
|
|
54
|
+
}
|
|
55
|
+
/** A parsed `slc.pins.json` (DR-007). */
|
|
56
|
+
export interface PinFile {
|
|
57
|
+
schema: string;
|
|
58
|
+
hashAlgorithm: string;
|
|
59
|
+
pathBoundary: PinPathBoundary;
|
|
60
|
+
pins: Record<string, PinRecord>;
|
|
61
|
+
}
|
|
62
|
+
/** A loaded pin file: the resolved path and parsed model, or both undefined when absent. */
|
|
63
|
+
export interface LoadedPins {
|
|
64
|
+
path?: string;
|
|
65
|
+
file?: PinFile;
|
|
66
|
+
}
|
|
67
|
+
/** Machine-readable reason a pin file was rejected (PIN-5). */
|
|
68
|
+
export type PinErrorCode = 'pin-parse' | 'pin-invalid';
|
|
69
|
+
/** Raised when `slc.pins.json` is not valid JSON or violates the pin schema (PIN-5). */
|
|
70
|
+
export declare class PinError extends Error {
|
|
71
|
+
readonly code: PinErrorCode;
|
|
72
|
+
constructor(code: PinErrorCode, message: string);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Loads and validates `<pipelineDir>/slc.pins.json` (PIN-1, PIN-5).
|
|
76
|
+
*
|
|
77
|
+
* @returns `{ path, file }` when present and valid, or `{}` (no pins) when absent.
|
|
78
|
+
* @throws {PinError} when the file is not valid JSON (`pin-parse`) or violates the
|
|
79
|
+
* schema (`pin-invalid`), with a diagnostic naming the offending field.
|
|
80
|
+
*/
|
|
81
|
+
export declare function loadPinFile(pipelineDir: string): Promise<LoadedPins>;
|
|
82
|
+
/** Parses and structurally validates the text of a pin file into a {@link PinFile} (PIN-5). */
|
|
83
|
+
export declare function parsePinFile(source: string, path?: string): PinFile;
|
|
84
|
+
//# sourceMappingURL=pins.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pins.d.ts","sourceRoot":"","sources":["../src/pins.ts"],"names":[],"mappings":"AAuBA,qEAAqE;AACrE,eAAO,MAAM,SAAS,kBAAkB,CAAC;AACzC,8DAA8D;AAC9D,eAAO,MAAM,UAAU,wBAAwB,CAAC;AAChD,sDAAsD;AACtD,eAAO,MAAM,kBAAkB,WAAW,CAAC;AAK3C,yEAAyE;AACzE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,sFAAsF;AACtF,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,iGAAiG;AACjG,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,6EAA6E;AAC7E,MAAM,WAAW,oBAAqB,SAAQ,aAAa;IACzD,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,4FAA4F;AAC5F,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEvD,sFAAsF;AACtF,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,6CAA6C;AAC7C,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,UAAU,CAAC;IACrB,6FAA6F;IAC7F,cAAc,EAAE,UAAU,CAAC;IAC3B,UAAU,EAAE,UAAU,CAAC;IACvB,cAAc,EAAE,gBAAgB,EAAE,CAAC;IACnC,cAAc,EAAE,gBAAgB,EAAE,CAAC;IACnC,uEAAuE;IACvE,mBAAmB,EAAE,oBAAoB,EAAE,CAAC;IAC5C,UAAU,EAAE,aAAa,CAAC;IAC1B,QAAQ,CAAC,EAAE,WAAW,CAAC;CACxB;AAED,qFAAqF;AACrF,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,yCAAyC;AACzC,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,eAAe,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACjC;AAED,4FAA4F;AAC5F,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,+DAA+D;AAC/D,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,aAAa,CAAC;AAEvD,wFAAwF;AACxF,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;gBAEhB,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM;CAKhD;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAoB1E;AAWD,+FAA+F;AAC/F,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,MAAkB,GACvB,OAAO,CAWT"}
|
package/dist/pins.js
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
|
|
3
|
+
/**
|
|
4
|
+
* Pin-file model and strict parser for the pin-currency validator (PIN-1, PIN-5;
|
|
5
|
+
* DR-007).
|
|
6
|
+
*
|
|
7
|
+
* Loads a pipeline's committed `slc.pins.json` and structurally validates it into
|
|
8
|
+
* a typed {@link PinFile}: the supported schema identifier and hash algorithm,
|
|
9
|
+
* the optional path boundary, and each phase's pin record (with the reserved
|
|
10
|
+
* `link` key naming the link phase). An absent file yields an empty result — no
|
|
11
|
+
* pins — and a non-JSON file or a record violating the schema is rejected with a
|
|
12
|
+
* {@link PinError} naming the offending field. This module performs structural
|
|
13
|
+
* validation only: it does not hash inputs, resolve the path boundary, derive the
|
|
14
|
+
* semantic closure, or judge currency — those are later validator stages. See
|
|
15
|
+
* specs/dev/pinning.md.
|
|
16
|
+
*/
|
|
17
|
+
import { lstat, readFile } from 'node:fs/promises';
|
|
18
|
+
import { join } from 'node:path';
|
|
19
|
+
import { isBarePackageSpecifier } from './runtime-package.js';
|
|
20
|
+
/** Committed pin-index filename in a pipeline directory (DR-007). */
|
|
21
|
+
export const PINS_FILE = 'slc.pins.json';
|
|
22
|
+
/** The only supported pin-file schema identifier (DR-007). */
|
|
23
|
+
export const PIN_SCHEMA = 'sublang.slc.pins.v2';
|
|
24
|
+
/** The only supported pin hash algorithm (DR-007). */
|
|
25
|
+
export const PIN_HASH_ALGORITHM = 'sha256';
|
|
26
|
+
const LINK_TARGET_KINDS = new Set(['file', 'directory', 'package']);
|
|
27
|
+
const PIN_PHASE_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*2[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
28
|
+
/** Raised when `slc.pins.json` is not valid JSON or violates the pin schema (PIN-5). */
|
|
29
|
+
export class PinError extends Error {
|
|
30
|
+
code;
|
|
31
|
+
constructor(code, message) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.name = 'PinError';
|
|
34
|
+
this.code = code;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Loads and validates `<pipelineDir>/slc.pins.json` (PIN-1, PIN-5).
|
|
39
|
+
*
|
|
40
|
+
* @returns `{ path, file }` when present and valid, or `{}` (no pins) when absent.
|
|
41
|
+
* @throws {PinError} when the file is not valid JSON (`pin-parse`) or violates the
|
|
42
|
+
* schema (`pin-invalid`), with a diagnostic naming the offending field.
|
|
43
|
+
*/
|
|
44
|
+
export async function loadPinFile(pipelineDir) {
|
|
45
|
+
const path = join(pipelineDir, PINS_FILE);
|
|
46
|
+
let info;
|
|
47
|
+
try {
|
|
48
|
+
info = await lstat(path);
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
if (errorCode(error) === 'ENOENT')
|
|
52
|
+
return {};
|
|
53
|
+
throw new PinError('pin-invalid', `${path} cannot be inspected: ${errorCode(error)}`);
|
|
54
|
+
}
|
|
55
|
+
if (!info.isFile() || info.isSymbolicLink()) {
|
|
56
|
+
throw new PinError('pin-invalid', `${path} must be a regular non-symbolic-link file`);
|
|
57
|
+
}
|
|
58
|
+
const source = await readFile(path, 'utf8');
|
|
59
|
+
return { path, file: parsePinFile(source, path) };
|
|
60
|
+
}
|
|
61
|
+
function errorCode(error) {
|
|
62
|
+
return typeof error === 'object' &&
|
|
63
|
+
error !== null &&
|
|
64
|
+
'code' in error &&
|
|
65
|
+
typeof error.code === 'string'
|
|
66
|
+
? error.code
|
|
67
|
+
: 'unknown error';
|
|
68
|
+
}
|
|
69
|
+
/** Parses and structurally validates the text of a pin file into a {@link PinFile} (PIN-5). */
|
|
70
|
+
export function parsePinFile(source, path = PINS_FILE) {
|
|
71
|
+
let raw;
|
|
72
|
+
try {
|
|
73
|
+
raw = JSON.parse(source);
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
throw new PinError('pin-parse', `${path} is not valid JSON: ${messageOf(error)}`);
|
|
77
|
+
}
|
|
78
|
+
return normalizePinFile(raw, path);
|
|
79
|
+
}
|
|
80
|
+
function normalizePinFile(value, path) {
|
|
81
|
+
const input = requireObject(value, path);
|
|
82
|
+
rejectUnknownKeys(input, new Set(['schema', 'hashAlgorithm', 'pathBoundary', 'pins']), path);
|
|
83
|
+
const schema = requireString(input.schema, `${path}.schema`);
|
|
84
|
+
if (schema !== PIN_SCHEMA) {
|
|
85
|
+
throw invalid(`${path}.schema`, `must be "${PIN_SCHEMA}"`);
|
|
86
|
+
}
|
|
87
|
+
const hashAlgorithm = requireString(input.hashAlgorithm, `${path}.hashAlgorithm`);
|
|
88
|
+
if (hashAlgorithm !== PIN_HASH_ALGORITHM) {
|
|
89
|
+
throw invalid(`${path}.hashAlgorithm`, `must be "${PIN_HASH_ALGORITHM}"`);
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
schema,
|
|
93
|
+
hashAlgorithm,
|
|
94
|
+
pathBoundary: normalizePathBoundary(input.pathBoundary, `${path}.pathBoundary`),
|
|
95
|
+
pins: normalizePins(input.pins, `${path}.pins`),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function normalizePathBoundary(value, path) {
|
|
99
|
+
if (value === undefined) {
|
|
100
|
+
return { path: '.' };
|
|
101
|
+
}
|
|
102
|
+
const input = requireObject(value, path);
|
|
103
|
+
rejectUnknownKeys(input, new Set(['path']), path);
|
|
104
|
+
return { path: requirePortablePath(input.path, `${path}.path`) };
|
|
105
|
+
}
|
|
106
|
+
function normalizePins(value, path) {
|
|
107
|
+
const input = requireObject(value, path);
|
|
108
|
+
const pins = {};
|
|
109
|
+
for (const [name, record] of Object.entries(input)) {
|
|
110
|
+
if (name !== 'link' && !PIN_PHASE_NAME.test(name)) {
|
|
111
|
+
throw invalid(`${path}.${name}`, 'phase key must be "link" or a kebab-case <source>2<target> name');
|
|
112
|
+
}
|
|
113
|
+
pins[name] = normalizePinRecord(record, `${path}.${name}`);
|
|
114
|
+
}
|
|
115
|
+
return pins;
|
|
116
|
+
}
|
|
117
|
+
function normalizePinRecord(value, path) {
|
|
118
|
+
const input = requireObject(value, path);
|
|
119
|
+
rejectUnknownKeys(input, new Set([
|
|
120
|
+
'artifact',
|
|
121
|
+
'artifactBundle',
|
|
122
|
+
'definition',
|
|
123
|
+
'semanticInputs',
|
|
124
|
+
'externalInputs',
|
|
125
|
+
'runtimeDependencies',
|
|
126
|
+
'linkTarget',
|
|
127
|
+
'producer',
|
|
128
|
+
]), path);
|
|
129
|
+
const record = {
|
|
130
|
+
artifact: normalizeFileRef(input.artifact, `${path}.artifact`),
|
|
131
|
+
artifactBundle: normalizeFileRef(input.artifactBundle, `${path}.artifactBundle`),
|
|
132
|
+
definition: normalizeFileRef(input.definition, `${path}.definition`),
|
|
133
|
+
linkTarget: normalizeLinkTarget(input.linkTarget, `${path}.linkTarget`),
|
|
134
|
+
semanticInputs: input.semanticInputs === undefined
|
|
135
|
+
? []
|
|
136
|
+
: normalizeSemanticInputs(input.semanticInputs, `${path}.semanticInputs`),
|
|
137
|
+
externalInputs: input.externalInputs === undefined
|
|
138
|
+
? []
|
|
139
|
+
: normalizeExternalInputs(input.externalInputs, `${path}.externalInputs`),
|
|
140
|
+
runtimeDependencies: normalizeRuntimeDependencies(input.runtimeDependencies, `${path}.runtimeDependencies`),
|
|
141
|
+
};
|
|
142
|
+
if (input.producer !== undefined) {
|
|
143
|
+
record.producer = normalizeProducer(input.producer, `${path}.producer`);
|
|
144
|
+
}
|
|
145
|
+
return record;
|
|
146
|
+
}
|
|
147
|
+
function normalizeRuntimeDependencies(value, path) {
|
|
148
|
+
return requireArray(value, path).map((entry, index) => normalizeRuntimeDependency(entry, `${path}[${index}]`));
|
|
149
|
+
}
|
|
150
|
+
function normalizeRuntimeDependency(value, path) {
|
|
151
|
+
const input = requireObject(value, path);
|
|
152
|
+
rejectUnknownKeys(input, new Set(['kind', 'locator', 'identity', 'provenance', 'specifier']), path);
|
|
153
|
+
const { specifier, ...linkTargetFields } = input;
|
|
154
|
+
const dependency = normalizeLinkTarget(linkTargetFields, path);
|
|
155
|
+
if (dependency.kind === 'package') {
|
|
156
|
+
dependency.specifier = requireString(specifier, `${path}.specifier`);
|
|
157
|
+
if (!isBarePackageSpecifier(dependency.specifier)) {
|
|
158
|
+
throw invalid(`${path}.specifier`, 'must be a bare package specifier');
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
else if (specifier !== undefined) {
|
|
162
|
+
throw invalid(`${path}.specifier`, 'is only valid for package dependencies');
|
|
163
|
+
}
|
|
164
|
+
return dependency;
|
|
165
|
+
}
|
|
166
|
+
function normalizeFileRef(value, path) {
|
|
167
|
+
const input = requireObject(value, path);
|
|
168
|
+
rejectUnknownKeys(input, new Set(['path', 'hash']), path);
|
|
169
|
+
return {
|
|
170
|
+
path: requirePortablePath(input.path, `${path}.path`),
|
|
171
|
+
hash: requireString(input.hash, `${path}.hash`),
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
function normalizeSemanticInputs(value, path) {
|
|
175
|
+
return requireArray(value, path).map((entry, index) => {
|
|
176
|
+
const item = `${path}[${index}]`;
|
|
177
|
+
const input = requireObject(entry, item);
|
|
178
|
+
rejectUnknownKeys(input, new Set(['path', 'hash', 'role']), item);
|
|
179
|
+
const semanticInput = {
|
|
180
|
+
path: requirePortablePath(input.path, `${item}.path`),
|
|
181
|
+
hash: requireString(input.hash, `${item}.hash`),
|
|
182
|
+
};
|
|
183
|
+
if (input.role !== undefined) {
|
|
184
|
+
semanticInput.role = requireString(input.role, `${item}.role`);
|
|
185
|
+
}
|
|
186
|
+
return semanticInput;
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
function normalizeLinkTarget(value, path) {
|
|
190
|
+
const input = requireObject(value, path);
|
|
191
|
+
rejectUnknownKeys(input, new Set(['kind', 'locator', 'identity', 'provenance']), path);
|
|
192
|
+
const kind = requireString(input.kind, `${path}.kind`);
|
|
193
|
+
if (!LINK_TARGET_KINDS.has(kind)) {
|
|
194
|
+
throw invalid(`${path}.kind`, 'must be one of: file, directory, package');
|
|
195
|
+
}
|
|
196
|
+
const linkTarget = {
|
|
197
|
+
kind,
|
|
198
|
+
locator: requirePortablePath(input.locator, `${path}.locator`),
|
|
199
|
+
identity: requireString(input.identity, `${path}.identity`),
|
|
200
|
+
};
|
|
201
|
+
if (input.provenance !== undefined) {
|
|
202
|
+
linkTarget.provenance = requireString(input.provenance, `${path}.provenance`);
|
|
203
|
+
}
|
|
204
|
+
return linkTarget;
|
|
205
|
+
}
|
|
206
|
+
function normalizeExternalInputs(value, path) {
|
|
207
|
+
return requireArray(value, path).map((entry, index) => requireObject(entry, `${path}[${index}]`));
|
|
208
|
+
}
|
|
209
|
+
function normalizeProducer(value, path) {
|
|
210
|
+
const input = requireObject(value, path);
|
|
211
|
+
rejectUnknownKeys(input, new Set(['pipeline', 'slcVersion', 'metaPipelineRevision']), path);
|
|
212
|
+
const producer = {
|
|
213
|
+
pipeline: requireString(input.pipeline, `${path}.pipeline`),
|
|
214
|
+
};
|
|
215
|
+
if (input.slcVersion !== undefined) {
|
|
216
|
+
producer.slcVersion = requireString(input.slcVersion, `${path}.slcVersion`);
|
|
217
|
+
}
|
|
218
|
+
if (input.metaPipelineRevision !== undefined) {
|
|
219
|
+
producer.metaPipelineRevision = requireString(input.metaPipelineRevision, `${path}.metaPipelineRevision`);
|
|
220
|
+
}
|
|
221
|
+
return producer;
|
|
222
|
+
}
|
|
223
|
+
function requireObject(value, path) {
|
|
224
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
225
|
+
throw invalid(path, 'must be an object');
|
|
226
|
+
}
|
|
227
|
+
return value;
|
|
228
|
+
}
|
|
229
|
+
function requireArray(value, path) {
|
|
230
|
+
if (!Array.isArray(value)) {
|
|
231
|
+
throw invalid(path, 'must be an array');
|
|
232
|
+
}
|
|
233
|
+
return value;
|
|
234
|
+
}
|
|
235
|
+
function requireString(value, path) {
|
|
236
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
237
|
+
throw invalid(path, 'must be a non-empty string');
|
|
238
|
+
}
|
|
239
|
+
return value;
|
|
240
|
+
}
|
|
241
|
+
function requirePortablePath(value, path) {
|
|
242
|
+
const result = requireString(value, path);
|
|
243
|
+
if (result === '' ||
|
|
244
|
+
result.includes('\\') ||
|
|
245
|
+
result.includes('\0') ||
|
|
246
|
+
result.startsWith('/') ||
|
|
247
|
+
/^[a-zA-Z]:/.test(result)) {
|
|
248
|
+
throw invalid(path, 'must be a non-empty portable relative POSIX path');
|
|
249
|
+
}
|
|
250
|
+
return result;
|
|
251
|
+
}
|
|
252
|
+
function rejectUnknownKeys(value, allowed, path) {
|
|
253
|
+
for (const key of Object.keys(value)) {
|
|
254
|
+
if (!allowed.has(key)) {
|
|
255
|
+
throw invalid(`${path}.${key}`, 'is an unknown field');
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function invalid(field, detail) {
|
|
260
|
+
return new PinError('pin-invalid', `${field} ${detail}`);
|
|
261
|
+
}
|
|
262
|
+
function messageOf(error) {
|
|
263
|
+
return error instanceof Error ? error.message : String(error);
|
|
264
|
+
}
|
|
265
|
+
//# sourceMappingURL=pins.js.map
|
package/dist/pins.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pins.js","sourceRoot":"","sources":["../src/pins.ts"],"names":[],"mappings":"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"}
|