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.

217 lines (215 loc) • 8.89 kB
const require_consts = require('../../helpers/consts.cjs'); const require_version = require('../../version.cjs'); const require_env = require('../../helpers/env.cjs'); const require_InngestExecution = require('../execution/InngestExecution.cjs'); const require_functions = require('../../helpers/functions.cjs'); const require_strings = require('../../helpers/strings.cjs'); const require_Inngest = require('../Inngest.cjs'); const require_InngestCommHandler = require('../InngestCommHandler.cjs'); const require_connect = require('../../proto/src/components/connect/protobuf/connect.cjs'); const require_util = require('./util.cjs'); const require_types = require('./types.cjs'); const require_index = require('./strategies/index.cjs'); //#region src/components/connect/index.ts const InngestBranchEnvironmentSigningKeyPrefix = "signkey-branch-"; /** * WebSocket worker connection that implements the WorkerConnection interface. * * This class acts as a facade that delegates to a connection strategy. * The strategy determines how the WebSocket connection, heartbeater, and * lease extender are managed (same thread vs worker thread). */ var WebSocketWorkerConnection = class { inngest; options; strategy; constructor(options) { if (!Array.isArray(options.apps) || options.apps.length === 0 || !options.apps[0]) throw new Error("No apps provided"); this.inngest = options.apps[0].client; for (const app of options.apps) { const client = app.client; if (client.env !== this.inngest.env) throw new Error(`All apps must be configured to the same environment. ${client.id} is configured to ${client.env} but ${this.inngest.id} is configured to ${this.inngest.env}`); } this.options = this.applyDefaults(options); } get functions() { const functions = {}; for (const app of this.options.apps) { const client = app.client; if (functions[client.id]) throw new Error(`Duplicate app id: ${client.id}`); functions[client.id] = { client: app.client, functions: app.functions ?? client.funcs }; } return functions; } applyDefaults(opts) { const options = { ...opts }; if (!Array.isArray(options.handleShutdownSignals)) options.handleShutdownSignals = require_types.DEFAULT_SHUTDOWN_SIGNALS; const env = require_env.allProcessEnv(); if (options.maxWorkerConcurrency === void 0) { const envValue = env[require_consts.envKeys.InngestConnectMaxWorkerConcurrency]; if (envValue) { const parsed = Number.parseInt(envValue, 10); if (!Number.isNaN(parsed) && parsed > 0) options.maxWorkerConcurrency = parsed; } } if (options.isolateExecution === void 0) { const envValue = env[require_consts.envKeys.InngestConnectIsolateExecution]; if (envValue === "0" || envValue === "false") options.isolateExecution = false; } if (options.gatewayUrl === void 0) { const envValue = env[require_consts.envKeys.InngestConnectGatewayUrl]; if (envValue) options.gatewayUrl = envValue; } return options; } get state() { return this.strategy?.state ?? require_types.ConnectionState.CONNECTING; } get connectionId() { if (!this.strategy?.connectionId) throw new Error("Connection not prepared"); return this.strategy.connectionId; } get closed() { if (!this.strategy) throw new Error("No connection established"); return this.strategy.closed; } async close() { if (!this.strategy) return; return this.strategy.close(); } /** * Establish a persistent connection to the gateway. */ async connect(attempt = 0) { this.inngest[require_Inngest.internalLoggerSymbol].debug({ attempt }, "Establishing connection"); const envName = this.inngest.env ?? require_env.getEnvironmentName(); const hashedSigningKey = this.inngest.signingKey ? require_strings.hashSigningKey(this.inngest.signingKey) : void 0; if (this.inngest.signingKey && this.inngest.signingKey.startsWith(InngestBranchEnvironmentSigningKeyPrefix) && !envName) throw new Error("Environment is required when using branch environment signing keys"); const hashedFallbackKey = this.inngest.signingKeyFallback ? require_strings.hashSigningKey(this.inngest.signingKeyFallback) : void 0; const capabilities = { trust_probe: "v1", connect: "v1" }; const functionConfigs = {}; for (const [appId, { client, functions }] of Object.entries(this.functions)) functionConfigs[appId] = { client, functions: functions.flatMap((f) => f["getConfig"]({ baseUrl: new URL("wss://connect"), appPrefix: client.id, isConnect: true })) }; this.inngest[require_Inngest.internalLoggerSymbol].debug({ functionSlugs: Object.entries(functionConfigs).map(([appId, { functions }]) => { return JSON.stringify({ appId, functions: functions.map((f) => ({ id: f.id, stepUrls: Object.values(f.steps).map((s) => s.runtime["url"]) })) }); }) }, "Prepared sync data"); const connectionData = { manualReadinessAck: false, marshaledCapabilities: JSON.stringify(capabilities), apps: Object.entries(functionConfigs).map(([appId, { client, functions }]) => ({ appName: appId, appVersion: client.appVersion, functions: new TextEncoder().encode(JSON.stringify(functions)) })) }; const requestHandlers = {}; for (const [appId, { client, functions }] of Object.entries(this.functions)) { const inngestCommHandler = new require_InngestCommHandler.InngestCommHandler({ client, functions, frameworkName: "connect", skipSignatureValidation: true, handler: (msg) => { const asString = new TextDecoder().decode(msg.requestPayload); const parsed = require_functions.parseFnData(JSON.parse(asString), void 0, this.inngest[require_Inngest.internalLoggerSymbol]); const userTraceCtx = require_util.parseTraceCtx(msg.userTraceCtx); return { body() { return parsed; }, method() { return "POST"; }, headers(key) { switch (key) { case require_consts.headerKeys.ContentLength.toString(): return asString.length.toString(); case require_consts.headerKeys.InngestExpectedServerKind.toString(): return "connect"; case require_consts.headerKeys.RequestVersion.toString(): return parsed.version.toString(); case require_consts.headerKeys.Signature.toString(): return null; case require_consts.headerKeys.TraceParent.toString(): return userTraceCtx?.traceParent ?? null; case require_consts.headerKeys.TraceState.toString(): return userTraceCtx?.traceState ?? null; default: return null; } }, transformResponse({ body, headers, status }) { let sdkResponseStatus = require_connect.SDKResponseStatus.DONE; switch (status) { case 200: sdkResponseStatus = require_connect.SDKResponseStatus.DONE; break; case 206: sdkResponseStatus = require_connect.SDKResponseStatus.NOT_COMPLETED; break; case 500: sdkResponseStatus = require_connect.SDKResponseStatus.ERROR; break; } return require_connect.SDKResponse.create({ requestId: msg.requestId, accountId: msg.accountId, envId: msg.envId, appId: msg.appId, status: sdkResponseStatus, body: new TextEncoder().encode(body), noRetry: headers[require_consts.headerKeys.NoRetry] === "true", retryAfter: headers[require_consts.headerKeys.RetryAfter], sdkVersion: `inngest-js:v${require_version.version}`, requestVersion: parseInt(headers[require_consts.headerKeys.RequestVersion] ?? require_InngestExecution.PREFERRED_ASYNC_EXECUTION_VERSION.toString(), 10), systemTraceCtx: msg.systemTraceCtx, userTraceCtx: msg.userTraceCtx, runId: msg.runId }); }, url() { const baseUrl = new URL("http://connect.inngest.com"); baseUrl.searchParams.set(require_consts.queryKeys.FnId, msg.functionSlug); if (msg.stepId) baseUrl.searchParams.set(require_consts.queryKeys.StepId, msg.stepId); return baseUrl; } }; } }); if (!inngestCommHandler.checkModeConfiguration()) throw new Error("Signing key is required"); requestHandlers[appId] = inngestCommHandler.createHandler(); } this.strategy = await require_index.createStrategy({ hashedSigningKey, hashedFallbackKey, internalLogger: this.inngest[require_Inngest.internalLoggerSymbol], envName, connectionData, requestHandlers, options: this.options, apiBaseUrl: this.inngest.apiBaseUrl, mode: this.inngest["mode"] }, this.options); await this.strategy.connect(attempt); } }; const connect = async (options) => { if (options.apps.length === 0) throw new Error("No apps provided"); const conn = new WebSocketWorkerConnection(options); await conn.connect(); return conn; }; //#endregion exports.connect = connect; //# sourceMappingURL=index.cjs.map