diff --git a/src/capability-language/source-closure.ts b/src/capability-language/source-closure.ts index 7fa7b52..6f71763 100644 --- a/src/capability-language/source-closure.ts +++ b/src/capability-language/source-closure.ts @@ -7,7 +7,8 @@ import { fileURLToPath } from "node:url"; import { loadQuixosLock, retentionTagForCommit } from "../resource-lock/index.js"; const exec = promisify(callback); -export type WorkspaceSourcePin = { repository: string; commit: string }; +import { workspaceSourcePin, type WorkspaceSourcePin } from "./source-pin.js"; +export { workspaceSourcePin, type WorkspaceSourcePin } from "./source-pin.js"; export type SourceClosureEntry = WorkspaceSourcePin & { kind: "workspace" | "interface" | "package" | "build"; directory: string; @@ -18,23 +19,6 @@ export type WorkspaceSourceClosure = { resources: SourceClosureEntry[]; }; -export function workspaceSourcePin(value: unknown): WorkspaceSourcePin { - if (!value || typeof value !== "object" || Array.isArray(value)) throw Error("Invalid Workspace source pin"); - const pin = value as WorkspaceSourcePin; - const url = new URL(pin.repository); - if ( - url.protocol !== "https:" || - url.username || - url.password || - url.search || - url.hash || - typeof pin.commit !== "string" || - !/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(pin.commit) - ) - throw Error("Workspace source pins require credential-free HTTPS and an exact commit"); - return { repository: pin.repository, commit: pin.commit }; -} - /** Trusted transport substitutions preserve source identity. A mirror or bundle * is explicitly selected, never tried automatically after an origin failure. * Git authentication stays in the caller's Git configuration, outside metadata. diff --git a/src/capability-language/source-pin.ts b/src/capability-language/source-pin.ts new file mode 100644 index 0000000..501347c --- /dev/null +++ b/src/capability-language/source-pin.ts @@ -0,0 +1,18 @@ +export type WorkspaceSourcePin = { repository: string; commit: string }; + +export function workspaceSourcePin(value: unknown): WorkspaceSourcePin { + if (!value || typeof value !== "object" || Array.isArray(value)) throw Error("Invalid Workspace source pin"); + const pin = value as WorkspaceSourcePin; + const url = new URL(pin.repository); + if ( + url.protocol !== "https:" || + url.username || + url.password || + url.search || + url.hash || + typeof pin.commit !== "string" || + !/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(pin.commit) + ) + throw Error("Workspace source pins require credential-free HTTPS and an exact commit"); + return { repository: pin.repository, commit: pin.commit }; +}