UNPKG

inngest

Version:

Official SDK for Inngest.com. Inngest is the reliability layer for modern applications. Inngest combines durable execution, events, and queues into a zero-infra platform with built-in observability.

311 lines (309 loc) • 9.51 kB
import { getErrorMessage } from "../helpers/errors.js"; import { err, ok } from "../types.js"; import { batchSchema, errorSchema, stepSchema } from "./schema.js"; import { fetchWithAuthFallback } from "../helpers/net.js"; import { hashSigningKey } from "../helpers/strings.js"; import { z } from "zod/v3"; //#region src/api/api.ts const realtimeSubscriptionTokenSchema = z.object({ jwt: z.string() }); const sendSignalSuccessResponseSchema = z.object({ data: z.object({ run_id: z.string().min(1) }) }); const checkpointNewRunResponseSchema = z.object({ data: z.object({ fn_id: z.string().min(1), app_id: z.string().min(1), run_id: z.string().min(1), token: z.string().min(1).optional() }) }); var InngestApi = class { _signingKey; _signingKeyFallback; _apiBaseUrl; _fetch; constructor({ baseUrl, signingKey, signingKeyFallback, fetch }) { this._apiBaseUrl = baseUrl; this._signingKey = signingKey; this._signingKeyFallback = signingKeyFallback; this._fetch = fetch; } get apiBaseUrl() { return this._apiBaseUrl(); } get signingKey() { return this._signingKey(); } get signingKeyFallback() { return this._signingKeyFallback(); } get hashedKey() { return hashSigningKey(this.signingKey); } get hashedFallbackKey() { if (!this.signingKeyFallback) return; return hashSigningKey(this.signingKeyFallback); } async getTargetUrl(path) { return new URL(path, this.apiBaseUrl); } async req(url, options) { const finalUrl = typeof url === "string" ? await this.getTargetUrl(url) : url; try { return ok(await fetchWithAuthFallback({ authToken: this.hashedKey, authTokenFallback: this.hashedFallbackKey, fetch: this._fetch(), url: finalUrl, options: { ...options, headers: { "Content-Type": "application/json", ...options?.headers } } })); } catch (error) { return err(error); } } async getRunSteps(runId) { const result = await this.req(`/v0/runs/${runId}/actions`); if (result.ok) { const res = result.value; const data = await res.json(); if (res.ok) return ok(stepSchema.parse(data)); return err(errorSchema.parse(data)); } return err({ error: getErrorMessage(result.error, "Unknown error retrieving step data"), status: 500 }); } async getRunBatch(runId) { const result = await this.req(`/v0/runs/${runId}/batch`); if (result.ok) { const res = result.value; const data = await res.json(); if (res.ok) return ok(batchSchema.parse(data)); return err(errorSchema.parse(data)); } return err({ error: getErrorMessage(result.error, "Unknown error retrieving event batch"), status: 500 }); } async publish(publishOptions, data) { const isStream = data instanceof ReadableStream; const url = await this.getTargetUrl("/v1/realtime/publish"); url.searchParams.set("channel", publishOptions.channel || ""); if (publishOptions.runId) url.searchParams.set("run_id", publishOptions.runId); for (const topic of publishOptions.topics) url.searchParams.append("topic", topic); const result = await this.req(url, { body: isStream ? data : typeof data === "string" ? data : JSON.stringify(data), method: "POST", headers: { "Content-Type": isStream ? "text/stream" : "application/json" }, ...isStream ? { duplex: "half" } : {} }); if (result.ok) { const res = result.value; if (!res.ok) throw new Error(`Failed to publish event: ${res.status} ${res.statusText}`); return ok(void 0); } return err({ error: getErrorMessage(result.error, "Unknown error publishing event"), status: 500 }); } async sendSignal(signalOptions, options) { const url = await this.getTargetUrl("/v1/signals"); const body = { signal: signalOptions.signal, data: signalOptions.data }; return fetchWithAuthFallback({ authToken: this.hashedKey, authTokenFallback: this.hashedFallbackKey, fetch: this._fetch(), url, options: { method: "POST", body: JSON.stringify(body), headers: { "Content-Type": "application/json", ...options?.headers } } }).then(async (res) => { if (res.status === 404) return ok({ runId: void 0 }); const resClone = res.clone(); let json; try { json = await res.json(); } catch { return err({ error: `Failed to send signal: ${res.status} ${res.statusText} - ${await resClone.text()}`, status: res.status }); } if (!res.ok) try { return err(errorSchema.parse(json)); } catch { return err({ error: `Failed to send signal: ${res.status} ${res.statusText} - ${await res.text()}`, status: res.status }); } const parseRes = sendSignalSuccessResponseSchema.safeParse(json); if (!parseRes.success) return err({ error: `Successfully sent signal, but response parsing failed: ${res.status} ${res.statusText} - ${await resClone.text()}`, status: res.status }); return ok({ runId: parseRes.data.data.run_id }); }).catch((error) => { return err({ error: getErrorMessage(error, "Unknown error sending signal"), status: 500 }); }); } async getSubscriptionToken(channel, topics) { const url = await this.getTargetUrl("/v1/realtime/token"); const body = topics.map((topic) => ({ channel, name: topic, kind: "run" })); return fetchWithAuthFallback({ authToken: this.hashedKey, authTokenFallback: this.hashedFallbackKey, fetch: this._fetch(), url, options: { method: "POST", body: JSON.stringify(body), headers: { "Content-Type": "application/json" } } }).then(async (res) => { if (!res.ok) throw new Error(`Failed to get subscription token: ${res.status} ${res.statusText} - ${await res.text()}`); return realtimeSubscriptionTokenSchema.parse(await res.json()).jwt; }).catch((error) => { throw new Error(getErrorMessage(error, "Unknown error getting subscription token")); }); } async updateMetadata(args, options) { const payload = { target: args.target, metadata: args.metadata }; const result = await this.req(`/v1/runs/${args.target.run_id}/metadata`, { method: "POST", body: JSON.stringify(payload), headers: options?.headers }); if (!result.ok) return err({ error: getErrorMessage(result.error, "Unknown error updating metadata"), status: 500 }); const res = result.value; if (res.ok) return ok(void 0); const resClone = res.clone(); let json; try { json = await res.json(); } catch { return err({ error: `Failed to update metadata: ${res.status} ${res.statusText} - ${await resClone.text()}`, status: res.status }); } try { return err(errorSchema.parse(json)); } catch { return err({ error: `Failed to update metadata: ${res.status} ${res.statusText}`, status: res.status }); } } /** * Start a new run, optionally passing in a number of steps to initialize the * run with. */ async checkpointNewRun(args) { const body = JSON.stringify({ run_id: args.runId, event: args.event, steps: args.steps, ts: (/* @__PURE__ */ new Date()).valueOf(), request_version: args.executionVersion, retries: args.retries }); const result = await this.req("/v1/checkpoint", { method: "POST", body }); if (!result.ok) throw new Error(getErrorMessage(result.error, "Unknown error checkpointing new run")); const res = result.value; if (res.ok) { const rawData = await res.json(); return checkpointNewRunResponseSchema.parse(rawData); } throw new Error(`Failed to checkpoint new run: ${res.status} ${res.statusText} - ${await res.text()}`); } /** * Checkpoint steps for a given sync run. */ async checkpointSteps(args) { const body = JSON.stringify({ fn_id: args.fnId, app_id: args.appId, run_id: args.runId, steps: args.steps, ts: (/* @__PURE__ */ new Date()).valueOf() }); const result = await this.req(`/v1/checkpoint/${args.runId}/steps`, { method: "POST", body }); if (!result.ok) throw new Error(getErrorMessage(result.error, "Unknown error checkpointing steps")); const res = result.value; if (!res.ok) throw new Error(`Failed to checkpoint steps: ${res.status} ${res.statusText} - ${await res.text()}`); } /** * Checkpoint steps for a given async run. */ async checkpointStepsAsync(args) { const body = JSON.stringify({ run_id: args.runId, fn_id: args.fnId, qi_id: args.queueItemId, steps: args.steps, ts: (/* @__PURE__ */ new Date()).valueOf() }); const result = await this.req(`/v1/checkpoint/${args.runId}/async`, { method: "POST", body }); if (!result.ok) throw new Error(getErrorMessage(result.error, "Unknown error checkpointing async")); const res = result.value; if (!res.ok) throw new Error(`Failed to checkpoint async: ${res.status} ${res.statusText} - ${await res.text()}`); } /** * Fetch the output of a completed run using a token. * * This uses token-based auth (not signing key) and is intended for use by * proxy endpoints that fetch results on behalf of users. * * @param runId - The ID of the run to fetch output for * @param token - The token used to authenticate the request * @returns The raw Response from the API */ async getRunOutput(runId, token) { const url = await this.getTargetUrl(`/v1/http/runs/${runId}/output`); url.searchParams.set("token", token); return this._fetch()(url.toString(), { method: "GET", headers: { "Content-Type": "application/json" } }); } }; //#endregion export { InngestApi }; //# sourceMappingURL=api.js.map