The Coline App SDK: apps, tools, file types and surfaces that run inside Coline workspaces, and public websites with Coline Sites. TypeScript, with an in-memory test workspace. MIT.
| 4 |
| /** |
| 5 | * Helpers shared by every execution path that hosts app handlers: the |
| 6 | * external `createColineAppHandler`, and the test workspace. The hosted |
| 7 | * Dynamic Worker bootstrap mirrors these in plain JavaScript. |
| 8 | */ |
| 9 |
| 10 | export function parseEndpointJson<T>(body: string): T { |
| 11 | try { |
| 12 | return JSON.parse(body) as T; |
| 13 | } catch { |
| 14 | throw Object.assign(new Error("The request body is not valid JSON."), { |
| 15 | code: "invalid_json", |
| 16 | }); |
| 17 | } |
| 18 | } |
| 19 |
| 20 | export function createJobRunInfo( |
| 21 | endpoint: CapabilityEndpoint, |
| 22 | job: { |
| 23 | id: string; |
| 24 | name: string; |
| 25 | attempt: number; |
| 26 | maxAttempts: number; |
| 27 | enqueuedAt: string; |
| 28 | checkpoint: unknown; |
| 29 | }, |
| 30 | ): ColineJobRunInfo { |
| 31 | const post = async (operation: string, args: unknown[]) => { |
| 32 | const fetchImpl = endpoint.fetchImpl ?? fetch; |
| 33 | const response = await fetchImpl(endpoint.url, { |
| 34 | method: "POST", |
| 35 | headers: { |
| 36 | "content-type": "application/json", |
| 37 | authorization: `Bearer ${endpoint.token}`, |
| 38 | }, |
| 39 | body: JSON.stringify({ operation, args }), |
| 40 | }); |
| 41 | const parsed = (await response.json().catch(() => null)) as { |
| 42 | error?: { code?: string; message?: string }; |
| 43 | } | null; |
| 44 | if (!response.ok || parsed?.error) { |
| 45 | throw Object.assign(new Error(parsed?.error?.message ?? `${operation} failed.`), { |
| 46 | code: parsed?.error?.code ?? "capability_error", |
| 47 | }); |
| 48 | } |
| 49 | }; |
| 50 | return { |
| 51 | id: job.id, |
| 52 | name: job.name, |
| 53 | attempt: job.attempt, |
| 54 | maxAttempts: job.maxAttempts, |
| 55 | enqueuedAt: job.enqueuedAt, |
| 56 | checkpoint: job.checkpoint ?? null, |
| 57 | saveCheckpoint: (state) => post("jobs.checkpoint", [state]), |
| 58 | progress: (value, message) => post("jobs.progress", [{ value, message: message ?? null }]), |
| 59 | }; |
| 60 | } |
| 61 |