@automagik/omni 2.260911.2 → 2.260911.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/db/drizzle/0067_automation_concurrency.sql +34 -0
- package/db/drizzle/meta/_journal.json +7 -0
- package/dist/commands/automations.d.ts +2 -0
- package/dist/commands/automations.d.ts.map +1 -1
- package/dist/commands/webhooks.d.ts +1 -1
- package/dist/commands/webhooks.d.ts.map +1 -1
- package/dist/index.js +51 -29
- package/dist/sdk/client.d.ts +21 -1
- package/dist/sdk/client.d.ts.map +1 -1
- package/dist/sdk/types.generated.d.ts +145 -2
- package/dist/sdk/types.generated.d.ts.map +1 -1
- package/dist/server/index.js +142 -46
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -38426,7 +38426,7 @@ var init_debounce = __esm(() => {
|
|
|
38426
38426
|
class AutomationEngine {
|
|
38427
38427
|
config;
|
|
38428
38428
|
subscriptions = new Map;
|
|
38429
|
-
|
|
38429
|
+
queues = new Map;
|
|
38430
38430
|
debounceManagers = new Map;
|
|
38431
38431
|
automations = [];
|
|
38432
38432
|
eventBus = null;
|
|
@@ -38751,29 +38751,38 @@ class AutomationEngine {
|
|
|
38751
38751
|
const manager = new DebounceManager(automation.debounce, callback);
|
|
38752
38752
|
this.debounceManagers.set(automation.id, manager);
|
|
38753
38753
|
}
|
|
38754
|
+
resolveQueueKey(automation, context2, instanceId) {
|
|
38755
|
+
if (automation.maxConcurrency == null && automation.concurrencyKey == null)
|
|
38756
|
+
return instanceId;
|
|
38757
|
+
const base = `${instanceId}:${automation.id}`;
|
|
38758
|
+
if (!automation.concurrencyKey)
|
|
38759
|
+
return base;
|
|
38760
|
+
const partition = substituteTemplate(automation.concurrencyKey, context2).trim();
|
|
38761
|
+
return partition ? `${base}:${partition}` : base;
|
|
38762
|
+
}
|
|
38754
38763
|
async queueExecution(automation, event, context2, instanceId) {
|
|
38755
|
-
|
|
38756
|
-
|
|
38757
|
-
|
|
38758
|
-
|
|
38759
|
-
|
|
38760
|
-
|
|
38761
|
-
|
|
38762
|
-
|
|
38763
|
-
|
|
38764
|
-
|
|
38765
|
-
|
|
38764
|
+
const key = this.resolveQueueKey(automation, context2, instanceId);
|
|
38765
|
+
const maxConcurrency = automation.maxConcurrency ?? this.config.instanceConcurrencyOverrides?.[instanceId] ?? this.config.defaultConcurrency;
|
|
38766
|
+
const queue = this.queues.get(key) ?? {
|
|
38767
|
+
key,
|
|
38768
|
+
evictWhenIdle: key !== instanceId,
|
|
38769
|
+
activeCount: 0,
|
|
38770
|
+
maxConcurrency,
|
|
38771
|
+
pending: []
|
|
38772
|
+
};
|
|
38773
|
+
queue.maxConcurrency = maxConcurrency;
|
|
38774
|
+
this.queues.set(key, queue);
|
|
38766
38775
|
if (queue.activeCount < queue.maxConcurrency) {
|
|
38767
38776
|
return this.executeAutomation(automation, event, context2, queue);
|
|
38768
38777
|
}
|
|
38769
38778
|
const maxQueueDepth = this.config.maxQueueDepth ?? 100;
|
|
38770
38779
|
if (queue.pending.length >= maxQueueDepth) {
|
|
38771
38780
|
logger4.warn("Queue full, applying backpressure", {
|
|
38772
|
-
|
|
38781
|
+
queueKey: key,
|
|
38773
38782
|
queueDepth: queue.pending.length,
|
|
38774
38783
|
maxDepth: maxQueueDepth
|
|
38775
38784
|
});
|
|
38776
|
-
throw new QueueFullError(
|
|
38785
|
+
throw new QueueFullError(key, queue.pending.length, maxQueueDepth);
|
|
38777
38786
|
}
|
|
38778
38787
|
const queueRef = queue;
|
|
38779
38788
|
return new Promise((resolve) => {
|
|
@@ -38785,7 +38794,7 @@ class AutomationEngine {
|
|
|
38785
38794
|
});
|
|
38786
38795
|
logger4.debug("Execution queued", {
|
|
38787
38796
|
automationId: automation.id,
|
|
38788
|
-
|
|
38797
|
+
queueKey: key,
|
|
38789
38798
|
queueLength: queueRef.pending.length
|
|
38790
38799
|
});
|
|
38791
38800
|
});
|
|
@@ -38892,6 +38901,10 @@ class AutomationEngine {
|
|
|
38892
38901
|
next.resolve(result);
|
|
38893
38902
|
}
|
|
38894
38903
|
}
|
|
38904
|
+
if (queue.evictWhenIdle && queue.activeCount === 0 && queue.pending.length === 0) {
|
|
38905
|
+
if (this.queues.get(queue.key) === queue)
|
|
38906
|
+
this.queues.delete(queue.key);
|
|
38907
|
+
}
|
|
38895
38908
|
}
|
|
38896
38909
|
}
|
|
38897
38910
|
async logExecution(result, trustedTenantId = null) {
|
|
@@ -38917,8 +38930,8 @@ class AutomationEngine {
|
|
|
38917
38930
|
});
|
|
38918
38931
|
}
|
|
38919
38932
|
getMetrics() {
|
|
38920
|
-
const instanceQueues = Array.from(this.
|
|
38921
|
-
instanceId: q.
|
|
38933
|
+
const instanceQueues = Array.from(this.queues.values()).map((q) => ({
|
|
38934
|
+
instanceId: q.key,
|
|
38922
38935
|
activeCount: q.activeCount,
|
|
38923
38936
|
pendingCount: q.pending.length
|
|
38924
38937
|
}));
|
|
@@ -38961,12 +38974,12 @@ var init_engine = __esm(() => {
|
|
|
38961
38974
|
init_templates();
|
|
38962
38975
|
logger4 = createLogger("automations:engine");
|
|
38963
38976
|
QueueFullError = class QueueFullError extends Error {
|
|
38964
|
-
|
|
38977
|
+
queueKey;
|
|
38965
38978
|
queueDepth;
|
|
38966
38979
|
maxDepth;
|
|
38967
|
-
constructor(
|
|
38968
|
-
super(`Queue full for
|
|
38969
|
-
this.
|
|
38980
|
+
constructor(queueKey, queueDepth, maxDepth) {
|
|
38981
|
+
super(`Queue full for ${queueKey}: ${queueDepth}/${maxDepth} pending`);
|
|
38982
|
+
this.queueKey = queueKey;
|
|
38970
38983
|
this.queueDepth = queueDepth;
|
|
38971
38984
|
this.maxDepth = maxDepth;
|
|
38972
38985
|
this.name = "QueueFullError";
|
|
@@ -76985,7 +76998,7 @@ var require_ClientVoiceManager = __commonJS((exports, module) => {
|
|
|
76985
76998
|
|
|
76986
76999
|
// ../../node_modules/.bun/@discordjs+ws@1.2.3/node_modules/@discordjs/ws/dist/index.js
|
|
76987
77000
|
var require_dist9 = __commonJS((exports, module) => {
|
|
76988
|
-
var __dirname = "/home/runner/work/omni/omni
|
|
77001
|
+
var __dirname = "/home/runner/work/omni/omni/node_modules/.bun/@discordjs+ws@1.2.3/node_modules/@discordjs/ws/dist";
|
|
76989
77002
|
var __create2 = Object.create;
|
|
76990
77003
|
var __defProp2 = Object.defineProperty;
|
|
76991
77004
|
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
|
|
@@ -162265,7 +162278,7 @@ var require_indexes = __commonJS((exports, module) => {
|
|
|
162265
162278
|
|
|
162266
162279
|
// ../../node_modules/.bun/thread-stream@3.1.0/node_modules/thread-stream/index.js
|
|
162267
162280
|
var require_thread_stream = __commonJS((exports, module) => {
|
|
162268
|
-
var __dirname = "/home/runner/work/omni/omni
|
|
162281
|
+
var __dirname = "/home/runner/work/omni/omni/node_modules/.bun/thread-stream@3.1.0/node_modules/thread-stream";
|
|
162269
162282
|
var { version } = require_package5();
|
|
162270
162283
|
var { EventEmitter: EventEmitter3 } = __require("events");
|
|
162271
162284
|
var { Worker } = __require("worker_threads");
|
|
@@ -162686,7 +162699,7 @@ var require_thread_stream = __commonJS((exports, module) => {
|
|
|
162686
162699
|
|
|
162687
162700
|
// ../../node_modules/.bun/pino@9.14.0/node_modules/pino/lib/transport.js
|
|
162688
162701
|
var require_transport2 = __commonJS((exports, module) => {
|
|
162689
|
-
var __dirname = "/home/runner/work/omni/omni
|
|
162702
|
+
var __dirname = "/home/runner/work/omni/omni/node_modules/.bun/pino@9.14.0/node_modules/pino/lib";
|
|
162690
162703
|
var { createRequire: createRequire2 } = __require("module");
|
|
162691
162704
|
var getCallers = require_caller();
|
|
162692
162705
|
var { join: join8, isAbsolute, sep: sep2 } = __require("path");
|
|
@@ -174411,6 +174424,8 @@ var init_schema2 = __esm(() => {
|
|
|
174411
174424
|
enabled: boolean2("enabled").notNull().default(true),
|
|
174412
174425
|
priority: integer("priority").notNull().default(0),
|
|
174413
174426
|
transactionalEmissions: boolean2("transactional_emissions").notNull().default(false),
|
|
174427
|
+
maxConcurrency: integer("max_concurrency"),
|
|
174428
|
+
concurrencyKey: text("concurrency_key"),
|
|
174414
174429
|
managedByAgentId: uuid("managed_by_agent_id").references(() => agents.id, { onDelete: "cascade" }),
|
|
174415
174430
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
174416
174431
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
@@ -244431,7 +244446,7 @@ var require_client3 = __commonJS((exports) => {
|
|
|
244431
244446
|
|
|
244432
244447
|
// ../../node_modules/.bun/@sentry+node-core@10.52.0+2c50d7e904f6cfd7/node_modules/@sentry/node-core/build/cjs/sdk/esmLoader.js
|
|
244433
244448
|
var require_esmLoader = __commonJS((exports) => {
|
|
244434
|
-
var __filename = "/home/runner/work/omni/omni
|
|
244449
|
+
var __filename = "/home/runner/work/omni/omni/node_modules/.bun/@sentry+node-core@10.52.0+2c50d7e904f6cfd7/node_modules/@sentry/node-core/build/cjs/sdk/esmLoader.js";
|
|
244435
244450
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
244436
244451
|
var core3 = require_cjs6();
|
|
244437
244452
|
var importInTheMiddle = require_import_in_the_middle();
|
|
@@ -251657,7 +251672,7 @@ var init_sentry_scrub = __esm(() => {
|
|
|
251657
251672
|
var require_package7 = __commonJS((exports, module) => {
|
|
251658
251673
|
module.exports = {
|
|
251659
251674
|
name: "@omni/api",
|
|
251660
|
-
version: "2.260911.
|
|
251675
|
+
version: "2.260911.4",
|
|
251661
251676
|
private: true,
|
|
251662
251677
|
type: "module",
|
|
251663
251678
|
exports: {
|
|
@@ -278759,7 +278774,7 @@ var require_src45 = __commonJS((exports) => {
|
|
|
278759
278774
|
|
|
278760
278775
|
// ../../node_modules/.bun/@grpc+grpc-js@1.14.3/node_modules/@grpc/grpc-js/build/src/channelz.js
|
|
278761
278776
|
var require_channelz = __commonJS((exports) => {
|
|
278762
|
-
var __dirname = "/home/runner/work/omni/omni
|
|
278777
|
+
var __dirname = "/home/runner/work/omni/omni/node_modules/.bun/@grpc+grpc-js@1.14.3/node_modules/@grpc/grpc-js/build/src";
|
|
278763
278778
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
278764
278779
|
exports.registerChannelzSocket = exports.registerChannelzServer = exports.registerChannelzSubchannel = exports.registerChannelzChannel = exports.ChannelzCallTrackerStub = exports.ChannelzCallTracker = exports.ChannelzChildrenTrackerStub = exports.ChannelzChildrenTracker = exports.ChannelzTrace = exports.ChannelzTraceStub = undefined;
|
|
278765
278780
|
exports.unregisterChannelzRef = unregisterChannelzRef;
|
|
@@ -284162,7 +284177,7 @@ var require_duration = __commonJS((exports) => {
|
|
|
284162
284177
|
|
|
284163
284178
|
// ../../node_modules/.bun/@grpc+grpc-js@1.14.3/node_modules/@grpc/grpc-js/build/src/orca.js
|
|
284164
284179
|
var require_orca = __commonJS((exports) => {
|
|
284165
|
-
var __dirname = "/home/runner/work/omni/omni
|
|
284180
|
+
var __dirname = "/home/runner/work/omni/omni/node_modules/.bun/@grpc+grpc-js@1.14.3/node_modules/@grpc/grpc-js/build/src";
|
|
284166
284181
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
284167
284182
|
exports.OrcaOobMetricsSubchannelWrapper = exports.GRPC_METRICS_HEADER = exports.ServerMetricRecorder = exports.PerRequestMetricRecorder = undefined;
|
|
284168
284183
|
exports.createOrcaClient = createOrcaClient;
|
|
@@ -375841,6 +375856,9 @@ var init_ingress_idempotency = __esm(() => {
|
|
|
375841
375856
|
|
|
375842
375857
|
// ../api/src/services/webhooks.ts
|
|
375843
375858
|
import { createHmac as createHmac4, timingSafeEqual } from "crypto";
|
|
375859
|
+
function scopeTriggerKey(key, instanceId, tenantId) {
|
|
375860
|
+
return `manual:${instanceId ?? tenantId ?? "global"}:${key}`;
|
|
375861
|
+
}
|
|
375844
375862
|
function timingSafeEqualStrings(a, b3) {
|
|
375845
375863
|
const bufA = Buffer.from(a);
|
|
375846
375864
|
const bufB = Buffer.from(b3);
|
|
@@ -376011,7 +376029,7 @@ class WebhookService {
|
|
|
376011
376029
|
payload,
|
|
376012
376030
|
headers
|
|
376013
376031
|
});
|
|
376014
|
-
const
|
|
376032
|
+
const claim = await this.claimJournalRow({
|
|
376015
376033
|
id: eventId,
|
|
376016
376034
|
channel: "internal",
|
|
376017
376035
|
eventType,
|
|
@@ -376021,18 +376039,17 @@ class WebhookService {
|
|
|
376021
376039
|
idempotencyKey,
|
|
376022
376040
|
receivedAt: new Date,
|
|
376023
376041
|
metadata: { correlationId: eventId, source: "webhook", fullEventType: eventType, webhookSource: sourceName }
|
|
376024
|
-
})
|
|
376025
|
-
if (
|
|
376042
|
+
});
|
|
376043
|
+
if (claim.duplicate) {
|
|
376026
376044
|
await this.db.update(webhookSources).set({
|
|
376027
376045
|
totalDuplicates: sql`${webhookSources.totalDuplicates} + 1`,
|
|
376028
376046
|
updatedAt: new Date
|
|
376029
376047
|
}).where(eq(webhookSources.id, source.id));
|
|
376030
|
-
const [original] = await this.db.select({ id: omniEvents.id }).from(omniEvents).where(eq(omniEvents.idempotencyKey, idempotencyKey)).limit(1);
|
|
376031
376048
|
log114.info("Webhook redelivery acked without a second event", { sourceName, idempotencyKey });
|
|
376032
376049
|
return {
|
|
376033
376050
|
received: true,
|
|
376034
376051
|
duplicate: true,
|
|
376035
|
-
eventId:
|
|
376052
|
+
eventId: claim.eventId,
|
|
376036
376053
|
source: sourceName,
|
|
376037
376054
|
eventType
|
|
376038
376055
|
};
|
|
@@ -376067,6 +376084,14 @@ class WebhookService {
|
|
|
376067
376084
|
eventType
|
|
376068
376085
|
};
|
|
376069
376086
|
}
|
|
376087
|
+
async claimJournalRow(row) {
|
|
376088
|
+
const claimed = await this.db.insert(omniEvents).values(row).onConflictDoNothing({ target: omniEvents.idempotencyKey }).returning({ id: omniEvents.id });
|
|
376089
|
+
if (claimed.length > 0) {
|
|
376090
|
+
return { eventId: row.id, duplicate: false };
|
|
376091
|
+
}
|
|
376092
|
+
const [original] = await this.db.select({ id: omniEvents.id }).from(omniEvents).where(eq(omniEvents.idempotencyKey, row.idempotencyKey)).limit(1);
|
|
376093
|
+
return { eventId: original?.id ?? row.id, duplicate: true };
|
|
376094
|
+
}
|
|
376070
376095
|
verifySignature(source, rawBody, headers) {
|
|
376071
376096
|
const config4 = source.signatureConfig;
|
|
376072
376097
|
if (!config4)
|
|
@@ -376130,16 +376155,66 @@ class WebhookService {
|
|
|
376130
376155
|
async trigger(eventType, payload, metadata) {
|
|
376131
376156
|
const provisionalId = metadata?.correlationId ?? generateId();
|
|
376132
376157
|
await this.enforceRegisteredSchema(eventType, payload, provisionalId, "manual trigger");
|
|
376133
|
-
|
|
376134
|
-
|
|
376135
|
-
|
|
376136
|
-
|
|
376137
|
-
|
|
376158
|
+
const bus2 = this.eventBus;
|
|
376159
|
+
if (!bus2) {
|
|
376160
|
+
return { eventId: provisionalId, published: false };
|
|
376161
|
+
}
|
|
376162
|
+
const key = metadata?.idempotencyKey;
|
|
376163
|
+
if (key) {
|
|
376164
|
+
return this.triggerClaimed(bus2, eventType, payload, metadata ?? {}, key);
|
|
376165
|
+
}
|
|
376166
|
+
const result = await bus2.publishGeneric(eventType, payload, {
|
|
376167
|
+
correlationId: metadata?.correlationId,
|
|
376168
|
+
causationId: metadata?.causationId,
|
|
376169
|
+
instanceId: metadata?.instanceId,
|
|
376170
|
+
source: "manual-trigger"
|
|
376171
|
+
});
|
|
376172
|
+
return { eventId: result.id, published: true };
|
|
376173
|
+
}
|
|
376174
|
+
async triggerClaimed(bus2, eventType, payload, metadata, key) {
|
|
376175
|
+
const idempotencyKey = scopeTriggerKey(key, metadata.instanceId, this.tenantId);
|
|
376176
|
+
const eventId = generateId();
|
|
376177
|
+
const claim = await this.claimJournalRow({
|
|
376178
|
+
id: eventId,
|
|
376179
|
+
channel: "internal",
|
|
376180
|
+
eventType,
|
|
376181
|
+
direction: "internal",
|
|
376182
|
+
status: "completed",
|
|
376183
|
+
rawPayload: payload,
|
|
376184
|
+
idempotencyKey,
|
|
376185
|
+
causationId: metadata.causationId ?? null,
|
|
376186
|
+
receivedAt: new Date,
|
|
376187
|
+
metadata: {
|
|
376188
|
+
correlationId: metadata.correlationId ?? eventId,
|
|
376189
|
+
source: "manual-trigger",
|
|
376190
|
+
fullEventType: eventType,
|
|
376191
|
+
idempotencyKey
|
|
376192
|
+
}
|
|
376193
|
+
});
|
|
376194
|
+
if (claim.duplicate) {
|
|
376195
|
+
log114.info("Manual trigger deduped: idempotency key already journaled", { eventType, idempotencyKey });
|
|
376196
|
+
return { eventId: claim.eventId, published: false, duplicate: true };
|
|
376197
|
+
}
|
|
376198
|
+
try {
|
|
376199
|
+
await bus2.publishGeneric(eventType, payload, {
|
|
376200
|
+
correlationId: metadata.correlationId,
|
|
376201
|
+
causationId: metadata.causationId,
|
|
376202
|
+
instanceId: metadata.instanceId,
|
|
376203
|
+
publishEventId: eventId,
|
|
376138
376204
|
source: "manual-trigger"
|
|
376139
376205
|
});
|
|
376140
|
-
|
|
376206
|
+
} catch (error3) {
|
|
376207
|
+
await this.db.delete(omniEvents).where(eq(omniEvents.id, eventId)).catch((releaseError) => {
|
|
376208
|
+
log114.error("Failed to release trigger idempotency claim after publish failure", {
|
|
376209
|
+
eventType,
|
|
376210
|
+
eventId,
|
|
376211
|
+
idempotencyKey,
|
|
376212
|
+
error: String(releaseError)
|
|
376213
|
+
});
|
|
376214
|
+
});
|
|
376215
|
+
throw error3;
|
|
376141
376216
|
}
|
|
376142
|
-
return { eventId:
|
|
376217
|
+
return { eventId, published: true, duplicate: false };
|
|
376143
376218
|
}
|
|
376144
376219
|
async heartbeat(sourceName) {
|
|
376145
376220
|
const source = await this.getByName(sourceName);
|
|
@@ -379382,6 +379457,12 @@ var init_automations3 = __esm(() => {
|
|
|
379382
379457
|
transactionalEmissions: exports_external.boolean().openapi({
|
|
379383
379458
|
description: "Transactional publication (G5, #988): buffer the run's emit_event publishes and flush them in order " + "only when every action succeeded; a failed run publishes zero"
|
|
379384
379459
|
}),
|
|
379460
|
+
maxConcurrency: exports_external.number().int().nullable().openapi({
|
|
379461
|
+
description: "Per-automation concurrency limit (#1108). null = queued per instance with the engine default; " + "set = a queue private to this automation, 1 being strict single-flight"
|
|
379462
|
+
}),
|
|
379463
|
+
concurrencyKey: exports_external.string().nullable().openapi({
|
|
379464
|
+
description: "Template over the event payload partitioning this automation\u2019s queue (#1108), e.g. " + '"{{payload.from.id}}" to serialize per chat; null = one queue for the whole automation'
|
|
379465
|
+
}),
|
|
379385
379466
|
managedByAgentId: exports_external.string().uuid().nullable().openapi({
|
|
379386
379467
|
description: "Set when this automation was compiled from an agent event manifest (RFC #925 G4b, #986); " + "null = hand-made. Managed automations reject manual mutation \u2014 edit the owning agent\u2019s manifest instead"
|
|
379387
379468
|
}),
|
|
@@ -379400,6 +379481,12 @@ var init_automations3 = __esm(() => {
|
|
|
379400
379481
|
priority: exports_external.number().int().default(0).openapi({ description: "Priority" }),
|
|
379401
379482
|
transactionalEmissions: exports_external.boolean().default(false).openapi({
|
|
379402
379483
|
description: "Transactional publication (G5, #988): buffer the run's emit_event publishes and flush them in order " + "only when every action succeeded; a failed run publishes zero. Default false = immediate publishing"
|
|
379484
|
+
}),
|
|
379485
|
+
maxConcurrency: exports_external.number().int().min(1).nullable().optional().openapi({
|
|
379486
|
+
description: "Per-automation concurrency limit (#1108). Omit/null = today\u2019s per-instance queueing with the engine " + "default; 1 = strict single-flight, which is what a read-before-write action needs"
|
|
379487
|
+
}),
|
|
379488
|
+
concurrencyKey: exports_external.string().min(1).nullable().optional().openapi({
|
|
379489
|
+
description: "Template over the event payload partitioning this automation\u2019s queue (#1108), e.g. " + '"{{payload.from.id}}" to serialize per chat; omit/null = one queue for the whole automation'
|
|
379403
379490
|
})
|
|
379404
379491
|
});
|
|
379405
379492
|
AutomationLogSchema = exports_external.object({
|
|
@@ -379445,7 +379532,9 @@ var init_automations3 = __esm(() => {
|
|
|
379445
379532
|
AutomationMetricsSchema = exports_external.object({
|
|
379446
379533
|
running: exports_external.boolean().openapi({ description: "Engine running" }),
|
|
379447
379534
|
instanceQueues: exports_external.array(exports_external.object({
|
|
379448
|
-
instanceId: exports_external.string().openapi({
|
|
379535
|
+
instanceId: exports_external.string().openapi({
|
|
379536
|
+
description: 'Queue key: the instance ID, or "<instanceId>:<automationId>[:<partition>]" for an automation ' + "running on its own queue (#1108)"
|
|
379537
|
+
}),
|
|
379449
379538
|
activeCount: exports_external.number().int().openapi({ description: "Active jobs" }),
|
|
379450
379539
|
pendingCount: exports_external.number().int().openapi({ description: "Pending jobs" })
|
|
379451
379540
|
})).optional().openapi({ description: "Instance queue stats" }),
|
|
@@ -383516,7 +383605,10 @@ var init_webhooks2 = __esm(() => {
|
|
|
383516
383605
|
payload: exports_external.record(exports_external.string(), exports_external.unknown()).openapi({ description: "Event payload" }),
|
|
383517
383606
|
correlationId: exports_external.string().optional().openapi({ description: "Correlation ID" }),
|
|
383518
383607
|
causationId: exports_external.string().uuid().optional().openapi({ description: "Parent event ID; stamps causationId so the emission is parented in the causality tree" }),
|
|
383519
|
-
instanceId: exports_external.string().uuid().optional().openapi({ description: "Instance ID for context" })
|
|
383608
|
+
instanceId: exports_external.string().uuid().optional().openapi({ description: "Instance ID for context" }),
|
|
383609
|
+
idempotencyKey: exports_external.string().min(1).max(255).optional().openapi({
|
|
383610
|
+
description: "Producer-supplied ingress key (#1109). Unique per instance (else per tenant), not global. A key already journaled publishes nothing and returns the ORIGINAL event id with duplicate: true. Omit for undeduped publishing."
|
|
383611
|
+
})
|
|
383520
383612
|
});
|
|
383521
383613
|
WebhookReceiveResponseSchema = exports_external.object({
|
|
383522
383614
|
eventId: exports_external.string().uuid().openapi({ description: "Created event ID (the ORIGINAL event on a duplicate)" }),
|
|
@@ -385197,7 +385289,9 @@ var init_automations4 = __esm(() => {
|
|
|
385197
385289
|
debounce: debounceSchema.optional().describe("Message debounce configuration"),
|
|
385198
385290
|
enabled: exports_external.boolean().default(true).describe("Whether automation is enabled"),
|
|
385199
385291
|
priority: exports_external.number().int().default(0).describe("Priority (higher runs first)"),
|
|
385200
|
-
transactionalEmissions: exports_external.boolean().default(false).describe("Transactional publication (G5, #988): buffer the run's emit_event publishes and flush them in order " + "only when every action succeeded; a failed run publishes zero. Default false = immediate publishing")
|
|
385292
|
+
transactionalEmissions: exports_external.boolean().default(false).describe("Transactional publication (G5, #988): buffer the run's emit_event publishes and flush them in order " + "only when every action succeeded; a failed run publishes zero. Default false = immediate publishing"),
|
|
385293
|
+
maxConcurrency: exports_external.number().int().min(1).nullable().optional().describe("Per-automation concurrency limit (#1108). Omit/null = today\u2019s per-instance queueing with the engine " + "default; 1 = strict single-flight, which is what a read-before-write action needs"),
|
|
385294
|
+
concurrencyKey: exports_external.string().min(1).nullable().optional().describe("Template over the event payload partitioning this automation\u2019s queue (#1108), e.g. " + '"{{payload.from.id}}" to serialize per chat; omit/null = one queue for the whole automation')
|
|
385201
385295
|
});
|
|
385202
385296
|
updateAutomationSchema = createAutomationSchema.partial();
|
|
385203
385297
|
listQuerySchema5 = exports_external.object({
|
|
@@ -396325,10 +396419,11 @@ var init_webhooks3 = __esm(() => {
|
|
|
396325
396419
|
payload: exports_external.record(exports_external.string(), exports_external.unknown()).describe("Event payload"),
|
|
396326
396420
|
correlationId: exports_external.string().optional().describe("Optional correlation ID"),
|
|
396327
396421
|
causationId: exports_external.string().uuid().optional().describe("Optional parent event ID (causality tree, #1072)"),
|
|
396328
|
-
instanceId: exports_external.string().uuid().optional().describe("Optional instance ID for context")
|
|
396422
|
+
instanceId: exports_external.string().uuid().optional().describe("Optional instance ID for context"),
|
|
396423
|
+
idempotencyKey: exports_external.string().min(1).max(255).optional().describe("Optional producer-supplied ingress key; a key already journaled returns the original event (#1109)")
|
|
396329
396424
|
});
|
|
396330
396425
|
webhooksRoutes.post("/events/trigger", zValidator("json", triggerEventSchema), async (c) => {
|
|
396331
|
-
const { eventType, payload, correlationId, causationId, instanceId } = c.req.valid("json");
|
|
396426
|
+
const { eventType, payload, correlationId, causationId, instanceId, idempotencyKey } = c.req.valid("json");
|
|
396332
396427
|
const services = c.get("services");
|
|
396333
396428
|
const apiKey = c.get("apiKey");
|
|
396334
396429
|
if (instanceId && apiKey && !ApiKeyService.instanceAllowed(apiKey.instanceIds, instanceId)) {
|
|
@@ -396337,7 +396432,8 @@ var init_webhooks3 = __esm(() => {
|
|
|
396337
396432
|
const result = await services.webhooks.trigger(eventType, payload, {
|
|
396338
396433
|
correlationId,
|
|
396339
396434
|
causationId,
|
|
396340
|
-
instanceId
|
|
396435
|
+
instanceId,
|
|
396436
|
+
idempotencyKey
|
|
396341
396437
|
});
|
|
396342
396438
|
return c.json(result, 201);
|
|
396343
396439
|
});
|