6bf8bebf51
CI / Test and Build (push) Failing after 1s
CI / Migrate Dev DB (push) Has been skipped
CI / Migrate DB (push) Has been skipped
CodeQL / Analyze actions (push) Has been cancelled
CodeQL / Analyze javascript-typescript (push) Has been cancelled
CI / Detect Version (push) Has been cancelled
CI / Detect Desktop Changes (push) Has been cancelled
CI / Build AMD64 (blacksmith-2vcpu-ubuntu-2404, ./docker/cron.Dockerfile, ubuntu-latest, ghcr.io/simstudioai/cron) (push) Has been cancelled
CI / Build AMD64 (blacksmith-2vcpu-ubuntu-2404, ./docker/db.Dockerfile, ECR_MIGRATIONS, ubuntu-latest, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (blacksmith-4vcpu-ubuntu-2404, ./docker/pii.Dockerfile, ECR_PII, ubuntu-latest, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (blacksmith-4vcpu-ubuntu-2404, ./docker/realtime.Dockerfile, ECR_REALTIME, ubuntu-latest, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build AMD64 (blacksmith-8vcpu-ubuntu-2404, ./docker/app.Dockerfile, ECR_APP, linux-x64-8-core, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/cron.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/cron) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/db.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/pii.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/realtime.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-8vcpu-ubuntu-2404-arm, ./docker/app.Dockerfile, linux-arm64-8-core, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
Helm Chart / Lint, test, and validate chart (push) Has been cancelled
Helm Chart / Chart version bumped (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
CI / Build Dev ECR (blacksmith-8vcpu-ubuntu-2404, ./docker/app.Dockerfile, ECR_APP, linux-x64-8-core) (push) Has been cancelled
CI / Promote Images (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/cron) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build Dev ECR (blacksmith-2vcpu-ubuntu-2404, ./docker/db.Dockerfile, ECR_MIGRATIONS, ubuntu-latest) (push) Has been cancelled
CI / Build Dev ECR (blacksmith-4vcpu-ubuntu-2404, ./docker/pii.Dockerfile, ECR_PII, ubuntu-latest) (push) Has been cancelled
CI / Build Dev ECR (blacksmith-4vcpu-ubuntu-2404, ./docker/realtime.Dockerfile, ECR_REALTIME, ubuntu-latest) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Check Desktop Signing Secrets (push) Has been cancelled
CI / Desktop Release (push) Has been cancelled
CI / Create Desktop Prerelease (push) Has been cancelled
CI / Desktop Prerelease Build (push) Has been cancelled
CI / Publish Desktop Prerelease (push) Has been cancelled
CI / Prune Desktop Prereleases (push) Has been cancelled
Helm Chart / Install on kind and run helm test (push) Has been cancelled
107 lines
3.3 KiB
TypeScript
107 lines
3.3 KiB
TypeScript
/**
|
|
* Default Thrive API host (Production, all regions except MEA).
|
|
* The Thrive REST API is reached at `https://{host}/rest/{version}`.
|
|
*/
|
|
export const THRIVE_DEFAULT_HOST = 'public.api.learn.link'
|
|
|
|
/**
|
|
* Builds the base REST URL for a Thrive API request.
|
|
*
|
|
* @param host - The region-specific API host (e.g. `public.api.learn.link`).
|
|
* @param version - The API version: `v1` for most resources, `v2` for user lifecycle.
|
|
*/
|
|
export function getThriveBaseUrl(host: string | undefined, version: 'v1' | 'v2'): string {
|
|
const resolvedHost = host?.trim() || THRIVE_DEFAULT_HOST
|
|
return `https://${resolvedHost}/rest/${version}`
|
|
}
|
|
|
|
/**
|
|
* Builds the HTTP Basic authentication headers for a Thrive API request.
|
|
* The Tenant ID is used as the username and the API key as the password.
|
|
*/
|
|
export function getThriveHeaders(tenantId: string, apiKey: string): Record<string, string> {
|
|
return {
|
|
Authorization: `Basic ${btoa(`${tenantId}:${apiKey}`)}`,
|
|
'Content-Type': 'application/json',
|
|
Accept: 'application/json',
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Appends a query parameter to a URL when the value is defined and non-empty.
|
|
* Numbers are coerced to strings; empty strings and `undefined`/`null` are skipped.
|
|
*/
|
|
export function appendThriveQuery(
|
|
url: URL,
|
|
key: string,
|
|
value: string | number | boolean | undefined | null
|
|
): void {
|
|
if (value === undefined || value === null) return
|
|
const stringValue = typeof value === 'string' ? value.trim() : String(value)
|
|
if (stringValue === '') return
|
|
url.searchParams.set(key, stringValue)
|
|
}
|
|
|
|
/**
|
|
* Parses a value that may be a JSON array string (from LLM/user input) or an
|
|
* already-parsed array into a typed array. An empty/whitespace string yields an
|
|
* empty array; malformed JSON throws so the caller sees a clear error rather
|
|
* than silently sending an empty collection.
|
|
*/
|
|
export function parseThriveArray<T = unknown>(value: unknown, fieldName = 'array'): T[] {
|
|
if (Array.isArray(value)) return value as T[]
|
|
if (typeof value === 'string') {
|
|
const trimmed = value.trim()
|
|
if (trimmed === '') return []
|
|
let parsed: unknown
|
|
try {
|
|
parsed = JSON.parse(trimmed)
|
|
} catch {
|
|
throw new Error(`Invalid JSON provided for ${fieldName}: expected a JSON array`)
|
|
}
|
|
return Array.isArray(parsed) ? (parsed as T[]) : [parsed as T]
|
|
}
|
|
return []
|
|
}
|
|
|
|
/**
|
|
* Parses a JSON object string (from LLM/user input), throwing a descriptive
|
|
* error on malformed JSON so it is never silently dropped.
|
|
*/
|
|
export function parseThriveJsonObject(value: string, fieldName: string): Record<string, unknown> {
|
|
try {
|
|
return JSON.parse(value)
|
|
} catch {
|
|
throw new Error(`Invalid JSON provided for ${fieldName}: expected a JSON object`)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reads a Thrive API response, throwing a descriptive error on non-2xx status.
|
|
* Tolerates empty bodies (returned by some delete endpoints) and non-JSON bodies.
|
|
*/
|
|
export async function parseThriveResponse<T = any>(
|
|
response: Response,
|
|
fallbackError: string
|
|
): Promise<T> {
|
|
const text = await response.text()
|
|
let data: any = {}
|
|
if (text) {
|
|
try {
|
|
data = JSON.parse(text)
|
|
} catch {
|
|
data = { raw: text }
|
|
}
|
|
}
|
|
|
|
if (!response.ok) {
|
|
const message =
|
|
(data && typeof data.message === 'string' && data.message) ||
|
|
(data && typeof data.error === 'string' && data.error) ||
|
|
fallbackError
|
|
throw new Error(message)
|
|
}
|
|
|
|
return data as T
|
|
}
|