openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
129 lines (128 loc) • 6.08 kB
JavaScript
import { i as normalizeOptionalString, l as isRecord } from "./string-coerce-6O-WySZM.js";
import "./src-BdCVpmTW.js";
import "@openclaw/fs-safe/path";
import path from "node:path";
import { AsyncLocalStorage } from "node:async_hooks";
import fs from "node:fs";
import { resolvePathViaExistingAncestorSync } from "@openclaw/fs-safe/advanced";
//#region packages/normalization-core/src/expect.ts
/** Returns the value or throws with the named context; use for genuine invariants only. */
function expectDefined(value, context) {
if (value === null || value === void 0) throw new Error("expected " + context + " to be defined");
return value;
}
//#endregion
//#region src/secrets/ref-contract.ts
/** Shared SecretRef grammar and validation helpers for config, schema, SDK, and gateway parity. */
/** Provider alias used when a SecretRef omits a source-specific provider. */
const DEFAULT_SECRET_PROVIDER_ALIAS = "default";
/** Strict env-var id shape accepted for env-backed SecretRefs. */
const ENV_SECRET_REF_ID_RE = /^[A-Z][A-Z0-9_]{0,127}$/;
/** Narrow a value to the canonical SecretRef object shape. */
function isSecretRef(value) {
if (!isRecord(value)) return false;
if (Object.keys(value).length !== 3) return false;
return (value.source === "env" || value.source === "file" || value.source === "exec" || value.source === "store") && typeof value.provider === "string" && value.provider.trim().length > 0 && typeof value.id === "string" && value.id.trim().length > 0;
}
/**
* Runtime secret-reference grammar shared by config parsing, plugin SDK schemas,
* gateway parity checks, and resolver planning.
*/
const FILE_SECRET_REF_SEGMENT_PATTERN = /^(?:[^~]|~0|~1)*$/;
/** Shared alias grammar for env/file/exec/store secret provider names. */
const SECRET_PROVIDER_ALIAS_PATTERN = /^[a-z][a-z0-9_-]{0,63}$/;
const EXEC_SECRET_REF_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:/#-]{0,255}$/;
/** Validates file secret ref ids against the shared JSON-pointer-style contract. */
function isValidFileSecretRefId(value) {
if (value === "value") return true;
if (!value.startsWith("/")) return false;
return value.slice(1).split("/").every((segment) => FILE_SECRET_REF_SEGMENT_PATTERN.test(segment));
}
/** Validates exec secret ref ids and reports why invalid ids failed. */
function validateExecSecretRefId(value) {
if (!EXEC_SECRET_REF_ID_PATTERN.test(value)) return {
ok: false,
reason: "pattern"
};
for (const segment of value.split("/")) if (segment === "." || segment === "..") return {
ok: false,
reason: "traversal-segment"
};
return { ok: true };
}
/** Boolean convenience wrapper for callers that only need accept/reject behavior. */
function isValidExecSecretRefId(value) {
return validateExecSecretRefId(value).ok;
}
/** Formats the user-facing validation message for rejected exec secret ref ids. */
function formatExecSecretRefIdValidationMessage() {
return [
"Exec secret reference id must match /^[A-Za-z0-9][A-Za-z0-9._:/#-]{0,255}$/",
"and must not include \".\" or \"..\" path segments",
"(example: \"vault/openai/api-key\" or \"aws/secret#json_key\")."
].join(" ");
}
//#endregion
//#region src/infra/boundary-path.ts
const runInBoundaryPathContext = AsyncLocalStorage.snapshot();
function resolvePathViaExistingAncestorSync$1(targetPath) {
return runInBoundaryPathContext(resolvePathViaExistingAncestorSync, targetPath);
}
function resolveIdentityPathViaExistingAncestorSync(targetPath) {
const fallback = path.resolve(targetPath);
const missingSegments = [];
let cursor = fallback;
while (true) try {
return path.join(fs.realpathSync.native(cursor), ...missingSegments.toReversed());
} catch {
const parent = path.dirname(cursor);
if (parent === cursor) return fallback;
missingSegments.push(path.basename(cursor));
cursor = parent;
}
}
//#endregion
//#region src/config/types.secrets.ts
const ENV_SECRET_TEMPLATE_RE = /^\$\{([A-Z][A-Z0-9_]{0,127})\}$/;
const ENV_SECRET_SHORTHAND_RE = /^\$([A-Z][A-Z0-9_]{0,127})$/;
function isLegacySecretRefWithoutProvider(value) {
if (!isRecord(value)) return false;
return (value.source === "env" || value.source === "file" || value.source === "exec" || value.source === "store") && typeof value.id === "string" && value.id.trim().length > 0 && value.provider === void 0;
}
/** Parse `$NAME` and `${NAME}` env-secret shorthand strings into env SecretRefs. */
function parseEnvTemplateSecretRef(value, provider = DEFAULT_SECRET_PROVIDER_ALIAS) {
if (typeof value !== "string") return null;
const trimmed = value.trim();
const match = ENV_SECRET_TEMPLATE_RE.exec(trimmed) ?? ENV_SECRET_SHORTHAND_RE.exec(trimmed);
if (!match) return null;
return {
source: "env",
provider: provider.trim() || "default",
id: expectDefined(match[1], "types.secrets regex capture 1")
};
}
/** Coerce canonical and env-shorthand secret inputs into a SecretRef.
* Retired string markers are parsed only by doctor migration above. */
function coerceSecretRef(value, defaults) {
if (isSecretRef(value)) return value;
if (isLegacySecretRefWithoutProvider(value)) {
const provider = defaults?.[value.source] ?? "default";
return {
source: value.source,
provider,
id: value.id
};
}
return parseEnvTemplateSecretRef(value, defaults?.env);
}
/** Return whether a value contains either a literal secret string or resolvable SecretRef shape. */
function hasConfiguredSecretInput(value, defaults) {
if (normalizeSecretInputString(value)) return true;
return coerceSecretRef(value, defaults) !== null;
}
/** Trim a literal secret input string while leaving non-string inputs unresolved. */
function normalizeSecretInputString(value) {
return normalizeOptionalString(value);
}
//#endregion
export { DEFAULT_SECRET_PROVIDER_ALIAS as a, formatExecSecretRefIdValidationMessage as c, expectDefined as d, resolvePathViaExistingAncestorSync$1 as i, isValidExecSecretRefId as l, parseEnvTemplateSecretRef as n, ENV_SECRET_REF_ID_RE as o, resolveIdentityPathViaExistingAncestorSync as r, SECRET_PROVIDER_ALIAS_PATTERN as s, hasConfiguredSecretInput as t, isValidFileSecretRefId as u };