chore: import upstream snapshot with attribution
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (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 / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (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 / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
Reference in New Issue
Block a user