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
JavaScript
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