langsmith
Version:
Client library to connect to the LangSmith Observability and Evaluation Platform.
254 lines (253 loc) • 9.29 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.s3Mount = s3Mount;
exports.gitMount = gitMount;
exports.gcsMount = gcsMount;
exports.mountConfig = mountConfig;
exports.validateMountConfigProxyConfig = validateMountConfigProxyConfig;
function requireNonEmptyString(value, field) {
if (typeof value !== "string" || value.trim() === "") {
throw new Error(`${field} must be a non-empty string`);
}
return value.trim();
}
function copyMountSecret(secret, field) {
if (secret === null || typeof secret !== "object" || Array.isArray(secret)) {
throw new Error(`${field} must be a sandbox secret`);
}
const candidate = secret;
if (candidate.type !== "workspace_secret" && candidate.type !== "opaque") {
throw new Error(`${field} must use workspace_secret or opaque`);
}
if (typeof candidate.value !== "string" || candidate.value.trim() === "") {
throw new Error(`${field}.value must be a non-empty string`);
}
return {
type: candidate.type,
value: candidate.value,
};
}
function requireGitRemoteUrl(remoteUrl) {
if (typeof remoteUrl !== "string" || remoteUrl === "") {
throw new Error("remoteUrl must be a non-empty string");
}
if (remoteUrl.trim() !== remoteUrl ||
/\s/u.test(remoteUrl) ||
remoteUrl.includes(String.fromCharCode(0))) {
throw new Error("remoteUrl must not contain whitespace or NUL bytes");
}
let parsed;
try {
parsed = new URL(remoteUrl);
}
catch {
throw new Error("remoteUrl must be an absolute HTTPS URL");
}
if (parsed.protocol !== "https:" || parsed.host === "") {
throw new Error("remoteUrl must be an absolute HTTPS URL");
}
if (parsed.username !== "" || parsed.password !== "") {
throw new Error("remoteUrl must not include embedded credentials");
}
if (parsed.pathname === "" || parsed.pathname === "/") {
throw new Error("remoteUrl must include a repository path");
}
if (parsed.search !== "" || parsed.hash !== "") {
throw new Error("remoteUrl must not include query or fragment");
}
return remoteUrl;
}
function copyGitRef(ref) {
if (ref === null || typeof ref !== "object" || Array.isArray(ref)) {
throw new Error("ref must be an object");
}
if (ref.type !== "branch" && ref.type !== "tag") {
throw new Error("ref.type must be branch or tag");
}
return {
type: ref.type,
name: requireNonEmptyString(ref.name, "ref.name"),
};
}
function s3Mount({ id, mountPath, bucket, region = "us-east-1", prefix, endpointUrl = "https://s3.amazonaws.com", pathStyle = false, readOnly, cache, }) {
const mount = {
id: requireNonEmptyString(id, "id"),
type: "s3",
mount_path: requireNonEmptyString(mountPath, "mountPath"),
s3: {
endpoint_url: requireNonEmptyString(endpointUrl, "endpointUrl"),
region: requireNonEmptyString(region, "region"),
bucket: requireNonEmptyString(bucket, "bucket"),
path_style: pathStyle,
},
};
if (prefix !== undefined) {
mount.s3.prefix = requireNonEmptyString(prefix, "prefix");
}
if (readOnly !== undefined) {
mount.read_only = readOnly;
}
if (cache !== undefined) {
mount.cache = { ...cache };
}
return mount;
}
function gitMount({ id, mountPath, remoteUrl, ref, refreshIntervalSeconds, }) {
const mount = {
id: requireNonEmptyString(id, "id"),
type: "git",
mount_path: requireNonEmptyString(mountPath, "mountPath"),
git: {
remote_url: requireGitRemoteUrl(remoteUrl),
},
};
if (ref !== undefined) {
mount.git.ref = copyGitRef(ref);
}
if (refreshIntervalSeconds !== undefined) {
if (refreshIntervalSeconds < 1) {
throw new Error("refreshIntervalSeconds must be at least 1");
}
mount.git.refresh_interval_seconds = refreshIntervalSeconds;
}
return mount;
}
function gcsMount({ id, mountPath, bucket, prefix, readOnly, cache, }) {
const mount = {
id: requireNonEmptyString(id, "id"),
type: "gcs",
mount_path: requireNonEmptyString(mountPath, "mountPath"),
gcs: {
bucket: requireNonEmptyString(bucket, "bucket"),
},
};
if (prefix !== undefined) {
mount.gcs.prefix = requireNonEmptyString(prefix, "prefix");
}
if (readOnly !== undefined) {
mount.read_only = readOnly;
}
if (cache !== undefined) {
mount.cache = { ...cache };
}
return mount;
}
function normalizeMounts(mounts) {
if (!Array.isArray(mounts) || mounts.length === 0) {
throw new Error("mounts must be a non-empty array of mount objects");
}
return mounts.map((mount) => {
if (mount === null || typeof mount !== "object" || Array.isArray(mount)) {
throw new Error("mounts must be a non-empty array of mount objects");
}
if (mount.type !== "s3" && mount.type !== "gcs" && mount.type !== "git") {
throw new Error("mountConfig only supports s3, gcs, and git mounts");
}
rejectProviderCredentialsInMount(mount);
return mount;
});
}
const FORBIDDEN_MOUNT_CREDENTIAL_FIELDS = new Set([
"access_key_id",
"secret_access_key",
"session_token",
"service_account_json",
"access_token",
"refresh_token",
"credentials",
"credential",
]);
function rejectProviderCredentialsInMount(value) {
if (Array.isArray(value)) {
for (const child of value) {
rejectProviderCredentialsInMount(child);
}
return;
}
if (value !== null && typeof value === "object") {
for (const [key, child] of Object.entries(value)) {
if (FORBIDDEN_MOUNT_CREDENTIAL_FIELDS.has(key)) {
throw new Error("provider credentials must be supplied in mountConfig.auth, not individual mount specs");
}
rejectProviderCredentialsInMount(child);
}
}
}
function normalizeMountAuth(auth) {
if (!Array.isArray(auth)) {
throw new Error("auth must be an array of provider auth blocks");
}
const byProvider = {};
for (const block of auth) {
if (block === null || typeof block !== "object" || Array.isArray(block)) {
throw new Error("auth must be an array of provider auth blocks");
}
const provider = block.type;
if (provider !== "aws" && provider !== "gcp") {
throw new Error("mountConfig auth only supports aws and gcp blocks");
}
if (byProvider[provider] !== undefined) {
throw new Error(`duplicate ${provider} auth rule in mountConfig`);
}
if (provider === "aws") {
const aws = block.aws;
if (aws === undefined) {
throw new Error("aws mount auth must include an aws block");
}
byProvider.aws = {
access_key_id: copyMountSecret(aws.access_key_id, "accessKeyId"),
secret_access_key: copyMountSecret(aws.secret_access_key, "secretAccessKey"),
};
}
else {
const gcp = block.gcp;
if (gcp === undefined) {
throw new Error("gcp mount auth must include a gcp block");
}
byProvider.gcp = {
service_account_json: copyMountSecret(gcp.service_account_json, "serviceAccountJson"),
};
}
}
return byProvider;
}
function mountConfig({ auth = [], mounts, }) {
const normalizedMounts = normalizeMounts(mounts);
const authByProvider = normalizeMountAuth(auth);
const mountProviders = new Set(normalizedMounts.map((mount) => mount.type));
if (mountProviders.has("s3") && authByProvider.aws === undefined) {
throw new Error("s3 mounts require aws auth in mountConfig");
}
if (mountProviders.has("gcs") && authByProvider.gcp === undefined) {
throw new Error("gcs mounts require gcp auth in mountConfig");
}
if (authByProvider.aws !== undefined && !mountProviders.has("s3")) {
throw new Error("aws auth requires at least one s3 mount in mountConfig");
}
if (authByProvider.gcp !== undefined && !mountProviders.has("gcs")) {
throw new Error("gcp auth requires at least one gcs mount in mountConfig");
}
return {
auth: authByProvider,
mounts: normalizedMounts,
};
}
function validateMountConfigProxyConfig(mountConfig, proxyConfig) {
if (proxyConfig === undefined) {
return;
}
const rules = proxyConfig.rules ?? [];
if (!Array.isArray(rules)) {
throw new Error("proxyConfig rules must be an array");
}
for (const rule of rules) {
if (rule === null || typeof rule !== "object" || Array.isArray(rule)) {
continue;
}
const ruleType = rule.type;
if ((ruleType === "aws" || ruleType === "gcp") &&
mountConfig.auth[ruleType] !== undefined) {
throw new Error(`${ruleType} auth cannot be provided in both mountConfig and proxyConfig`);
}
}
}