@pattern-stack/codegen 0.4.4 → 0.4.6
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/dist/runtime/subsystems/index.d.ts +7 -0
- package/dist/runtime/subsystems/index.js +923 -208
- package/dist/runtime/subsystems/index.js.map +1 -1
- package/dist/runtime/subsystems/observability/index.d.ts +10 -0
- package/dist/runtime/subsystems/observability/index.js +913 -0
- package/dist/runtime/subsystems/observability/index.js.map +1 -0
- package/dist/runtime/subsystems/observability/observability.drizzle-backend.d.ts +15 -0
- package/dist/runtime/subsystems/observability/observability.drizzle-backend.js +465 -0
- package/dist/runtime/subsystems/observability/observability.drizzle-backend.js.map +1 -0
- package/dist/runtime/subsystems/observability/observability.memory-backend.d.ts +28 -0
- package/dist/runtime/subsystems/observability/observability.memory-backend.js +75 -0
- package/dist/runtime/subsystems/observability/observability.memory-backend.js.map +1 -0
- package/dist/runtime/subsystems/observability/observability.module.d.ts +56 -0
- package/dist/runtime/subsystems/observability/observability.module.js +905 -0
- package/dist/runtime/subsystems/observability/observability.module.js.map +1 -0
- package/dist/runtime/subsystems/observability/observability.protocol.d.ts +155 -0
- package/dist/runtime/subsystems/observability/observability.protocol.js +1 -0
- package/dist/runtime/subsystems/observability/observability.protocol.js.map +1 -0
- package/dist/runtime/subsystems/observability/observability.tokens.d.ts +19 -0
- package/dist/runtime/subsystems/observability/observability.tokens.js +8 -0
- package/dist/runtime/subsystems/observability/observability.tokens.js.map +1 -0
- package/dist/runtime/subsystems/observability/reporters/bridge-metrics.reporter.d.ts +87 -0
- package/dist/runtime/subsystems/observability/reporters/bridge-metrics.reporter.js +443 -0
- package/dist/runtime/subsystems/observability/reporters/bridge-metrics.reporter.js.map +1 -0
- package/dist/runtime/subsystems/sync/sync-audit.schema.d.ts +4 -4
- package/package.json +6 -1
- package/runtime/subsystems/index.ts +23 -0
- package/runtime/subsystems/observability/index.ts +35 -0
- package/runtime/subsystems/observability/observability.drizzle-backend.ts +223 -0
- package/runtime/subsystems/observability/observability.memory-backend.ts +111 -0
- package/runtime/subsystems/observability/observability.module.ts +115 -0
- package/runtime/subsystems/observability/observability.protocol.ts +167 -0
- package/runtime/subsystems/observability/observability.tokens.ts +18 -0
- package/runtime/subsystems/observability/reporters/bridge-metrics.reporter.ts +242 -0
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
6
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
7
|
+
}) : x)(function(x) {
|
|
8
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
9
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
10
|
+
});
|
|
11
|
+
var __esm = (fn, res) => function __init() {
|
|
12
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
13
|
+
};
|
|
14
|
+
var __export = (target, all) => {
|
|
15
|
+
for (var name in all)
|
|
16
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
17
|
+
};
|
|
18
|
+
var __copyProps = (to, from, except, desc5) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
+
for (let key of __getOwnPropNames(from))
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
22
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc5 = __getOwnPropDesc(from, key)) || desc5.enumerable });
|
|
23
|
+
}
|
|
24
|
+
return to;
|
|
25
|
+
};
|
|
26
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
3
27
|
var __decorateClass = (decorators, target, key, kind) => {
|
|
4
28
|
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
5
29
|
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
@@ -8,7 +32,470 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
8
32
|
if (kind && result) __defProp(target, key, result);
|
|
9
33
|
return result;
|
|
10
34
|
};
|
|
11
|
-
var __decorateParam = (
|
|
35
|
+
var __decorateParam = (index5, decorator) => (target, key) => decorator(target, key, index5);
|
|
36
|
+
|
|
37
|
+
// runtime/constants/tokens.ts
|
|
38
|
+
var DRIZZLE;
|
|
39
|
+
var init_tokens = __esm({
|
|
40
|
+
"runtime/constants/tokens.ts"() {
|
|
41
|
+
"use strict";
|
|
42
|
+
DRIZZLE = "DRIZZLE";
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// runtime/subsystems/events/domain-events.schema.ts
|
|
47
|
+
import {
|
|
48
|
+
index,
|
|
49
|
+
jsonb,
|
|
50
|
+
pgTable,
|
|
51
|
+
text,
|
|
52
|
+
timestamp,
|
|
53
|
+
uuid
|
|
54
|
+
} from "drizzle-orm/pg-core";
|
|
55
|
+
var domainEvents;
|
|
56
|
+
var init_domain_events_schema = __esm({
|
|
57
|
+
"runtime/subsystems/events/domain-events.schema.ts"() {
|
|
58
|
+
"use strict";
|
|
59
|
+
domainEvents = pgTable(
|
|
60
|
+
"domain_events",
|
|
61
|
+
{
|
|
62
|
+
id: uuid("id").primaryKey(),
|
|
63
|
+
type: text("type").notNull(),
|
|
64
|
+
aggregateId: text("aggregate_id").notNull(),
|
|
65
|
+
aggregateType: text("aggregate_type").notNull(),
|
|
66
|
+
payload: jsonb("payload").notNull().$type(),
|
|
67
|
+
occurredAt: timestamp("occurred_at", { withTimezone: true }).notNull(),
|
|
68
|
+
processedAt: timestamp("processed_at", { withTimezone: true }),
|
|
69
|
+
/** Lifecycle status: pending | processed | failed */
|
|
70
|
+
status: text("status").notNull().default("pending"),
|
|
71
|
+
/** Error message from the last failed dispatch attempt. */
|
|
72
|
+
error: text("error"),
|
|
73
|
+
metadata: jsonb("metadata").$type(),
|
|
74
|
+
/** Routing pool (e.g. `events_inbound`, `events_change`, `events_outbound`). Populated by DrizzleEventBus.publish() in EVT-4. */
|
|
75
|
+
pool: text("pool"),
|
|
76
|
+
/** Routing direction: `inbound` | `change` | `outbound`. Populated by DrizzleEventBus.publish() in EVT-4. */
|
|
77
|
+
direction: text("direction"),
|
|
78
|
+
// conditional: emitted only when events.multi_tenant: true
|
|
79
|
+
tenantId: text("tenant_id")
|
|
80
|
+
},
|
|
81
|
+
(t) => ({
|
|
82
|
+
/** Polling drain filter (existing — promoted from comment to declaration in EVT-1). */
|
|
83
|
+
idxDomainEventsStatusOccurredAt: index("idx_domain_events_status_occurred_at").on(
|
|
84
|
+
t.status,
|
|
85
|
+
t.occurredAt
|
|
86
|
+
),
|
|
87
|
+
/** Event replay per aggregate (existing — promoted from comment to declaration in EVT-1). */
|
|
88
|
+
idxDomainEventsAggregate: index("idx_domain_events_aggregate").on(
|
|
89
|
+
t.aggregateId,
|
|
90
|
+
t.aggregateType
|
|
91
|
+
),
|
|
92
|
+
/** Per-pool drain filter (EVT-1). Enables DrizzleEventBus to drain a single pool without scanning all events. */
|
|
93
|
+
idxDomainEventsPoolStatusOccurredAt: index(
|
|
94
|
+
"idx_domain_events_pool_status_occurred_at"
|
|
95
|
+
).on(t.pool, t.status, t.occurredAt)
|
|
96
|
+
})
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// runtime/subsystems/jobs/job-orchestration.schema.ts
|
|
102
|
+
import {
|
|
103
|
+
pgEnum,
|
|
104
|
+
pgTable as pgTable2,
|
|
105
|
+
uuid as uuid2,
|
|
106
|
+
text as text2,
|
|
107
|
+
jsonb as jsonb2,
|
|
108
|
+
integer,
|
|
109
|
+
timestamp as timestamp2,
|
|
110
|
+
index as index2,
|
|
111
|
+
uniqueIndex
|
|
112
|
+
} from "drizzle-orm/pg-core";
|
|
113
|
+
import { sql } from "drizzle-orm";
|
|
114
|
+
var jobRunStatusEnum, jobStepKindEnum, jobStepStatusEnum, collisionModeEnum, replayFromEnum, parentClosePolicyEnum, waitKindEnum, triggerSourceEnum, jobs, jobRuns, jobSteps;
|
|
115
|
+
var init_job_orchestration_schema = __esm({
|
|
116
|
+
"runtime/subsystems/jobs/job-orchestration.schema.ts"() {
|
|
117
|
+
"use strict";
|
|
118
|
+
jobRunStatusEnum = pgEnum("job_run_status", [
|
|
119
|
+
"pending",
|
|
120
|
+
"running",
|
|
121
|
+
"waiting",
|
|
122
|
+
"completed",
|
|
123
|
+
"failed",
|
|
124
|
+
"timed_out",
|
|
125
|
+
"canceled"
|
|
126
|
+
]);
|
|
127
|
+
jobStepKindEnum = pgEnum("job_step_kind", ["task"]);
|
|
128
|
+
jobStepStatusEnum = pgEnum("job_step_status", [
|
|
129
|
+
"pending",
|
|
130
|
+
"running",
|
|
131
|
+
"completed",
|
|
132
|
+
"failed",
|
|
133
|
+
"skipped"
|
|
134
|
+
]);
|
|
135
|
+
collisionModeEnum = pgEnum("job_collision_mode", [
|
|
136
|
+
"queue",
|
|
137
|
+
"reject",
|
|
138
|
+
"replace"
|
|
139
|
+
]);
|
|
140
|
+
replayFromEnum = pgEnum("job_replay_from", [
|
|
141
|
+
"scratch",
|
|
142
|
+
"last_step",
|
|
143
|
+
"last_checkpoint"
|
|
144
|
+
]);
|
|
145
|
+
parentClosePolicyEnum = pgEnum("job_parent_close_policy", [
|
|
146
|
+
"terminate",
|
|
147
|
+
"cancel",
|
|
148
|
+
"abandon"
|
|
149
|
+
]);
|
|
150
|
+
waitKindEnum = pgEnum("job_wait_kind", ["signal"]);
|
|
151
|
+
triggerSourceEnum = pgEnum("job_trigger_source", [
|
|
152
|
+
"manual",
|
|
153
|
+
"schedule",
|
|
154
|
+
"event",
|
|
155
|
+
"parent"
|
|
156
|
+
]);
|
|
157
|
+
jobs = pgTable2("job", {
|
|
158
|
+
type: text2("type").primaryKey(),
|
|
159
|
+
version: integer("version").notNull().default(1),
|
|
160
|
+
pool: text2("pool").notNull(),
|
|
161
|
+
scopeEntityType: text2("scope_entity_type"),
|
|
162
|
+
retryPolicy: jsonb2("retry_policy").notNull().$type(),
|
|
163
|
+
timeoutMs: integer("timeout_ms"),
|
|
164
|
+
concurrencyKeyTemplate: text2("concurrency_key_template"),
|
|
165
|
+
collisionMode: collisionModeEnum("collision_mode").notNull().default("queue"),
|
|
166
|
+
dedupeKeyTemplate: text2("dedupe_key_template"),
|
|
167
|
+
dedupeWindowMs: integer("dedupe_window_ms"),
|
|
168
|
+
priorityDefault: integer("priority_default").notNull().default(0),
|
|
169
|
+
replayFrom: replayFromEnum("replay_from").notNull().default("last_checkpoint"),
|
|
170
|
+
createdAt: timestamp2("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
171
|
+
updatedAt: timestamp2("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
172
|
+
});
|
|
173
|
+
jobRuns = pgTable2(
|
|
174
|
+
"job_run",
|
|
175
|
+
{
|
|
176
|
+
id: uuid2("id").primaryKey().defaultRandom(),
|
|
177
|
+
jobType: text2("job_type").notNull().references(() => jobs.type),
|
|
178
|
+
jobVersion: integer("job_version").notNull(),
|
|
179
|
+
parentRunId: uuid2("parent_run_id").references(() => jobRuns.id),
|
|
180
|
+
/**
|
|
181
|
+
* Service generates `id` client-side via randomUUID() and sets
|
|
182
|
+
* root_run_id = id for root runs (single INSERT, no self-FK race).
|
|
183
|
+
*/
|
|
184
|
+
rootRunId: uuid2("root_run_id").notNull(),
|
|
185
|
+
parentClosePolicy: parentClosePolicyEnum("parent_close_policy").notNull().default("terminate"),
|
|
186
|
+
scopeEntityType: text2("scope_entity_type"),
|
|
187
|
+
scopeEntityId: text2("scope_entity_id"),
|
|
188
|
+
tenantId: text2("tenant_id"),
|
|
189
|
+
tags: jsonb2("tags").notNull().default({}).$type(),
|
|
190
|
+
pool: text2("pool").notNull(),
|
|
191
|
+
priority: integer("priority").notNull().default(0),
|
|
192
|
+
concurrencyKey: text2("concurrency_key"),
|
|
193
|
+
dedupeKey: text2("dedupe_key"),
|
|
194
|
+
status: jobRunStatusEnum("status").notNull().default("pending"),
|
|
195
|
+
input: jsonb2("input").notNull().$type(),
|
|
196
|
+
output: jsonb2("output").$type(),
|
|
197
|
+
error: jsonb2("error").$type(),
|
|
198
|
+
triggerSource: triggerSourceEnum("trigger_source").notNull(),
|
|
199
|
+
triggerRef: text2("trigger_ref"),
|
|
200
|
+
runAt: timestamp2("run_at", { withTimezone: true }).notNull().defaultNow(),
|
|
201
|
+
startedAt: timestamp2("started_at", { withTimezone: true }),
|
|
202
|
+
finishedAt: timestamp2("finished_at", { withTimezone: true }),
|
|
203
|
+
claimedAt: timestamp2("claimed_at", { withTimezone: true }),
|
|
204
|
+
attempts: integer("attempts").notNull().default(0),
|
|
205
|
+
// Phase 3 placeholder — see ADR-025
|
|
206
|
+
waitKind: waitKindEnum("wait_kind"),
|
|
207
|
+
// Phase 3 placeholder — see ADR-025
|
|
208
|
+
resumeToken: text2("resume_token"),
|
|
209
|
+
// Phase 3 placeholder — see ADR-025
|
|
210
|
+
waitDeadline: timestamp2("wait_deadline", { withTimezone: true }),
|
|
211
|
+
createdAt: timestamp2("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
212
|
+
updatedAt: timestamp2("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
213
|
+
},
|
|
214
|
+
(t) => ({
|
|
215
|
+
/** Claim query: ORDER BY priority DESC, run_at ASC. */
|
|
216
|
+
idxJobRunClaim: index2("idx_job_run_claim").on(t.status, t.pool, t.runAt),
|
|
217
|
+
/** Tree traversal / cascade cancel. */
|
|
218
|
+
idxJobRunRoot: index2("idx_job_run_root").on(t.rootRunId),
|
|
219
|
+
/** listForScope query. */
|
|
220
|
+
idxJobRunScope: index2("idx_job_run_scope").on(t.scopeEntityType, t.scopeEntityId),
|
|
221
|
+
/** Idempotency collapse — partial index. */
|
|
222
|
+
idxJobRunDedupe: index2("idx_job_run_dedupe").on(t.jobType, t.dedupeKey).where(sql`${t.dedupeKey} IS NOT NULL`),
|
|
223
|
+
/** Collision check — partial index. */
|
|
224
|
+
idxJobRunConcurrency: index2("idx_job_run_concurrency").on(t.concurrencyKey).where(
|
|
225
|
+
sql`${t.concurrencyKey} IS NOT NULL AND ${t.status} IN ('pending','running')`
|
|
226
|
+
)
|
|
227
|
+
})
|
|
228
|
+
);
|
|
229
|
+
jobSteps = pgTable2(
|
|
230
|
+
"job_step",
|
|
231
|
+
{
|
|
232
|
+
id: uuid2("id").primaryKey().defaultRandom(),
|
|
233
|
+
jobRunId: uuid2("job_run_id").notNull().references(() => jobRuns.id),
|
|
234
|
+
stepId: text2("step_id").notNull(),
|
|
235
|
+
kind: jobStepKindEnum("kind").notNull().default("task"),
|
|
236
|
+
/**
|
|
237
|
+
* Monotonic within run. integer (max ~2B per run) is sufficient —
|
|
238
|
+
* downgraded from ADR-022's bigint; revisit only if a single run
|
|
239
|
+
* ever exceeds 2 billion steps.
|
|
240
|
+
*/
|
|
241
|
+
seq: integer("seq").notNull(),
|
|
242
|
+
status: jobStepStatusEnum("status").notNull().default("pending"),
|
|
243
|
+
input: jsonb2("input").$type(),
|
|
244
|
+
/** Memoised on success for replay. */
|
|
245
|
+
output: jsonb2("output").$type(),
|
|
246
|
+
error: jsonb2("error").$type(),
|
|
247
|
+
attempts: integer("attempts").notNull().default(0),
|
|
248
|
+
startedAt: timestamp2("started_at", { withTimezone: true }),
|
|
249
|
+
finishedAt: timestamp2("finished_at", { withTimezone: true })
|
|
250
|
+
},
|
|
251
|
+
(t) => ({
|
|
252
|
+
/** No duplicate step IDs per run. */
|
|
253
|
+
idxJobStepRunStep: uniqueIndex("idx_job_step_run_step").on(t.jobRunId, t.stepId),
|
|
254
|
+
/** Ordered timeline reads. */
|
|
255
|
+
idxJobStepTimeline: index2("idx_job_step_timeline").on(t.jobRunId, t.seq)
|
|
256
|
+
})
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// runtime/subsystems/bridge/bridge-delivery.schema.ts
|
|
262
|
+
import {
|
|
263
|
+
index as index4,
|
|
264
|
+
jsonb as jsonb5,
|
|
265
|
+
pgEnum as pgEnum3,
|
|
266
|
+
pgTable as pgTable5,
|
|
267
|
+
text as text5,
|
|
268
|
+
timestamp as timestamp5,
|
|
269
|
+
unique,
|
|
270
|
+
uuid as uuid4
|
|
271
|
+
} from "drizzle-orm/pg-core";
|
|
272
|
+
import { sql as sql6 } from "drizzle-orm";
|
|
273
|
+
var bridgeDeliveryStatusEnum, bridgeDelivery;
|
|
274
|
+
var init_bridge_delivery_schema = __esm({
|
|
275
|
+
"runtime/subsystems/bridge/bridge-delivery.schema.ts"() {
|
|
276
|
+
"use strict";
|
|
277
|
+
init_domain_events_schema();
|
|
278
|
+
init_job_orchestration_schema();
|
|
279
|
+
bridgeDeliveryStatusEnum = pgEnum3("bridge_delivery_status", [
|
|
280
|
+
"pending",
|
|
281
|
+
"delivered",
|
|
282
|
+
"skipped",
|
|
283
|
+
"failed"
|
|
284
|
+
]);
|
|
285
|
+
bridgeDelivery = pgTable5(
|
|
286
|
+
"bridge_delivery",
|
|
287
|
+
{
|
|
288
|
+
id: uuid4("id").primaryKey().defaultRandom(),
|
|
289
|
+
/** FK to the source event in the outbox. */
|
|
290
|
+
eventId: uuid4("event_id").notNull().references(() => domainEvents.id),
|
|
291
|
+
/**
|
|
292
|
+
* Stable codegen-emitted identifier for the (job, trigger) pair, of the
|
|
293
|
+
* form `<job_type>#<triggerIndex>` (BRIDGE-6). Forms the second half of
|
|
294
|
+
* the UNIQUE idempotency key.
|
|
295
|
+
*/
|
|
296
|
+
triggerId: text5("trigger_id").notNull(),
|
|
297
|
+
/**
|
|
298
|
+
* Wrapper `job_run.id` (the framework `@framework/bridge_delivery` run
|
|
299
|
+
* that drove this delivery). Nullable: the facade-eager path
|
|
300
|
+
* (`publishAndStart` Case B) pre-writes a delivered row with no wrapper.
|
|
301
|
+
*/
|
|
302
|
+
wrapperRunId: uuid4("wrapper_run_id").references(() => jobRuns.id),
|
|
303
|
+
/**
|
|
304
|
+
* Spawned user `job_run.id`. Null until status is `delivered`; remains
|
|
305
|
+
* null for `skipped` and `failed` deliveries.
|
|
306
|
+
*/
|
|
307
|
+
userRunId: uuid4("user_run_id").references(() => jobRuns.id),
|
|
308
|
+
status: bridgeDeliveryStatusEnum("status").notNull().default("pending"),
|
|
309
|
+
/** Populated when status=`skipped` (e.g. `'when_returned_false'`, `'trigger_unregistered'`). */
|
|
310
|
+
skipReason: text5("skip_reason"),
|
|
311
|
+
/** Populated when status=`failed`. Mirrors `job_run.error` shape. */
|
|
312
|
+
error: jsonb5("error").$type(),
|
|
313
|
+
/**
|
|
314
|
+
* Emitted unconditionally and nullable (JOB-8 / SYNC-6 precedent).
|
|
315
|
+
* Enforcement gated on `BRIDGE_MULTI_TENANT` at the service layer
|
|
316
|
+
* (BRIDGE-8); no DB constraint.
|
|
317
|
+
*/
|
|
318
|
+
tenantId: text5("tenant_id"),
|
|
319
|
+
attemptedAt: timestamp5("attempted_at", { withTimezone: true }).notNull().defaultNow(),
|
|
320
|
+
deliveredAt: timestamp5("delivered_at", { withTimezone: true })
|
|
321
|
+
},
|
|
322
|
+
(t) => ({
|
|
323
|
+
/**
|
|
324
|
+
* Idempotency ledger. Outbox replays and facade-vs-drain collisions both
|
|
325
|
+
* dedup through this constraint.
|
|
326
|
+
*/
|
|
327
|
+
uqBridgeDeliveryEventTrigger: unique("uq_bridge_delivery_event_trigger").on(
|
|
328
|
+
t.eventId,
|
|
329
|
+
t.triggerId
|
|
330
|
+
),
|
|
331
|
+
/** Lookup all deliveries for an event (fanout report, debugging). */
|
|
332
|
+
idxBridgeDeliveryEvent: index4("idx_bridge_delivery_event").on(t.eventId),
|
|
333
|
+
/**
|
|
334
|
+
* Ops dashboard filter — only the actionable states. Partial index keeps
|
|
335
|
+
* it small at scale (the bulk of rows will be `delivered`).
|
|
336
|
+
*/
|
|
337
|
+
idxBridgeDeliveryStatus: index4("idx_bridge_delivery_status").on(t.status).where(sql6`${t.status} IN ('pending','failed')`),
|
|
338
|
+
/**
|
|
339
|
+
* Reverse lookup from a spawned user run back to its delivery row.
|
|
340
|
+
* Partial — most rows in the bridge ledger but only successful
|
|
341
|
+
* deliveries have a `user_run_id`.
|
|
342
|
+
*/
|
|
343
|
+
idxBridgeDeliveryUserRun: index4("idx_bridge_delivery_user_run").on(t.userRunId).where(sql6`${t.userRunId} IS NOT NULL`)
|
|
344
|
+
})
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
// runtime/subsystems/observability/reporters/bridge-metrics.reporter.ts
|
|
350
|
+
var bridge_metrics_reporter_exports = {};
|
|
351
|
+
__export(bridge_metrics_reporter_exports, {
|
|
352
|
+
BridgeMetricsReporter: () => BridgeMetricsReporter
|
|
353
|
+
});
|
|
354
|
+
import {
|
|
355
|
+
Inject as Inject15,
|
|
356
|
+
Injectable as Injectable17,
|
|
357
|
+
Logger as Logger8,
|
|
358
|
+
Optional as Optional7
|
|
359
|
+
} from "@nestjs/common";
|
|
360
|
+
import { and as and6, eq as eq8, gt as gt3, sql as sql7 } from "drizzle-orm";
|
|
361
|
+
var INTERVAL_NAME, DEFAULT_INTERVAL_MS, MIN_INTERVAL_MS, BridgeMetricsReporter;
|
|
362
|
+
var init_bridge_metrics_reporter = __esm({
|
|
363
|
+
"runtime/subsystems/observability/reporters/bridge-metrics.reporter.ts"() {
|
|
364
|
+
"use strict";
|
|
365
|
+
init_tokens();
|
|
366
|
+
init_bridge_delivery_schema();
|
|
367
|
+
init_domain_events_schema();
|
|
368
|
+
INTERVAL_NAME = "bridge-metrics-tick";
|
|
369
|
+
DEFAULT_INTERVAL_MS = 6e4;
|
|
370
|
+
MIN_INTERVAL_MS = 1e3;
|
|
371
|
+
BridgeMetricsReporter = class {
|
|
372
|
+
constructor(db, scheduler = null) {
|
|
373
|
+
this.db = db;
|
|
374
|
+
this.scheduler = scheduler;
|
|
375
|
+
this.intervalMs = this.resolveIntervalMs();
|
|
376
|
+
this.lastTickAt = /* @__PURE__ */ new Date();
|
|
377
|
+
}
|
|
378
|
+
db;
|
|
379
|
+
scheduler;
|
|
380
|
+
logger = new Logger8(BridgeMetricsReporter.name);
|
|
381
|
+
intervalMs;
|
|
382
|
+
lastTickAt;
|
|
383
|
+
/**
|
|
384
|
+
* Timer handle retained as a field when `SchedulerRegistry` isn't
|
|
385
|
+
* available (optional dep). `SchedulerRegistry` is the Nest-idiomatic
|
|
386
|
+
* home for interval cleanup, but global-module wiring across consumer
|
|
387
|
+
* topologies doesn't always make it injectable here — the fallback
|
|
388
|
+
* keeps the reporter self-sufficient.
|
|
389
|
+
*/
|
|
390
|
+
ownedTimer = null;
|
|
391
|
+
onModuleInit() {
|
|
392
|
+
this.logger.log(
|
|
393
|
+
`BridgeMetricsReporter starting (intervalMs=${this.intervalMs}).`
|
|
394
|
+
);
|
|
395
|
+
const timer = setInterval(() => {
|
|
396
|
+
void this.tick();
|
|
397
|
+
}, this.intervalMs);
|
|
398
|
+
timer.unref?.();
|
|
399
|
+
if (this.scheduler) {
|
|
400
|
+
this.scheduler.addInterval(INTERVAL_NAME, timer);
|
|
401
|
+
} else {
|
|
402
|
+
this.ownedTimer = timer;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
onModuleDestroy() {
|
|
406
|
+
if (this.scheduler && this.scheduler.getIntervals().includes(INTERVAL_NAME)) {
|
|
407
|
+
this.scheduler.deleteInterval(INTERVAL_NAME);
|
|
408
|
+
}
|
|
409
|
+
if (this.ownedTimer !== null) {
|
|
410
|
+
clearInterval(this.ownedTimer);
|
|
411
|
+
this.ownedTimer = null;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Run one sampling tick. Public so tests can drive it deterministically
|
|
416
|
+
* without waiting on the timer.
|
|
417
|
+
*/
|
|
418
|
+
async tick() {
|
|
419
|
+
const windowStart = this.lastTickAt;
|
|
420
|
+
const windowEnd = /* @__PURE__ */ new Date();
|
|
421
|
+
this.lastTickAt = windowEnd;
|
|
422
|
+
let rows = [];
|
|
423
|
+
try {
|
|
424
|
+
rows = await this.sample(windowStart, windowEnd);
|
|
425
|
+
} catch (err) {
|
|
426
|
+
this.logger.error(
|
|
427
|
+
`bridge metrics sample failed: ${err.message}`
|
|
428
|
+
);
|
|
429
|
+
return { windowStart, windowEnd, rows: [] };
|
|
430
|
+
}
|
|
431
|
+
this.emit({ windowStart, windowEnd, rows });
|
|
432
|
+
return { windowStart, windowEnd, rows };
|
|
433
|
+
}
|
|
434
|
+
async sample(windowStart, windowEnd) {
|
|
435
|
+
const lastTransition = sql7`COALESCE(${bridgeDelivery.deliveredAt}, ${bridgeDelivery.attemptedAt})`;
|
|
436
|
+
const result = await this.db.select({
|
|
437
|
+
status: bridgeDelivery.status,
|
|
438
|
+
eventType: domainEvents.type,
|
|
439
|
+
skipReason: bridgeDelivery.skipReason,
|
|
440
|
+
count: sql7`COUNT(*)::int`
|
|
441
|
+
}).from(bridgeDelivery).innerJoin(domainEvents, eq8(bridgeDelivery.eventId, domainEvents.id)).where(
|
|
442
|
+
and6(
|
|
443
|
+
gt3(lastTransition, windowStart),
|
|
444
|
+
sql7`${lastTransition} <= ${windowEnd}`
|
|
445
|
+
)
|
|
446
|
+
).groupBy(
|
|
447
|
+
bridgeDelivery.status,
|
|
448
|
+
domainEvents.type,
|
|
449
|
+
bridgeDelivery.skipReason
|
|
450
|
+
);
|
|
451
|
+
return result.map((r) => ({
|
|
452
|
+
status: r.status,
|
|
453
|
+
eventType: r.eventType,
|
|
454
|
+
skipReason: r.skipReason,
|
|
455
|
+
count: r.count
|
|
456
|
+
}));
|
|
457
|
+
}
|
|
458
|
+
emit(tick) {
|
|
459
|
+
if (tick.rows.length === 0) {
|
|
460
|
+
this.logger.log(
|
|
461
|
+
`bridge_metrics tick=empty window=[${tick.windowStart.toISOString()}..${tick.windowEnd.toISOString()}]`
|
|
462
|
+
);
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
const totals = tick.rows.reduce(
|
|
466
|
+
(acc, r) => {
|
|
467
|
+
acc[r.status] = (acc[r.status] ?? 0) + r.count;
|
|
468
|
+
return acc;
|
|
469
|
+
},
|
|
470
|
+
{}
|
|
471
|
+
);
|
|
472
|
+
const detail = tick.rows.map(
|
|
473
|
+
(r) => `${r.eventType}|${r.status}${r.skipReason ? `:${r.skipReason}` : ""}=${r.count}`
|
|
474
|
+
).join(" ");
|
|
475
|
+
this.logger.log(
|
|
476
|
+
`bridge_metrics tick window=[${tick.windowStart.toISOString()}..${tick.windowEnd.toISOString()}] totals=${JSON.stringify(totals)} detail=[${detail}]`
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
resolveIntervalMs() {
|
|
480
|
+
const raw = process.env["BRIDGE_METRICS_INTERVAL_MS"];
|
|
481
|
+
if (!raw) return DEFAULT_INTERVAL_MS;
|
|
482
|
+
const parsed = Number.parseInt(raw, 10);
|
|
483
|
+
if (!Number.isFinite(parsed) || parsed < MIN_INTERVAL_MS) {
|
|
484
|
+
new Logger8(BridgeMetricsReporter.name).warn(
|
|
485
|
+
`Ignoring BRIDGE_METRICS_INTERVAL_MS='${raw}' (invalid or < ${MIN_INTERVAL_MS}ms); using default ${DEFAULT_INTERVAL_MS}ms.`
|
|
486
|
+
);
|
|
487
|
+
return DEFAULT_INTERVAL_MS;
|
|
488
|
+
}
|
|
489
|
+
return parsed;
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
BridgeMetricsReporter = __decorateClass([
|
|
493
|
+
Injectable17(),
|
|
494
|
+
__decorateParam(0, Inject15(DRIZZLE)),
|
|
495
|
+
__decorateParam(1, Optional7())
|
|
496
|
+
], BridgeMetricsReporter);
|
|
497
|
+
}
|
|
498
|
+
});
|
|
12
499
|
|
|
13
500
|
// runtime/subsystems/events/events.tokens.ts
|
|
14
501
|
var EVENT_BUS = "EVENT_BUS";
|
|
@@ -208,63 +695,14 @@ TypedEventBus = __decorateClass([
|
|
|
208
695
|
|
|
209
696
|
// runtime/subsystems/events/events.module.ts
|
|
210
697
|
import { Module } from "@nestjs/common";
|
|
211
|
-
|
|
212
|
-
// runtime/constants/tokens.ts
|
|
213
|
-
var DRIZZLE = "DRIZZLE";
|
|
698
|
+
init_tokens();
|
|
214
699
|
|
|
215
700
|
// runtime/subsystems/events/event-bus.drizzle-backend.ts
|
|
701
|
+
init_domain_events_schema();
|
|
702
|
+
init_tokens();
|
|
216
703
|
import { Injectable as Injectable2, Inject as Inject2, Logger, Optional } from "@nestjs/common";
|
|
217
704
|
import { eq, and, inArray, asc } from "drizzle-orm";
|
|
218
705
|
|
|
219
|
-
// runtime/subsystems/events/domain-events.schema.ts
|
|
220
|
-
import {
|
|
221
|
-
index,
|
|
222
|
-
jsonb,
|
|
223
|
-
pgTable,
|
|
224
|
-
text,
|
|
225
|
-
timestamp,
|
|
226
|
-
uuid
|
|
227
|
-
} from "drizzle-orm/pg-core";
|
|
228
|
-
var domainEvents = pgTable(
|
|
229
|
-
"domain_events",
|
|
230
|
-
{
|
|
231
|
-
id: uuid("id").primaryKey(),
|
|
232
|
-
type: text("type").notNull(),
|
|
233
|
-
aggregateId: text("aggregate_id").notNull(),
|
|
234
|
-
aggregateType: text("aggregate_type").notNull(),
|
|
235
|
-
payload: jsonb("payload").notNull().$type(),
|
|
236
|
-
occurredAt: timestamp("occurred_at", { withTimezone: true }).notNull(),
|
|
237
|
-
processedAt: timestamp("processed_at", { withTimezone: true }),
|
|
238
|
-
/** Lifecycle status: pending | processed | failed */
|
|
239
|
-
status: text("status").notNull().default("pending"),
|
|
240
|
-
/** Error message from the last failed dispatch attempt. */
|
|
241
|
-
error: text("error"),
|
|
242
|
-
metadata: jsonb("metadata").$type(),
|
|
243
|
-
/** Routing pool (e.g. `events_inbound`, `events_change`, `events_outbound`). Populated by DrizzleEventBus.publish() in EVT-4. */
|
|
244
|
-
pool: text("pool"),
|
|
245
|
-
/** Routing direction: `inbound` | `change` | `outbound`. Populated by DrizzleEventBus.publish() in EVT-4. */
|
|
246
|
-
direction: text("direction"),
|
|
247
|
-
// conditional: emitted only when events.multi_tenant: true
|
|
248
|
-
tenantId: text("tenant_id")
|
|
249
|
-
},
|
|
250
|
-
(t) => ({
|
|
251
|
-
/** Polling drain filter (existing — promoted from comment to declaration in EVT-1). */
|
|
252
|
-
idxDomainEventsStatusOccurredAt: index("idx_domain_events_status_occurred_at").on(
|
|
253
|
-
t.status,
|
|
254
|
-
t.occurredAt
|
|
255
|
-
),
|
|
256
|
-
/** Event replay per aggregate (existing — promoted from comment to declaration in EVT-1). */
|
|
257
|
-
idxDomainEventsAggregate: index("idx_domain_events_aggregate").on(
|
|
258
|
-
t.aggregateId,
|
|
259
|
-
t.aggregateType
|
|
260
|
-
),
|
|
261
|
-
/** Per-pool drain filter (EVT-1). Enables DrizzleEventBus to drain a single pool without scanning all events. */
|
|
262
|
-
idxDomainEventsPoolStatusOccurredAt: index(
|
|
263
|
-
"idx_domain_events_pool_status_occurred_at"
|
|
264
|
-
).on(t.pool, t.status, t.occurredAt)
|
|
265
|
-
})
|
|
266
|
-
);
|
|
267
|
-
|
|
268
706
|
// runtime/subsystems/bridge/bridge.tokens.ts
|
|
269
707
|
var BRIDGE_OUTBOX_DRAIN_HOOK = "BRIDGE_OUTBOX_DRAIN_HOOK";
|
|
270
708
|
|
|
@@ -893,159 +1331,12 @@ EventsModule = __decorateClass([
|
|
|
893
1331
|
Module({})
|
|
894
1332
|
], EventsModule);
|
|
895
1333
|
|
|
896
|
-
// runtime/subsystems/
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
jsonb as jsonb2,
|
|
903
|
-
integer,
|
|
904
|
-
timestamp as timestamp2,
|
|
905
|
-
index as index2,
|
|
906
|
-
uniqueIndex
|
|
907
|
-
} from "drizzle-orm/pg-core";
|
|
908
|
-
import { sql } from "drizzle-orm";
|
|
909
|
-
var jobRunStatusEnum = pgEnum("job_run_status", [
|
|
910
|
-
"pending",
|
|
911
|
-
"running",
|
|
912
|
-
"waiting",
|
|
913
|
-
"completed",
|
|
914
|
-
"failed",
|
|
915
|
-
"timed_out",
|
|
916
|
-
"canceled"
|
|
917
|
-
]);
|
|
918
|
-
var jobStepKindEnum = pgEnum("job_step_kind", ["task"]);
|
|
919
|
-
var jobStepStatusEnum = pgEnum("job_step_status", [
|
|
920
|
-
"pending",
|
|
921
|
-
"running",
|
|
922
|
-
"completed",
|
|
923
|
-
"failed",
|
|
924
|
-
"skipped"
|
|
925
|
-
]);
|
|
926
|
-
var collisionModeEnum = pgEnum("job_collision_mode", [
|
|
927
|
-
"queue",
|
|
928
|
-
"reject",
|
|
929
|
-
"replace"
|
|
930
|
-
]);
|
|
931
|
-
var replayFromEnum = pgEnum("job_replay_from", [
|
|
932
|
-
"scratch",
|
|
933
|
-
"last_step",
|
|
934
|
-
"last_checkpoint"
|
|
935
|
-
]);
|
|
936
|
-
var parentClosePolicyEnum = pgEnum("job_parent_close_policy", [
|
|
937
|
-
"terminate",
|
|
938
|
-
"cancel",
|
|
939
|
-
"abandon"
|
|
940
|
-
]);
|
|
941
|
-
var waitKindEnum = pgEnum("job_wait_kind", ["signal"]);
|
|
942
|
-
var triggerSourceEnum = pgEnum("job_trigger_source", [
|
|
943
|
-
"manual",
|
|
944
|
-
"schedule",
|
|
945
|
-
"event",
|
|
946
|
-
"parent"
|
|
947
|
-
]);
|
|
948
|
-
var jobs = pgTable2("job", {
|
|
949
|
-
type: text2("type").primaryKey(),
|
|
950
|
-
version: integer("version").notNull().default(1),
|
|
951
|
-
pool: text2("pool").notNull(),
|
|
952
|
-
scopeEntityType: text2("scope_entity_type"),
|
|
953
|
-
retryPolicy: jsonb2("retry_policy").notNull().$type(),
|
|
954
|
-
timeoutMs: integer("timeout_ms"),
|
|
955
|
-
concurrencyKeyTemplate: text2("concurrency_key_template"),
|
|
956
|
-
collisionMode: collisionModeEnum("collision_mode").notNull().default("queue"),
|
|
957
|
-
dedupeKeyTemplate: text2("dedupe_key_template"),
|
|
958
|
-
dedupeWindowMs: integer("dedupe_window_ms"),
|
|
959
|
-
priorityDefault: integer("priority_default").notNull().default(0),
|
|
960
|
-
replayFrom: replayFromEnum("replay_from").notNull().default("last_checkpoint"),
|
|
961
|
-
createdAt: timestamp2("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
962
|
-
updatedAt: timestamp2("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
963
|
-
});
|
|
964
|
-
var jobRuns = pgTable2(
|
|
965
|
-
"job_run",
|
|
966
|
-
{
|
|
967
|
-
id: uuid2("id").primaryKey().defaultRandom(),
|
|
968
|
-
jobType: text2("job_type").notNull().references(() => jobs.type),
|
|
969
|
-
jobVersion: integer("job_version").notNull(),
|
|
970
|
-
parentRunId: uuid2("parent_run_id").references(() => jobRuns.id),
|
|
971
|
-
/**
|
|
972
|
-
* Service generates `id` client-side via randomUUID() and sets
|
|
973
|
-
* root_run_id = id for root runs (single INSERT, no self-FK race).
|
|
974
|
-
*/
|
|
975
|
-
rootRunId: uuid2("root_run_id").notNull(),
|
|
976
|
-
parentClosePolicy: parentClosePolicyEnum("parent_close_policy").notNull().default("terminate"),
|
|
977
|
-
scopeEntityType: text2("scope_entity_type"),
|
|
978
|
-
scopeEntityId: text2("scope_entity_id"),
|
|
979
|
-
tenantId: text2("tenant_id"),
|
|
980
|
-
tags: jsonb2("tags").notNull().default({}).$type(),
|
|
981
|
-
pool: text2("pool").notNull(),
|
|
982
|
-
priority: integer("priority").notNull().default(0),
|
|
983
|
-
concurrencyKey: text2("concurrency_key"),
|
|
984
|
-
dedupeKey: text2("dedupe_key"),
|
|
985
|
-
status: jobRunStatusEnum("status").notNull().default("pending"),
|
|
986
|
-
input: jsonb2("input").notNull().$type(),
|
|
987
|
-
output: jsonb2("output").$type(),
|
|
988
|
-
error: jsonb2("error").$type(),
|
|
989
|
-
triggerSource: triggerSourceEnum("trigger_source").notNull(),
|
|
990
|
-
triggerRef: text2("trigger_ref"),
|
|
991
|
-
runAt: timestamp2("run_at", { withTimezone: true }).notNull().defaultNow(),
|
|
992
|
-
startedAt: timestamp2("started_at", { withTimezone: true }),
|
|
993
|
-
finishedAt: timestamp2("finished_at", { withTimezone: true }),
|
|
994
|
-
claimedAt: timestamp2("claimed_at", { withTimezone: true }),
|
|
995
|
-
attempts: integer("attempts").notNull().default(0),
|
|
996
|
-
// Phase 3 placeholder — see ADR-025
|
|
997
|
-
waitKind: waitKindEnum("wait_kind"),
|
|
998
|
-
// Phase 3 placeholder — see ADR-025
|
|
999
|
-
resumeToken: text2("resume_token"),
|
|
1000
|
-
// Phase 3 placeholder — see ADR-025
|
|
1001
|
-
waitDeadline: timestamp2("wait_deadline", { withTimezone: true }),
|
|
1002
|
-
createdAt: timestamp2("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
1003
|
-
updatedAt: timestamp2("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
1004
|
-
},
|
|
1005
|
-
(t) => ({
|
|
1006
|
-
/** Claim query: ORDER BY priority DESC, run_at ASC. */
|
|
1007
|
-
idxJobRunClaim: index2("idx_job_run_claim").on(t.status, t.pool, t.runAt),
|
|
1008
|
-
/** Tree traversal / cascade cancel. */
|
|
1009
|
-
idxJobRunRoot: index2("idx_job_run_root").on(t.rootRunId),
|
|
1010
|
-
/** listForScope query. */
|
|
1011
|
-
idxJobRunScope: index2("idx_job_run_scope").on(t.scopeEntityType, t.scopeEntityId),
|
|
1012
|
-
/** Idempotency collapse — partial index. */
|
|
1013
|
-
idxJobRunDedupe: index2("idx_job_run_dedupe").on(t.jobType, t.dedupeKey).where(sql`${t.dedupeKey} IS NOT NULL`),
|
|
1014
|
-
/** Collision check — partial index. */
|
|
1015
|
-
idxJobRunConcurrency: index2("idx_job_run_concurrency").on(t.concurrencyKey).where(
|
|
1016
|
-
sql`${t.concurrencyKey} IS NOT NULL AND ${t.status} IN ('pending','running')`
|
|
1017
|
-
)
|
|
1018
|
-
})
|
|
1019
|
-
);
|
|
1020
|
-
var jobSteps = pgTable2(
|
|
1021
|
-
"job_step",
|
|
1022
|
-
{
|
|
1023
|
-
id: uuid2("id").primaryKey().defaultRandom(),
|
|
1024
|
-
jobRunId: uuid2("job_run_id").notNull().references(() => jobRuns.id),
|
|
1025
|
-
stepId: text2("step_id").notNull(),
|
|
1026
|
-
kind: jobStepKindEnum("kind").notNull().default("task"),
|
|
1027
|
-
/**
|
|
1028
|
-
* Monotonic within run. integer (max ~2B per run) is sufficient —
|
|
1029
|
-
* downgraded from ADR-022's bigint; revisit only if a single run
|
|
1030
|
-
* ever exceeds 2 billion steps.
|
|
1031
|
-
*/
|
|
1032
|
-
seq: integer("seq").notNull(),
|
|
1033
|
-
status: jobStepStatusEnum("status").notNull().default("pending"),
|
|
1034
|
-
input: jsonb2("input").$type(),
|
|
1035
|
-
/** Memoised on success for replay. */
|
|
1036
|
-
output: jsonb2("output").$type(),
|
|
1037
|
-
error: jsonb2("error").$type(),
|
|
1038
|
-
attempts: integer("attempts").notNull().default(0),
|
|
1039
|
-
startedAt: timestamp2("started_at", { withTimezone: true }),
|
|
1040
|
-
finishedAt: timestamp2("finished_at", { withTimezone: true })
|
|
1041
|
-
},
|
|
1042
|
-
(t) => ({
|
|
1043
|
-
/** No duplicate step IDs per run. */
|
|
1044
|
-
idxJobStepRunStep: uniqueIndex("idx_job_step_run_step").on(t.jobRunId, t.stepId),
|
|
1045
|
-
/** Ordered timeline reads. */
|
|
1046
|
-
idxJobStepTimeline: index2("idx_job_step_timeline").on(t.jobRunId, t.seq)
|
|
1047
|
-
})
|
|
1048
|
-
);
|
|
1334
|
+
// runtime/subsystems/events/index.ts
|
|
1335
|
+
init_domain_events_schema();
|
|
1336
|
+
|
|
1337
|
+
// runtime/subsystems/jobs/index.ts
|
|
1338
|
+
init_job_orchestration_schema();
|
|
1339
|
+
init_job_orchestration_schema();
|
|
1049
1340
|
|
|
1050
1341
|
// runtime/subsystems/jobs/jobs-domain.tokens.ts
|
|
1051
1342
|
var JOB_ORCHESTRATOR = /* @__PURE__ */ Symbol("JOB_ORCHESTRATOR");
|
|
@@ -1068,6 +1359,8 @@ var HandlerRegistry;
|
|
|
1068
1359
|
})(HandlerRegistry || (HandlerRegistry = {}));
|
|
1069
1360
|
|
|
1070
1361
|
// runtime/subsystems/jobs/job-orchestrator.drizzle-backend.ts
|
|
1362
|
+
init_tokens();
|
|
1363
|
+
init_job_orchestration_schema();
|
|
1071
1364
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
1072
1365
|
import { Inject as Inject5, Injectable as Injectable5, Logger as Logger4 } from "@nestjs/common";
|
|
1073
1366
|
import { and as and2, desc, eq as eq2, gt, inArray as inArray2, isNotNull, ne, notInArray, sql as sql2 } from "drizzle-orm";
|
|
@@ -1152,6 +1445,7 @@ var ReservedPoolViolationError = class extends Error {
|
|
|
1152
1445
|
};
|
|
1153
1446
|
|
|
1154
1447
|
// runtime/subsystems/jobs/job-orchestrator.drizzle-backend.ts
|
|
1448
|
+
init_job_orchestration_schema();
|
|
1155
1449
|
var TERMINAL_STATUSES = [
|
|
1156
1450
|
"completed",
|
|
1157
1451
|
"failed",
|
|
@@ -1476,6 +1770,8 @@ function notInStatus(statuses) {
|
|
|
1476
1770
|
}
|
|
1477
1771
|
|
|
1478
1772
|
// runtime/subsystems/jobs/job-run-service.drizzle-backend.ts
|
|
1773
|
+
init_tokens();
|
|
1774
|
+
init_job_orchestration_schema();
|
|
1479
1775
|
import { Inject as Inject6, Injectable as Injectable6 } from "@nestjs/common";
|
|
1480
1776
|
import { and as and3, asc as asc2, desc as desc2, eq as eq3, inArray as inArray3, isNull } from "drizzle-orm";
|
|
1481
1777
|
var NON_TERMINAL_STATUSES = [
|
|
@@ -1587,6 +1883,8 @@ DrizzleJobRunService = __decorateClass([
|
|
|
1587
1883
|
], DrizzleJobRunService);
|
|
1588
1884
|
|
|
1589
1885
|
// runtime/subsystems/jobs/job-step-service.drizzle-backend.ts
|
|
1886
|
+
init_tokens();
|
|
1887
|
+
init_job_orchestration_schema();
|
|
1590
1888
|
import { Inject as Inject7, Injectable as Injectable7 } from "@nestjs/common";
|
|
1591
1889
|
import { and as and4, eq as eq4 } from "drizzle-orm";
|
|
1592
1890
|
var DrizzleJobStepService = class {
|
|
@@ -1631,6 +1929,8 @@ DrizzleJobStepService = __decorateClass([
|
|
|
1631
1929
|
], DrizzleJobStepService);
|
|
1632
1930
|
|
|
1633
1931
|
// runtime/subsystems/jobs/job-worker.ts
|
|
1932
|
+
init_tokens();
|
|
1933
|
+
init_job_orchestration_schema();
|
|
1634
1934
|
import { Inject as Inject8, Injectable as Injectable8, Logger as Logger5 } from "@nestjs/common";
|
|
1635
1935
|
import { and as and5, asc as asc3, desc as desc3, eq as eq5, inArray as inArray4, lt, lte, sql as sql3 } from "drizzle-orm";
|
|
1636
1936
|
var JOB_WORKER_OPTIONS = /* @__PURE__ */ Symbol("JOB_WORKER_OPTIONS");
|
|
@@ -2904,6 +3204,7 @@ JobsDomainModule = __decorateClass([
|
|
|
2904
3204
|
], JobsDomainModule);
|
|
2905
3205
|
|
|
2906
3206
|
// runtime/subsystems/jobs/job-worker.module.ts
|
|
3207
|
+
init_tokens();
|
|
2907
3208
|
import {
|
|
2908
3209
|
Inject as Inject11,
|
|
2909
3210
|
Injectable as Injectable12,
|
|
@@ -3200,6 +3501,7 @@ var CACHE_DEFAULT_TTL = /* @__PURE__ */ Symbol("CACHE_DEFAULT_TTL");
|
|
|
3200
3501
|
|
|
3201
3502
|
// runtime/subsystems/cache/cache.module.ts
|
|
3202
3503
|
import { Module as Module4 } from "@nestjs/common";
|
|
3504
|
+
init_tokens();
|
|
3203
3505
|
|
|
3204
3506
|
// runtime/subsystems/cache/cache.drizzle-backend.ts
|
|
3205
3507
|
import { Injectable as Injectable13, Inject as Inject12, Optional as Optional5 } from "@nestjs/common";
|
|
@@ -3221,6 +3523,7 @@ var cacheEntries = pgTable3(
|
|
|
3221
3523
|
);
|
|
3222
3524
|
|
|
3223
3525
|
// runtime/subsystems/cache/cache.drizzle-backend.ts
|
|
3526
|
+
init_tokens();
|
|
3224
3527
|
var CLEANUP_INTERVAL_MS = 5 * 60 * 1e3;
|
|
3225
3528
|
var DrizzleCacheService = class {
|
|
3226
3529
|
constructor(db, defaultTtl = null) {
|
|
@@ -3641,6 +3944,412 @@ StorageModule = __decorateClass([
|
|
|
3641
3944
|
Module5({})
|
|
3642
3945
|
], StorageModule);
|
|
3643
3946
|
|
|
3947
|
+
// runtime/subsystems/observability/observability.tokens.ts
|
|
3948
|
+
var OBSERVABILITY = /* @__PURE__ */ Symbol("OBSERVABILITY");
|
|
3949
|
+
var OBSERVABILITY_REPORTERS = /* @__PURE__ */ Symbol("OBSERVABILITY_REPORTERS");
|
|
3950
|
+
|
|
3951
|
+
// runtime/subsystems/observability/observability.module.ts
|
|
3952
|
+
import { Module as Module6 } from "@nestjs/common";
|
|
3953
|
+
|
|
3954
|
+
// runtime/subsystems/observability/observability.drizzle-backend.ts
|
|
3955
|
+
init_tokens();
|
|
3956
|
+
init_job_orchestration_schema();
|
|
3957
|
+
import { Inject as Inject14, Injectable as Injectable15 } from "@nestjs/common";
|
|
3958
|
+
import { desc as desc4, eq as eq7, sql as sql5 } from "drizzle-orm";
|
|
3959
|
+
|
|
3960
|
+
// runtime/subsystems/sync/sync-audit.schema.ts
|
|
3961
|
+
import {
|
|
3962
|
+
pgEnum as pgEnum2,
|
|
3963
|
+
pgTable as pgTable4,
|
|
3964
|
+
uuid as uuid3,
|
|
3965
|
+
text as text4,
|
|
3966
|
+
jsonb as jsonb4,
|
|
3967
|
+
integer as integer2,
|
|
3968
|
+
boolean,
|
|
3969
|
+
timestamp as timestamp4,
|
|
3970
|
+
index as index3,
|
|
3971
|
+
uniqueIndex as uniqueIndex2
|
|
3972
|
+
} from "drizzle-orm/pg-core";
|
|
3973
|
+
var syncRunDirectionEnum = pgEnum2("sync_run_direction", [
|
|
3974
|
+
"inbound",
|
|
3975
|
+
"outbound"
|
|
3976
|
+
]);
|
|
3977
|
+
var syncRunActionEnum = pgEnum2("sync_run_action", [
|
|
3978
|
+
"poll",
|
|
3979
|
+
"cdc",
|
|
3980
|
+
"webhook",
|
|
3981
|
+
"manual",
|
|
3982
|
+
"writeback"
|
|
3983
|
+
]);
|
|
3984
|
+
var syncRunStatusEnum = pgEnum2("sync_run_status", [
|
|
3985
|
+
"running",
|
|
3986
|
+
"success",
|
|
3987
|
+
"no_changes",
|
|
3988
|
+
"failed"
|
|
3989
|
+
]);
|
|
3990
|
+
var syncRunItemOperationEnum = pgEnum2("sync_run_item_operation", [
|
|
3991
|
+
"created",
|
|
3992
|
+
"updated",
|
|
3993
|
+
"deleted",
|
|
3994
|
+
"noop"
|
|
3995
|
+
]);
|
|
3996
|
+
var syncRunItemStatusEnum = pgEnum2("sync_run_item_status", [
|
|
3997
|
+
"success",
|
|
3998
|
+
"failed",
|
|
3999
|
+
"skipped"
|
|
4000
|
+
]);
|
|
4001
|
+
var syncSubscriptions = pgTable4(
|
|
4002
|
+
"sync_subscriptions",
|
|
4003
|
+
{
|
|
4004
|
+
id: uuid3("id").primaryKey().defaultRandom(),
|
|
4005
|
+
integrationId: text4("integration_id").notNull(),
|
|
4006
|
+
adapter: text4("adapter").notNull(),
|
|
4007
|
+
domain: text4("domain").notNull(),
|
|
4008
|
+
externalRef: text4("external_ref"),
|
|
4009
|
+
enabled: boolean("enabled").notNull().default(true),
|
|
4010
|
+
/**
|
|
4011
|
+
* Per-subscription configuration bag. Strategies type it internally;
|
|
4012
|
+
* e.g. polling strategies stash `{ batchSize, highWatermark }` here.
|
|
4013
|
+
*/
|
|
4014
|
+
config: jsonb4("config").notNull().default({}).$type(),
|
|
4015
|
+
/**
|
|
4016
|
+
* Opaque cursor persisted by `ICursorStore.put()`. NULL until the first
|
|
4017
|
+
* successful run advances it.
|
|
4018
|
+
*/
|
|
4019
|
+
cursor: jsonb4("cursor").$type(),
|
|
4020
|
+
lastSyncAt: timestamp4("last_sync_at", { withTimezone: true }),
|
|
4021
|
+
/** Runtime-enforced when `SYNC_MULTI_TENANT` is true; see SYNC-6. */
|
|
4022
|
+
tenantId: text4("tenant_id"),
|
|
4023
|
+
createdAt: timestamp4("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
4024
|
+
updatedAt: timestamp4("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
4025
|
+
},
|
|
4026
|
+
(t) => ({
|
|
4027
|
+
/**
|
|
4028
|
+
* Composite uniqueness per the epic shape. `external_ref` is nullable;
|
|
4029
|
+
* Postgres treats NULLs as distinct in a UNIQUE constraint, which means
|
|
4030
|
+
* two rows with the same `(integration_id, adapter, domain)` and NULL
|
|
4031
|
+
* external_ref are allowed. That's intentional — a subscription with
|
|
4032
|
+
* NULL external_ref covers the full domain, and duplicates there would
|
|
4033
|
+
* be a consumer-layer modeling issue, not a schema concern.
|
|
4034
|
+
*/
|
|
4035
|
+
uqSyncSubscriptionTuple: uniqueIndex2("uq_sync_subscriptions_tuple").on(
|
|
4036
|
+
t.integrationId,
|
|
4037
|
+
t.adapter,
|
|
4038
|
+
t.domain,
|
|
4039
|
+
t.externalRef
|
|
4040
|
+
),
|
|
4041
|
+
/** Scheduling query: list enabled subscriptions ordered by staleness. */
|
|
4042
|
+
idxSyncSubscriptionsEnabledLastSync: index3(
|
|
4043
|
+
"idx_sync_subscriptions_enabled_last_sync"
|
|
4044
|
+
).on(t.enabled, t.lastSyncAt)
|
|
4045
|
+
})
|
|
4046
|
+
);
|
|
4047
|
+
var syncRuns = pgTable4(
|
|
4048
|
+
"sync_runs",
|
|
4049
|
+
{
|
|
4050
|
+
id: uuid3("id").primaryKey().defaultRandom(),
|
|
4051
|
+
subscriptionId: uuid3("subscription_id").notNull().references(() => syncSubscriptions.id, { onDelete: "cascade" }),
|
|
4052
|
+
direction: syncRunDirectionEnum("direction").notNull(),
|
|
4053
|
+
action: syncRunActionEnum("action").notNull(),
|
|
4054
|
+
status: syncRunStatusEnum("status").notNull().default("running"),
|
|
4055
|
+
recordsFound: integer2("records_found").notNull().default(0),
|
|
4056
|
+
recordsProcessed: integer2("records_processed").notNull().default(0),
|
|
4057
|
+
cursorBefore: jsonb4("cursor_before").$type(),
|
|
4058
|
+
cursorAfter: jsonb4("cursor_after").$type(),
|
|
4059
|
+
durationMs: integer2("duration_ms"),
|
|
4060
|
+
error: text4("error"),
|
|
4061
|
+
startedAt: timestamp4("started_at", { withTimezone: true }).notNull().defaultNow(),
|
|
4062
|
+
completedAt: timestamp4("completed_at", { withTimezone: true }),
|
|
4063
|
+
/** Runtime-enforced when `SYNC_MULTI_TENANT` is true; see SYNC-6. */
|
|
4064
|
+
tenantId: text4("tenant_id")
|
|
4065
|
+
},
|
|
4066
|
+
(t) => ({
|
|
4067
|
+
/** Timeline read: "most recent runs for this subscription". */
|
|
4068
|
+
idxSyncRunsSubscriptionStartedAt: index3(
|
|
4069
|
+
"idx_sync_runs_subscription_started_at"
|
|
4070
|
+
).on(t.subscriptionId, t.startedAt),
|
|
4071
|
+
/** Stale-run sweeper: "runs that started > N minutes ago and are still running". */
|
|
4072
|
+
idxSyncRunsStatusStartedAt: index3("idx_sync_runs_status_started_at").on(
|
|
4073
|
+
t.status,
|
|
4074
|
+
t.startedAt
|
|
4075
|
+
)
|
|
4076
|
+
})
|
|
4077
|
+
);
|
|
4078
|
+
var syncRunItems = pgTable4(
|
|
4079
|
+
"sync_run_items",
|
|
4080
|
+
{
|
|
4081
|
+
id: uuid3("id").primaryKey().defaultRandom(),
|
|
4082
|
+
syncRunId: uuid3("sync_run_id").notNull().references(() => syncRuns.id, { onDelete: "cascade" }),
|
|
4083
|
+
entityType: text4("entity_type").notNull(),
|
|
4084
|
+
externalId: text4("external_id").notNull(),
|
|
4085
|
+
localId: text4("local_id"),
|
|
4086
|
+
operation: syncRunItemOperationEnum("operation").notNull(),
|
|
4087
|
+
status: syncRunItemStatusEnum("status").notNull(),
|
|
4088
|
+
/**
|
|
4089
|
+
* Structured per-field diff — ADR-0003 shape enforced by
|
|
4090
|
+
* `FieldDiffSchema.parse` at the recorder service layer.
|
|
4091
|
+
*
|
|
4092
|
+
* Shape: `{ [fieldName]: { from: unknown, to: unknown } }`.
|
|
4093
|
+
* Empty `{}` for `noop` items; `{ [field]: { from: null, to: <value> } }`
|
|
4094
|
+
* for created items; `{ [field]: { from: <value>, to: null } }` for
|
|
4095
|
+
* deleted items.
|
|
4096
|
+
*/
|
|
4097
|
+
changedFields: jsonb4("changed_fields").notNull().default({}).$type(),
|
|
4098
|
+
title: text4("title"),
|
|
4099
|
+
error: text4("error"),
|
|
4100
|
+
createdAt: timestamp4("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
4101
|
+
/** Runtime-enforced when `SYNC_MULTI_TENANT` is true; see SYNC-6. */
|
|
4102
|
+
tenantId: text4("tenant_id")
|
|
4103
|
+
},
|
|
4104
|
+
(t) => ({
|
|
4105
|
+
/** Ordered timeline within a run. */
|
|
4106
|
+
idxSyncRunItemsRunCreatedAt: index3("idx_sync_run_items_run_created_at").on(
|
|
4107
|
+
t.syncRunId,
|
|
4108
|
+
t.createdAt
|
|
4109
|
+
),
|
|
4110
|
+
/** Per-record history: "every sync that touched opportunity/$extId". */
|
|
4111
|
+
idxSyncRunItemsEntityExternal: index3(
|
|
4112
|
+
"idx_sync_run_items_entity_external"
|
|
4113
|
+
).on(t.entityType, t.externalId)
|
|
4114
|
+
})
|
|
4115
|
+
);
|
|
4116
|
+
|
|
4117
|
+
// runtime/subsystems/observability/observability.drizzle-backend.ts
|
|
4118
|
+
var DrizzleObservabilityService = class {
|
|
4119
|
+
constructor(db) {
|
|
4120
|
+
this.db = db;
|
|
4121
|
+
}
|
|
4122
|
+
db;
|
|
4123
|
+
async getPoolDepths() {
|
|
4124
|
+
const result = await this.db.execute(sql5`
|
|
4125
|
+
SELECT
|
|
4126
|
+
pool AS name,
|
|
4127
|
+
COUNT(*) FILTER (WHERE status = 'pending')::int AS pending,
|
|
4128
|
+
COUNT(*) FILTER (WHERE status = 'running')::int AS running,
|
|
4129
|
+
(percentile_cont(0.95) WITHIN GROUP (
|
|
4130
|
+
ORDER BY EXTRACT(EPOCH FROM (now() - claimed_at)) * 1000
|
|
4131
|
+
) FILTER (WHERE status = 'running' AND claimed_at IS NOT NULL))::int
|
|
4132
|
+
AS claimed_age_p95_ms
|
|
4133
|
+
FROM job_run
|
|
4134
|
+
WHERE status IN ('pending','running')
|
|
4135
|
+
GROUP BY pool
|
|
4136
|
+
ORDER BY pool
|
|
4137
|
+
`);
|
|
4138
|
+
const rows = extractRows(result);
|
|
4139
|
+
return rows.map((r) => ({
|
|
4140
|
+
name: r.name,
|
|
4141
|
+
pending: r.pending,
|
|
4142
|
+
running: r.running,
|
|
4143
|
+
claimedAgeP95Ms: r.claimed_age_p95_ms
|
|
4144
|
+
}));
|
|
4145
|
+
}
|
|
4146
|
+
async getRecentSyncRuns(limit, integrationId) {
|
|
4147
|
+
const base = this.db.select({
|
|
4148
|
+
id: syncRuns.id,
|
|
4149
|
+
subscriptionId: syncRuns.subscriptionId,
|
|
4150
|
+
integrationId: syncSubscriptions.integrationId,
|
|
4151
|
+
adapter: syncSubscriptions.adapter,
|
|
4152
|
+
domain: syncSubscriptions.domain,
|
|
4153
|
+
direction: syncRuns.direction,
|
|
4154
|
+
action: syncRuns.action,
|
|
4155
|
+
status: syncRuns.status,
|
|
4156
|
+
recordsFound: syncRuns.recordsFound,
|
|
4157
|
+
recordsProcessed: syncRuns.recordsProcessed,
|
|
4158
|
+
durationMs: syncRuns.durationMs,
|
|
4159
|
+
error: syncRuns.error,
|
|
4160
|
+
startedAt: syncRuns.startedAt,
|
|
4161
|
+
completedAt: syncRuns.completedAt
|
|
4162
|
+
}).from(syncRuns).innerJoin(
|
|
4163
|
+
syncSubscriptions,
|
|
4164
|
+
eq7(syncRuns.subscriptionId, syncSubscriptions.id)
|
|
4165
|
+
);
|
|
4166
|
+
const filtered = integrationId !== void 0 ? base.where(eq7(syncSubscriptions.integrationId, integrationId)) : base;
|
|
4167
|
+
const rows = await filtered.orderBy(desc4(syncRuns.startedAt)).limit(limit);
|
|
4168
|
+
return rows.map((r) => ({
|
|
4169
|
+
id: r.id,
|
|
4170
|
+
subscriptionId: r.subscriptionId,
|
|
4171
|
+
integrationId: r.integrationId,
|
|
4172
|
+
adapter: r.adapter,
|
|
4173
|
+
domain: r.domain,
|
|
4174
|
+
direction: r.direction,
|
|
4175
|
+
action: r.action,
|
|
4176
|
+
status: r.status,
|
|
4177
|
+
recordsFound: r.recordsFound,
|
|
4178
|
+
recordsProcessed: r.recordsProcessed,
|
|
4179
|
+
durationMs: r.durationMs,
|
|
4180
|
+
error: r.error,
|
|
4181
|
+
startedAt: r.startedAt,
|
|
4182
|
+
completedAt: r.completedAt
|
|
4183
|
+
}));
|
|
4184
|
+
}
|
|
4185
|
+
async getBridgeDeliveryHistogram(windowHours) {
|
|
4186
|
+
const result = await this.db.execute(sql5`
|
|
4187
|
+
SELECT status, COUNT(*)::int AS count
|
|
4188
|
+
FROM bridge_delivery
|
|
4189
|
+
WHERE COALESCE(delivered_at, attempted_at) > now() - make_interval(hours => ${windowHours})
|
|
4190
|
+
GROUP BY status
|
|
4191
|
+
`);
|
|
4192
|
+
const rows = extractRows(result);
|
|
4193
|
+
const hist = {};
|
|
4194
|
+
for (const r of rows) hist[r.status] = r.count;
|
|
4195
|
+
return hist;
|
|
4196
|
+
}
|
|
4197
|
+
async getRecentFailedJobs(limit) {
|
|
4198
|
+
const rows = await this.db.select({
|
|
4199
|
+
id: jobRuns.id,
|
|
4200
|
+
jobType: jobRuns.jobType,
|
|
4201
|
+
pool: jobRuns.pool,
|
|
4202
|
+
status: jobRuns.status,
|
|
4203
|
+
error: jobRuns.error,
|
|
4204
|
+
startedAt: jobRuns.startedAt,
|
|
4205
|
+
finishedAt: jobRuns.finishedAt,
|
|
4206
|
+
attempts: jobRuns.attempts
|
|
4207
|
+
}).from(jobRuns).where(eq7(jobRuns.status, "failed")).orderBy(desc4(jobRuns.finishedAt)).limit(limit);
|
|
4208
|
+
return rows.map((r) => ({
|
|
4209
|
+
id: r.id,
|
|
4210
|
+
jobType: r.jobType,
|
|
4211
|
+
pool: r.pool,
|
|
4212
|
+
status: r.status,
|
|
4213
|
+
error: r.error,
|
|
4214
|
+
startedAt: r.startedAt,
|
|
4215
|
+
finishedAt: r.finishedAt,
|
|
4216
|
+
attempts: r.attempts
|
|
4217
|
+
}));
|
|
4218
|
+
}
|
|
4219
|
+
async getCursors() {
|
|
4220
|
+
const rows = await this.db.select({
|
|
4221
|
+
id: syncSubscriptions.id,
|
|
4222
|
+
integrationId: syncSubscriptions.integrationId,
|
|
4223
|
+
adapter: syncSubscriptions.adapter,
|
|
4224
|
+
domain: syncSubscriptions.domain,
|
|
4225
|
+
cursor: syncSubscriptions.cursor,
|
|
4226
|
+
lastSyncAt: syncSubscriptions.lastSyncAt
|
|
4227
|
+
}).from(syncSubscriptions).where(eq7(syncSubscriptions.enabled, true)).orderBy(syncSubscriptions.integrationId, syncSubscriptions.domain);
|
|
4228
|
+
return rows.map((r) => ({
|
|
4229
|
+
subscriptionId: r.id,
|
|
4230
|
+
integrationId: r.integrationId,
|
|
4231
|
+
adapter: r.adapter,
|
|
4232
|
+
domain: r.domain,
|
|
4233
|
+
lastCursor: r.cursor,
|
|
4234
|
+
lastSyncAt: r.lastSyncAt
|
|
4235
|
+
}));
|
|
4236
|
+
}
|
|
4237
|
+
};
|
|
4238
|
+
DrizzleObservabilityService = __decorateClass([
|
|
4239
|
+
Injectable15(),
|
|
4240
|
+
__decorateParam(0, Inject14(DRIZZLE))
|
|
4241
|
+
], DrizzleObservabilityService);
|
|
4242
|
+
function extractRows(result) {
|
|
4243
|
+
const maybe = result;
|
|
4244
|
+
if (Array.isArray(maybe.rows)) return maybe.rows;
|
|
4245
|
+
if (Array.isArray(result)) return result;
|
|
4246
|
+
return [];
|
|
4247
|
+
}
|
|
4248
|
+
|
|
4249
|
+
// runtime/subsystems/observability/observability.memory-backend.ts
|
|
4250
|
+
import { Injectable as Injectable16 } from "@nestjs/common";
|
|
4251
|
+
var MemoryObservabilityService = class {
|
|
4252
|
+
pools = [];
|
|
4253
|
+
syncRuns = [];
|
|
4254
|
+
bridgeHistogram = {};
|
|
4255
|
+
failedJobs = [];
|
|
4256
|
+
cursors = [];
|
|
4257
|
+
// ─── Core contract ─────────────────────────────────────────────────────
|
|
4258
|
+
async getPoolDepths() {
|
|
4259
|
+
return [...this.pools];
|
|
4260
|
+
}
|
|
4261
|
+
async getRecentSyncRuns(limit, integrationId) {
|
|
4262
|
+
const filtered = integrationId !== void 0 ? this.syncRuns.filter((r) => r.integrationId === integrationId) : this.syncRuns;
|
|
4263
|
+
return filtered.slice().sort((a, b) => b.startedAt.getTime() - a.startedAt.getTime()).slice(0, limit);
|
|
4264
|
+
}
|
|
4265
|
+
async getBridgeDeliveryHistogram(_windowHours) {
|
|
4266
|
+
return { ...this.bridgeHistogram };
|
|
4267
|
+
}
|
|
4268
|
+
async getRecentFailedJobs(limit) {
|
|
4269
|
+
return this.failedJobs.slice().sort(
|
|
4270
|
+
(a, b) => (b.finishedAt?.getTime() ?? 0) - (a.finishedAt?.getTime() ?? 0)
|
|
4271
|
+
).slice(0, limit);
|
|
4272
|
+
}
|
|
4273
|
+
async getCursors() {
|
|
4274
|
+
return [...this.cursors];
|
|
4275
|
+
}
|
|
4276
|
+
// ─── Test seams ────────────────────────────────────────────────────────
|
|
4277
|
+
/** Replace the pool-depth slice. */
|
|
4278
|
+
seedPools(pools) {
|
|
4279
|
+
this.pools = [...pools];
|
|
4280
|
+
}
|
|
4281
|
+
/** Replace the sync-run slice. */
|
|
4282
|
+
seedSyncRuns(runs) {
|
|
4283
|
+
this.syncRuns = [...runs];
|
|
4284
|
+
}
|
|
4285
|
+
/** Replace the bridge-delivery histogram. */
|
|
4286
|
+
seedBridgeHistogram(hist) {
|
|
4287
|
+
this.bridgeHistogram = { ...hist };
|
|
4288
|
+
}
|
|
4289
|
+
/** Replace the failed-jobs slice. */
|
|
4290
|
+
seedFailedJobs(jobs2) {
|
|
4291
|
+
this.failedJobs = [...jobs2];
|
|
4292
|
+
}
|
|
4293
|
+
/** Replace the cursor slice. */
|
|
4294
|
+
seedCursors(cursors) {
|
|
4295
|
+
this.cursors = [...cursors];
|
|
4296
|
+
}
|
|
4297
|
+
/** Reset every slice — for afterEach hooks. */
|
|
4298
|
+
reset() {
|
|
4299
|
+
this.pools = [];
|
|
4300
|
+
this.syncRuns = [];
|
|
4301
|
+
this.bridgeHistogram = {};
|
|
4302
|
+
this.failedJobs = [];
|
|
4303
|
+
this.cursors = [];
|
|
4304
|
+
}
|
|
4305
|
+
};
|
|
4306
|
+
MemoryObservabilityService = __decorateClass([
|
|
4307
|
+
Injectable16()
|
|
4308
|
+
], MemoryObservabilityService);
|
|
4309
|
+
|
|
4310
|
+
// runtime/subsystems/observability/observability.module.ts
|
|
4311
|
+
var ObservabilityModule = class {
|
|
4312
|
+
static forRoot(options = { backend: "drizzle" }) {
|
|
4313
|
+
const ConcreteClass = options.backend === "drizzle" ? DrizzleObservabilityService : MemoryObservabilityService;
|
|
4314
|
+
const wantsBridgeMetrics = options.reporters?.bridgeMetrics === true;
|
|
4315
|
+
const providers = [
|
|
4316
|
+
// Register the concrete class as the canonical instance.
|
|
4317
|
+
ConcreteClass,
|
|
4318
|
+
// OBSERVABILITY token points at the same instance — no duplicate.
|
|
4319
|
+
{ provide: OBSERVABILITY, useExisting: ConcreteClass },
|
|
4320
|
+
// Expose the resolved reporter config for introspection / tests.
|
|
4321
|
+
{
|
|
4322
|
+
provide: OBSERVABILITY_REPORTERS,
|
|
4323
|
+
useValue: options.reporters ?? {}
|
|
4324
|
+
}
|
|
4325
|
+
];
|
|
4326
|
+
const exports = [OBSERVABILITY];
|
|
4327
|
+
if (wantsBridgeMetrics) {
|
|
4328
|
+
const { BridgeMetricsReporter: BridgeMetricsReporter2 } = (init_bridge_metrics_reporter(), __toCommonJS(bridge_metrics_reporter_exports));
|
|
4329
|
+
providers.push(BridgeMetricsReporter2);
|
|
4330
|
+
exports.push(BridgeMetricsReporter2);
|
|
4331
|
+
}
|
|
4332
|
+
const imports = [];
|
|
4333
|
+
if (wantsBridgeMetrics) {
|
|
4334
|
+
const { ScheduleModule } = __require("@nestjs/schedule");
|
|
4335
|
+
imports.push(ScheduleModule.forRoot());
|
|
4336
|
+
}
|
|
4337
|
+
return {
|
|
4338
|
+
module: ObservabilityModule,
|
|
4339
|
+
global: true,
|
|
4340
|
+
imports,
|
|
4341
|
+
providers,
|
|
4342
|
+
exports
|
|
4343
|
+
};
|
|
4344
|
+
}
|
|
4345
|
+
};
|
|
4346
|
+
ObservabilityModule = __decorateClass([
|
|
4347
|
+
Module6({})
|
|
4348
|
+
], ObservabilityModule);
|
|
4349
|
+
|
|
4350
|
+
// runtime/subsystems/observability/index.ts
|
|
4351
|
+
init_bridge_metrics_reporter();
|
|
4352
|
+
|
|
3644
4353
|
// runtime/subsystems/auth/auth.tokens.ts
|
|
3645
4354
|
var ENCRYPTION_KEY = /* @__PURE__ */ Symbol("ENCRYPTION_KEY");
|
|
3646
4355
|
var OAUTH_STATE_STORE = /* @__PURE__ */ Symbol("OAUTH_STATE_STORE");
|
|
@@ -3854,7 +4563,7 @@ var InMemoryOAuthStateStore = class {
|
|
|
3854
4563
|
};
|
|
3855
4564
|
|
|
3856
4565
|
// runtime/subsystems/auth/auth.module.ts
|
|
3857
|
-
import { Module as
|
|
4566
|
+
import { Module as Module7 } from "@nestjs/common";
|
|
3858
4567
|
function resolveEncryptionKeyProvider(choice) {
|
|
3859
4568
|
if (choice === "env") {
|
|
3860
4569
|
return { provide: ENCRYPTION_KEY, useClass: EnvEncryptionKey };
|
|
@@ -3884,16 +4593,18 @@ var AuthModule = class {
|
|
|
3884
4593
|
}
|
|
3885
4594
|
};
|
|
3886
4595
|
AuthModule = __decorateClass([
|
|
3887
|
-
|
|
4596
|
+
Module7({})
|
|
3888
4597
|
], AuthModule);
|
|
3889
4598
|
export {
|
|
3890
4599
|
AUTH_INTEGRATION_READER,
|
|
3891
4600
|
AUTH_INTEGRATION_TOKEN_WRITER,
|
|
3892
4601
|
AuthModule,
|
|
4602
|
+
BridgeMetricsReporter,
|
|
3893
4603
|
CACHE,
|
|
3894
4604
|
CacheModule,
|
|
3895
4605
|
DrizzleCacheService,
|
|
3896
4606
|
DrizzleEventBus,
|
|
4607
|
+
DrizzleObservabilityService,
|
|
3897
4608
|
ENCRYPTION_KEY,
|
|
3898
4609
|
EVENT_BUS,
|
|
3899
4610
|
EnvEncryptionKey,
|
|
@@ -3903,9 +4614,13 @@ export {
|
|
|
3903
4614
|
LocalStorageBackend,
|
|
3904
4615
|
MemoryCacheService,
|
|
3905
4616
|
MemoryEventBus,
|
|
4617
|
+
MemoryObservabilityService,
|
|
3906
4618
|
MemoryStorageBackend,
|
|
3907
4619
|
OAUTH_STATE_STORE,
|
|
3908
4620
|
OAuth2RefreshStrategy,
|
|
4621
|
+
OBSERVABILITY,
|
|
4622
|
+
OBSERVABILITY_REPORTERS,
|
|
4623
|
+
ObservabilityModule,
|
|
3909
4624
|
STORAGE,
|
|
3910
4625
|
SessionExpiredError,
|
|
3911
4626
|
StorageModule,
|