@anthropic-ai/sdk
Version:
The official TypeScript library for the Anthropic API
142 lines (115 loc) • 4.63 kB
text/typescript
import { AnthropicError } from '../../core/error';
// https://url.spec.whatwg.org/#url-scheme-string
const startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;
export const isAbsoluteURL = (url: string): boolean => {
return startsWithSchemeRegexp.test(url);
};
export let isArray = (val: unknown): val is unknown[] => ((isArray = Array.isArray), isArray(val));
export let isReadonlyArray = isArray as (val: unknown) => val is readonly unknown[];
/** Returns an object if the given value isn't an object, otherwise returns as-is */
export function maybeObj(x: unknown): object {
if (typeof x !== 'object') {
return {};
}
return x ?? {};
}
// https://stackoverflow.com/a/34491287
export function isEmptyObj(obj: Object | null | undefined): boolean {
if (!obj) return true;
for (const _k in obj) return false;
return true;
}
// https://eslint.org/docs/latest/rules/no-prototype-builtins
export function hasOwn<T extends object = object>(obj: T, key: PropertyKey): key is keyof T {
return Object.prototype.hasOwnProperty.call(obj, key);
}
export function isObj(obj: unknown): obj is Record<string, unknown> {
return obj != null && typeof obj === 'object' && !Array.isArray(obj);
}
export const ensurePresent = <T>(value: T | null | undefined): T => {
if (value == null) {
throw new AnthropicError(`Expected a value to be given but received ${value} instead.`);
}
return value;
};
export const validatePositiveInteger = (name: string, n: unknown): number => {
if (typeof n !== 'number' || !Number.isInteger(n)) {
throw new AnthropicError(`${name} must be an integer`);
}
if (n < 0) {
throw new AnthropicError(`${name} must be a positive integer`);
}
return n;
};
export const CREDENTIAL_OPTIONS = ['apiKey', 'authToken', 'credentials', 'config', 'profile'] as const;
export type CredentialOption = (typeof CREDENTIAL_OPTIONS)[number];
export type PlatformCredentials = {
/** The first-party credential options the platform client takes. It rejects the rest. */
accepts: readonly CredentialOption[];
unsupportedOptionMessage: (option: CredentialOption) => string;
};
/**
* Throws when `options` holds a first-party credential option that a platform
* client does not accept, so that a new one is rejected until the client opts
* in. `null` passes, because the base `withOptions` fills the credential
* options it clears with `null`.
*/
export const rejectUnsupportedCredentials = (options: object, platform: PlatformCredentials): void => {
for (const name of CREDENTIAL_OPTIONS) {
if (!platform.accepts.includes(name) && (options as Record<string, unknown>)[name] != null) {
throw new AnthropicError(platform.unsupportedOptionMessage(name));
}
}
};
export const coerceInteger = (value: unknown): number => {
if (typeof value === 'number') return Math.round(value);
if (typeof value === 'string') return parseInt(value, 10);
throw new AnthropicError(`Could not coerce ${value} (type: ${typeof value}) into a number`);
};
export const coerceFloat = (value: unknown): number => {
if (typeof value === 'number') return value;
if (typeof value === 'string') return parseFloat(value);
throw new AnthropicError(`Could not coerce ${value} (type: ${typeof value}) into a number`);
};
export const coerceBoolean = (value: unknown): boolean => {
if (typeof value === 'boolean') return value;
if (typeof value === 'string') return value === 'true';
return Boolean(value);
};
export const maybeCoerceInteger = (value: unknown): number | undefined => {
if (value == null) {
return undefined;
}
return coerceInteger(value);
};
export const maybeCoerceFloat = (value: unknown): number | undefined => {
if (value == null) {
return undefined;
}
return coerceFloat(value);
};
export const maybeCoerceBoolean = (value: unknown): boolean | undefined => {
if (value == null) {
return undefined;
}
return coerceBoolean(value);
};
export const safeJSON = (text: string) => {
try {
return JSON.parse(text);
} catch (err) {
return undefined;
}
};
// Gets a value from an object, deletes the key, and returns the value (or undefined if not found)
export const pop = <T extends Record<string, any>, K extends string>(obj: T, key: K): T[K] => {
const value = obj[key];
delete obj[key];
return value;
};
/**
* Compile-time exhaustiveness check: passing a value here only type-checks once every
* member of its union has been handled. Does nothing at runtime, so unknown values from a
* newer API version fall through instead of throwing.
*/
export function checkNever(_value: never): void {}