paperclip/server/src/services/cloud-instance.ts

53 lines
1.8 KiB
TypeScript

export type CloudInstanceEnv = Record<string, string | undefined>;
export type CloudStackContext = {
stackId: string | null;
stackSlug: string | null;
accountGroupId: string | null;
primaryHost: string | null;
cloudOrigin: string | null;
};
function normalizeOptionalEnvValue(value: string | undefined): string | null {
const normalized = value?.trim();
return normalized ? normalized : null;
}
/**
* The canonical Paperclip Cloud instance predicate.
*
* The tenant token is the signal injected on live cloud stacks. The managed
* config document is the legacy/bootstrap signal used by managed feature and
* plugin floors. Their union is intentionally monotonic: either prior signal
* keeps every restrictive cloud floor enabled.
*/
export function isCloudManagedInstance(
env: CloudInstanceEnv = process.env,
): boolean {
return (
normalizeOptionalEnvValue(env.PAPERCLIP_CLOUD_TENANT_SERVER_TOKEN) !== null ||
env.PAPERCLIP_MANAGED_CONFIG !== undefined
);
}
/**
* Public stack metadata injected by the Paperclip Cloud provisioner.
*
* A managed signal can exist briefly before every metadata value is available,
* so absent or blank values are represented as null rather than making health
* checks fail. Self-hosted instances never expose a stack context.
*/
export function getCloudStackContext(
env: CloudInstanceEnv = process.env,
): CloudStackContext | null {
if (!isCloudManagedInstance(env)) return null;
return {
stackId: normalizeOptionalEnvValue(env.PAPERCLIP_CLOUD_STACK_ID),
stackSlug: normalizeOptionalEnvValue(env.PAPERCLIP_STACK_SLUG),
accountGroupId: normalizeOptionalEnvValue(env.PAPERCLIP_CLOUD_ACCOUNT_GROUP_ID),
primaryHost: normalizeOptionalEnvValue(env.PAPERCLIP_PRIMARY_HOST),
cloudOrigin: normalizeOptionalEnvValue(env.PAPERCLIP_CLOUD_API_ORIGIN),
};
}