@interactive-inc/claude-funnel 0.66.0 → 0.68.0
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/README.md +31 -6
- package/dist/bin.js +292 -383
- package/dist/channel.d.ts +76 -52
- package/dist/channel.js +82 -47
- package/dist/{channels-DR90RmUP.d.ts → channels-B0cifCfw.d.ts} +6 -6
- package/dist/claude.d.ts +11 -8
- package/dist/claude.js +31 -15
- package/dist/connector-descriptor-D4XtEsH8.d.ts +215 -0
- package/dist/{connector-diagnostics-recorder-COtNEmUp.js → connector-diagnostics-recorder-BmOijU1p.js} +1 -0
- package/dist/connectors/discord.d.ts +11 -8
- package/dist/connectors/discord.js +2 -2
- package/dist/connectors/gh.d.ts +7 -6
- package/dist/connectors/gh.js +2 -2
- package/dist/connectors/schedule.d.ts +21 -17
- package/dist/connectors/schedule.js +3 -3
- package/dist/connectors/slack.d.ts +15 -10
- package/dist/connectors/slack.js +3 -3
- package/dist/diagnostic-event-CxMM5Bl2.js +78 -0
- package/dist/diagnostic-log-BsAg5qZK.d.ts +186 -0
- package/dist/diagnostics.d.ts +2 -2
- package/dist/diagnostics.js +3 -2
- package/dist/{discord-connector-DXARcO6w.js → discord-connector-CAcWifJn.js} +6 -6
- package/dist/{discord-connector-schema-D1dyxhXk.d.ts → discord-connector-schema-BaBZYHxK.d.ts} +0 -1
- package/dist/docs.d.ts +1 -1
- package/dist/docs.js +1 -1
- package/dist/doctor.d.ts +1 -1
- package/dist/doctor.js +1 -1
- package/dist/event-log.d.ts +2 -0
- package/dist/event-log.js +3 -0
- package/dist/{file-process-guard-CiBwXjzm.d.ts → file-process-guard-D-QatrwL.d.ts} +22 -18
- package/dist/{file-system-DHgbuTFb.d.ts → file-system-BNtl997T.d.ts} +2 -1
- package/dist/{flume-source-listener-FzR5lGpL.d.ts → flume-source-listener-Ba8_1Mg-.d.ts} +9 -6
- package/dist/{funnel-diagnostics-Cvk6Sk4x.js → funnel-diagnostics-CAG7hJP0.js} +85 -141
- package/dist/{funnel-diagnostics-kbd27d7I.d.ts → funnel-diagnostics-CDrZznTB.d.ts} +18 -18
- package/dist/{funnel-docs-C-ge0MuB.js → funnel-docs-CI4hMkhq.js} +12 -3
- package/dist/{funnel-doctor-CVTNUtDn.d.ts → funnel-doctor-CY4S5cnz.d.ts} +20 -9
- package/dist/{funnel-doctor-XrI2GBH8.js → funnel-doctor-Csw5qjcH.js} +1 -0
- package/dist/{funnel-error-0t1MK1R6.js → funnel-error-DoSBCogD.js} +13 -0
- package/dist/{funnel-recovery-D8MkiTpk.d.ts → funnel-recovery-BwcSNNSN.d.ts} +1 -2
- package/dist/{funnel-recovery-DKnEutUS.js → funnel-recovery-DYbSYGWC.js} +1 -0
- package/dist/gateway/daemon.js +60 -139
- package/dist/gateway.d.ts +2 -3
- package/dist/gateway.js +2 -2
- package/dist/{gh-connector-BUGCOEWS.js → gh-connector-DMwI6zJA.js} +5 -5
- package/dist/{gh-connector-schema-BCHEqpUg.d.ts → gh-connector-schema-BrNsCl1T.d.ts} +0 -1
- package/dist/{index-BU1TtuFy.d.ts → index-fHrKn4jm.d.ts} +210 -40
- package/dist/index.d.ts +125 -115
- package/dist/index.js +242 -57
- package/dist/{local-config-json-schema-DexV8vX3.js → local-config-json-schema-_-YVHX4c.js} +4 -4
- package/dist/local-config.d.ts +2 -3
- package/dist/local-config.js +1 -1
- package/dist/logger.d.ts +17 -265
- package/dist/logger.js +6 -141
- package/dist/memory-event-log-BY8XjFzi.js +147 -0
- package/dist/{memory-token-prompter-D0kIdhar.d.ts → memory-token-prompter-B20tl_aU.d.ts} +2 -3
- package/dist/{node-file-system-BOXIHW_Q.js → node-file-system-xJx7dymE.js} +11 -3
- package/dist/{profiles-M24JrcOh.d.ts → profiles-CePRnv3F.d.ts} +3 -4
- package/dist/{profiles-ZHLONml4.js → profiles-KpN7_gBw.js} +19 -5
- package/dist/profiles.d.ts +1 -1
- package/dist/profiles.js +1 -1
- package/dist/recovery.d.ts +1 -1
- package/dist/recovery.js +1 -1
- package/dist/{schedule-connector-9k3gOIgl.js → schedule-connector-BXUOYgwZ.js} +63 -99
- package/dist/schedule-connector-schema-CNV8PgWX.js +137 -0
- package/dist/schedule-connector-schema-Tq5kJul-.d.ts +127 -0
- package/dist/{settings-reader-BnKIbmsD.d.ts → settings-reader-CyTpbAre.d.ts} +1 -2
- package/dist/{settings-schema-IShSMm5G.d.ts → settings-schema-B-CKLuST.d.ts} +0 -1
- package/dist/{settings-store-ccv291GV.js → settings-store-ZFWBhOnp.js} +12 -3
- package/dist/{slack-connector-CxpWagbT.js → slack-connector-CC3V2VXQ.js} +10 -9
- package/dist/{slack-event-processor-xFDG3US0.js → slack-event-processor-Cs_YuI3w.js} +2 -2
- package/dist/{slack-event-processor-BDTr62cN.d.ts → slack-event-processor-DmAlq4cV.d.ts} +0 -1
- package/dist/{slot-fields-D-pvMgTK.js → slot-fields-eCWizJqS.js} +4 -4
- package/dist/{sqlite-diagnostic-log-CwhXE9Qh.js → sqlite-diagnostic-log-Qs4cf9I_.js} +92 -100
- package/dist/sqlite-event-log-BYgCFMxC.d.ts +284 -0
- package/dist/{funnel-log-sqlite-sink-DLYkY0pZ.js → sqlite-event-log-eZuXKszJ.js} +53 -12
- package/dist/{yaml-render-DVEtYuF1.js → yaml-render-DxxRQT-V.js} +3 -3
- package/package.json +25 -10
- package/dist/broadcaster-DVNcw00K.d.ts +0 -138
- package/dist/connector-descriptor-CmyHlEiT.d.ts +0 -380
- package/dist/diagnostic-sql-reader-oXZnWFf_.js +0 -83
- package/dist/file-system-Wvzc2ePY.js +0 -9
- package/dist/logger-B6iyNbxM.js +0 -9
- package/dist/schedule-connector-schema-D7ZEKvit.d.ts +0 -49
- package/dist/schedule-connector-schema-DKEPZnVv.js +0 -31
- package/dist/settings-reader-9FcX3qS1.js +0 -11
- /package/dist/{connector-adapter-Dvs8N7ew.js → connector-adapter-BL2ehMej.js} +0 -0
- /package/dist/{connector-listener-mPGZYa8e.js → connector-listener-BcQMzY6Q.js} +0 -0
- /package/dist/{discord-connector-schema-B4YpWpR3.js → discord-connector-schema-saAGuPmJ.js} +0 -0
- /package/dist/{error-message-of-ColuYmAk.js → error-message-of-BG4ezZ_s.js} +0 -0
- /package/dist/{funnel-docs-Cd66sKyV.d.ts → funnel-docs-BJWawfWI.d.ts} +0 -0
- /package/dist/{gh-connector-schema-CAqIhzGr.js → gh-connector-schema-DmZTrzUu.js} +0 -0
- /package/dist/{logger-Bc_Ooypb.d.ts → logger-mMZvblTx.d.ts} +0 -0
- /package/dist/{loopback-fetch-CVNuN3YZ.js → loopback-fetch-HP-bo9Kv.js} +0 -0
- /package/dist/{node-http-client-u00atiKx.js → node-http-client-SX3xFh4h.js} +0 -0
- /package/dist/{node-process-runner-DxTvycoK.js → node-process-runner-D4rzPl8Q.js} +0 -0
- /package/dist/{resolve-connector-token-DxDG9mhf.js → resolve-connector-token-BwiJCu82.js} +0 -0
- /package/dist/{slack-connector-schema-Dem8to4P.js → slack-connector-schema-EGVuuqSX.js} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { t as errorMessageOf } from "./error-message-of-
|
|
2
|
-
import { t as FunnelConnectorListener } from "./connector-listener-
|
|
3
|
-
import { t as FunnelConnectorDiagnosticsRecorder } from "./connector-diagnostics-recorder-
|
|
1
|
+
import { t as errorMessageOf } from "./error-message-of-BG4ezZ_s.js";
|
|
2
|
+
import { t as FunnelConnectorListener } from "./connector-listener-BcQMzY6Q.js";
|
|
3
|
+
import { t as FunnelConnectorDiagnosticsRecorder } from "./connector-diagnostics-recorder-BmOijU1p.js";
|
|
4
4
|
import { Flume, createFlumeDefaultDeps } from "@interactive-inc/flume";
|
|
5
5
|
//#region lib/engine/connectors/flume-deps.ts
|
|
6
6
|
/**
|
|
@@ -46,7 +46,7 @@ const flumeLogHandler = (logger) => {
|
|
|
46
46
|
};
|
|
47
47
|
};
|
|
48
48
|
const buildMeta = (log) => {
|
|
49
|
-
const meta = { ...log.detail
|
|
49
|
+
const meta = { ...log.detail };
|
|
50
50
|
if (log.error) {
|
|
51
51
|
meta.error = log.error.message;
|
|
52
52
|
if (log.error.stack) meta.stack = log.error.stack;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { n as gatewayLoopbackUrl, t as loopbackFetch } from "./loopback-fetch-
|
|
2
|
-
import { t as NodeFunnelFileSystem } from "./node-file-system-
|
|
3
|
-
import { t as NodeFunnelProcessRunner } from "./node-process-runner-
|
|
4
|
-
import { n as FUNNEL_DIR, s as resolveFunnelPort } from "./settings-store-
|
|
5
|
-
import { t as FunnelAuthFailedError } from "./funnel-error-
|
|
6
|
-
import { t as
|
|
7
|
-
import { t as
|
|
1
|
+
import { n as gatewayLoopbackUrl, t as loopbackFetch } from "./loopback-fetch-HP-bo9Kv.js";
|
|
2
|
+
import { t as NodeFunnelFileSystem } from "./node-file-system-xJx7dymE.js";
|
|
3
|
+
import { t as NodeFunnelProcessRunner } from "./node-process-runner-D4rzPl8Q.js";
|
|
4
|
+
import { n as FUNNEL_DIR, s as resolveFunnelPort } from "./settings-store-ZFWBhOnp.js";
|
|
5
|
+
import { t as FunnelAuthFailedError } from "./funnel-error-DoSBCogD.js";
|
|
6
|
+
import { n as diagnosticEventOfProcessed, t as diagnosticConnectionEventOf } from "./diagnostic-event-CxMM5Bl2.js";
|
|
7
|
+
import { t as SqliteEventLog } from "./sqlite-event-log-eZuXKszJ.js";
|
|
8
8
|
import { dirname, join } from "node:path";
|
|
9
9
|
import { chmodSync, existsSync, mkdirSync } from "node:fs";
|
|
10
10
|
import { homedir, tmpdir } from "node:os";
|
|
11
11
|
import { z } from "zod";
|
|
12
|
-
import { timingSafeEqual } from "node:crypto";
|
|
12
|
+
import { createHash, randomUUID, timingSafeEqual } from "node:crypto";
|
|
13
13
|
import { createFactory } from "hono/factory";
|
|
14
14
|
import { HTTPException } from "hono/http-exception";
|
|
15
15
|
import { zValidator } from "@hono/zod-validator";
|
|
@@ -128,6 +128,7 @@ var ConnectorDiagnosticLog = class {};
|
|
|
128
128
|
* rejecting a malformed payload.
|
|
129
129
|
*/
|
|
130
130
|
var MemoryConnectorDiagnosticLog = class extends ConnectorDiagnosticLog {
|
|
131
|
+
now;
|
|
131
132
|
raws = [];
|
|
132
133
|
processeds = [];
|
|
133
134
|
connections = [];
|
|
@@ -158,21 +159,31 @@ var MemoryConnectorDiagnosticLog = class extends ConnectorDiagnosticLog {
|
|
|
158
159
|
});
|
|
159
160
|
}
|
|
160
161
|
queryRaw(query) {
|
|
161
|
-
|
|
162
|
+
const matched = this.raws.filter((event) => {
|
|
163
|
+
if (!matches(event, query)) return false;
|
|
164
|
+
if (query.eventId !== void 0 && event.eventId !== query.eventId) return false;
|
|
165
|
+
return true;
|
|
166
|
+
});
|
|
167
|
+
return takeRecent(matched, query.limit);
|
|
162
168
|
}
|
|
163
169
|
queryProcessed(query) {
|
|
164
|
-
|
|
170
|
+
const matched = this.processeds.filter((event) => {
|
|
165
171
|
if (!matches(event, query)) return false;
|
|
172
|
+
if (query.eventId !== void 0 && event.eventId !== query.eventId) return false;
|
|
166
173
|
if (query.outcome !== void 0 && event.outcome !== query.outcome) return false;
|
|
174
|
+
if (query.outcomePrefix !== void 0 && !event.outcome.startsWith(query.outcomePrefix)) return false;
|
|
167
175
|
return true;
|
|
168
|
-
})
|
|
176
|
+
});
|
|
177
|
+
return takeRecent(matched, query.limit);
|
|
169
178
|
}
|
|
170
179
|
queryConnection(query) {
|
|
171
|
-
|
|
180
|
+
const matched = this.connections.filter((event) => {
|
|
172
181
|
if (!matches(event, query)) return false;
|
|
173
182
|
if (query.status !== void 0 && event.status !== query.status) return false;
|
|
183
|
+
if (query.statuses !== void 0 && !query.statuses.includes(event.status)) return false;
|
|
174
184
|
return true;
|
|
175
|
-
})
|
|
185
|
+
});
|
|
186
|
+
return takeRecent(matched, query.limit);
|
|
176
187
|
}
|
|
177
188
|
clear() {
|
|
178
189
|
this.raws.length = 0;
|
|
@@ -185,6 +196,7 @@ const matches = (event, query) => {
|
|
|
185
196
|
if (query.type !== void 0 && event.type !== query.type) return false;
|
|
186
197
|
if (query.connectorId !== void 0 && event.connectorId !== query.connectorId) return false;
|
|
187
198
|
if (query.channelId !== void 0 && event.channelId !== query.channelId) return false;
|
|
199
|
+
if ("seq" in event && query.seq !== void 0 && event.seq !== query.seq) return false;
|
|
188
200
|
return true;
|
|
189
201
|
};
|
|
190
202
|
const takeRecent = (events, limit) => {
|
|
@@ -279,7 +291,8 @@ var FunnelChannelPublisher = class {
|
|
|
279
291
|
*/
|
|
280
292
|
const requireBearerToken = (deps) => {
|
|
281
293
|
return async (c, next) => {
|
|
282
|
-
|
|
294
|
+
const presented = (c.req.header("authorization") ?? "").match(/^Bearer\s+(.+)$/i)?.[1] ?? "";
|
|
295
|
+
if (!constantTimeEqual(presented, deps.expected)) return c.text("unauthorized", 401);
|
|
283
296
|
return await next();
|
|
284
297
|
};
|
|
285
298
|
};
|
|
@@ -447,7 +460,6 @@ var FunnelBroadcaster = class {
|
|
|
447
460
|
offset: this.latestOffset
|
|
448
461
|
};
|
|
449
462
|
const payload = JSON.stringify(event);
|
|
450
|
-
meta?.connector;
|
|
451
463
|
this.eventsBroadcast += 1;
|
|
452
464
|
this.lastBroadcastAt = this.now();
|
|
453
465
|
if (this.replayBufferSize > 0) {
|
|
@@ -574,7 +586,7 @@ var SqliteFunnelEventLog = class extends FunnelEventLog {
|
|
|
574
586
|
this.now = props.now ?? (() => Date.now());
|
|
575
587
|
this.logger = props.logger;
|
|
576
588
|
this.onError = props.onError;
|
|
577
|
-
this.sink = new
|
|
589
|
+
this.sink = new SqliteEventLog({
|
|
578
590
|
path: props.path,
|
|
579
591
|
indexes: ["channel_id", "connector_id"],
|
|
580
592
|
extractIndexes: (event) => ({
|
|
@@ -626,7 +638,10 @@ var SqliteFunnelEventLog = class extends FunnelEventLog {
|
|
|
626
638
|
* so this returns the full slice and lets the caller filter.
|
|
627
639
|
*/
|
|
628
640
|
loadSince(since) {
|
|
629
|
-
const records = this.sink.query({
|
|
641
|
+
const records = this.sink.query({
|
|
642
|
+
sinceSeq: since,
|
|
643
|
+
limit: Number.MAX_SAFE_INTEGER
|
|
644
|
+
});
|
|
630
645
|
const out = [];
|
|
631
646
|
for (const record of records) out.push({
|
|
632
647
|
content: record.event.content,
|
|
@@ -885,7 +900,7 @@ var FunnelListenerRegistry = class FunnelListenerRegistry {
|
|
|
885
900
|
async stopAll() {
|
|
886
901
|
this.stopHealthCheck();
|
|
887
902
|
this.pendingRetry.clear();
|
|
888
|
-
for (const [, entry] of
|
|
903
|
+
for (const [, entry] of this.running.entries()) await this.stop(entry.channelName, entry.config.name);
|
|
889
904
|
}
|
|
890
905
|
ensureStats(key) {
|
|
891
906
|
const existing = this.stats.get(key);
|
|
@@ -932,7 +947,7 @@ var FunnelListenerRegistry = class FunnelListenerRegistry {
|
|
|
932
947
|
this.healthCheckInFlight = true;
|
|
933
948
|
try {
|
|
934
949
|
const dead = [];
|
|
935
|
-
for (const [key, entry] of
|
|
950
|
+
for (const [key, entry] of this.running.entries()) {
|
|
936
951
|
if (entry.listener.isAlive()) {
|
|
937
952
|
this.failureCounts.delete(key);
|
|
938
953
|
continue;
|
|
@@ -945,7 +960,7 @@ var FunnelListenerRegistry = class FunnelListenerRegistry {
|
|
|
945
960
|
}
|
|
946
961
|
await Promise.all(dead.map((target) => this.recoverDead(target.channelName, target.connectorName, target.type)));
|
|
947
962
|
const retries = [];
|
|
948
|
-
for (const [key, pending] of
|
|
963
|
+
for (const [key, pending] of this.pendingRetry.entries()) {
|
|
949
964
|
if (this.running.has(key)) {
|
|
950
965
|
this.pendingRetry.delete(key);
|
|
951
966
|
continue;
|
|
@@ -1181,19 +1196,6 @@ const channelsPublishHandler = factory.createHandlers(zParam(z.object({ channel:
|
|
|
1181
1196
|
});
|
|
1182
1197
|
//#endregion
|
|
1183
1198
|
//#region lib/gateway/routes/debug.ts
|
|
1184
|
-
const extractPreview = (payload) => {
|
|
1185
|
-
if (typeof payload !== "string" || payload.length === 0) return null;
|
|
1186
|
-
try {
|
|
1187
|
-
const parsed = JSON.parse(payload);
|
|
1188
|
-
if (parsed !== null && typeof parsed === "object" && "text" in parsed) {
|
|
1189
|
-
const text = String(parsed.text);
|
|
1190
|
-
return text.length > 80 ? `${text.slice(0, 80)}…` : text;
|
|
1191
|
-
}
|
|
1192
|
-
} catch {
|
|
1193
|
-
return payload.length > 80 ? `${payload.slice(0, 80)}…` : payload;
|
|
1194
|
-
}
|
|
1195
|
-
return payload.length > 80 ? `${payload.slice(0, 80)}…` : payload;
|
|
1196
|
-
};
|
|
1197
1199
|
const buildChannelDiagnosis = (channel) => {
|
|
1198
1200
|
const rootCause = (channel.connectionErrors[channel.connectionErrors.length - 1] ?? null)?.detail ?? null;
|
|
1199
1201
|
if (channel.connectors.length === 0) return {
|
|
@@ -1242,11 +1244,6 @@ const debugHandler = factory.createHandlers(async (c) => {
|
|
|
1242
1244
|
const gatewayListeners = deps.registry.list();
|
|
1243
1245
|
const gatewayClients = deps.broadcaster.listChannels();
|
|
1244
1246
|
const metrics = deps.broadcaster.getMetrics();
|
|
1245
|
-
const tmpDir = funnelTmpDir();
|
|
1246
|
-
const rawPath = join(tmpDir, "connector-raw.db");
|
|
1247
|
-
const processedPath = join(tmpDir, "connector-processed.db");
|
|
1248
|
-
const connectionPath = join(tmpDir, "connector-connection.db");
|
|
1249
|
-
const hasStore = existsSync(rawPath) && existsSync(processedPath) && existsSync(connectionPath);
|
|
1250
1247
|
const channels = targetChannels.map((ch) => {
|
|
1251
1248
|
const listenerEntry = gatewayListeners.find((l) => l.channelName === ch.name) ?? null;
|
|
1252
1249
|
const listener = listenerEntry ? {
|
|
@@ -1256,61 +1253,30 @@ const debugHandler = factory.createHandlers(async (c) => {
|
|
|
1256
1253
|
lastEventAt: listenerEntry.lastEventAt
|
|
1257
1254
|
} : null;
|
|
1258
1255
|
const claudeClients = gatewayClients.filter((cl) => cl.channel === ch.id || cl.channel === ch.name).length;
|
|
1259
|
-
const recentEvents =
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
}
|
|
1267
|
-
|
|
1268
|
-
try {
|
|
1269
|
-
return reader.query("SELECT seq, ts, type, outcome, payload FROM processed WHERE channel_id = ? ORDER BY seq DESC LIMIT 10", [ch.id]);
|
|
1270
|
-
} finally {
|
|
1271
|
-
reader.close();
|
|
1272
|
-
}
|
|
1273
|
-
})();
|
|
1274
|
-
if (!(rows instanceof Error)) for (const row of [...rows].reverse()) {
|
|
1275
|
-
const rawPayload = typeof row.payload === "string" ? row.payload : null;
|
|
1276
|
-
let payloadParsed = null;
|
|
1277
|
-
if (rawPayload) try {
|
|
1278
|
-
const parsed = JSON.parse(rawPayload);
|
|
1279
|
-
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) payloadParsed = parsed;
|
|
1280
|
-
} catch {
|
|
1281
|
-
payloadParsed = null;
|
|
1282
|
-
}
|
|
1283
|
-
recentEvents.push({
|
|
1284
|
-
seq: typeof row.seq === "number" ? row.seq : null,
|
|
1285
|
-
ts: typeof row.ts === "number" ? row.ts : null,
|
|
1286
|
-
type: typeof row.type === "string" ? row.type : "?",
|
|
1287
|
-
outcome: typeof row.outcome === "string" ? row.outcome : "?",
|
|
1288
|
-
payload: rawPayload,
|
|
1289
|
-
payloadParsed,
|
|
1290
|
-
preview: extractPreview(row.payload)
|
|
1291
|
-
});
|
|
1256
|
+
const recentEvents = (() => {
|
|
1257
|
+
if (!deps.diagnosticLog) return [];
|
|
1258
|
+
try {
|
|
1259
|
+
return deps.diagnosticLog.queryProcessed({
|
|
1260
|
+
channelId: ch.id,
|
|
1261
|
+
limit: 10
|
|
1262
|
+
}).map(diagnosticEventOfProcessed);
|
|
1263
|
+
} catch {
|
|
1264
|
+
return [];
|
|
1292
1265
|
}
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
})();
|
|
1306
|
-
if (!(errRows instanceof Error)) for (const row of [...errRows].reverse()) connectionErrors.push({
|
|
1307
|
-
ts: typeof row.ts === "number" ? row.ts : null,
|
|
1308
|
-
type: typeof row.type === "string" ? row.type : "?",
|
|
1309
|
-
status: typeof row.status === "string" ? row.status : "?",
|
|
1310
|
-
detail: typeof row.detail === "string" && row.detail.length > 0 ? row.detail : null
|
|
1311
|
-
});
|
|
1266
|
+
})();
|
|
1267
|
+
const needsConnErrors = listener && (!listener.alive || listener.errors > 0) || !listener;
|
|
1268
|
+
const connectionErrors = (() => {
|
|
1269
|
+
if (!needsConnErrors || !deps.diagnosticLog) return [];
|
|
1270
|
+
try {
|
|
1271
|
+
return deps.diagnosticLog.queryConnection({
|
|
1272
|
+
channelId: ch.id,
|
|
1273
|
+
statuses: ["auth-failed", "error"],
|
|
1274
|
+
limit: 3
|
|
1275
|
+
}).map(diagnosticConnectionEventOf);
|
|
1276
|
+
} catch {
|
|
1277
|
+
return [];
|
|
1312
1278
|
}
|
|
1313
|
-
}
|
|
1279
|
+
})();
|
|
1314
1280
|
const base = {
|
|
1315
1281
|
id: ch.id,
|
|
1316
1282
|
name: ch.name,
|
|
@@ -1410,15 +1376,26 @@ function buildGatewayRoutes() {
|
|
|
1410
1376
|
}
|
|
1411
1377
|
const gatewayRoutes = buildGatewayRoutes();
|
|
1412
1378
|
//#endregion
|
|
1379
|
+
//#region lib/gateway/default-event-db-path.ts
|
|
1380
|
+
/**
|
|
1381
|
+
* Gives each durable gateway endpoint its own replay database. Port zero is
|
|
1382
|
+
* ephemeral, so each construction receives a fresh scope instead of pretending
|
|
1383
|
+
* that replay can survive a restart onto a different assigned port.
|
|
1384
|
+
*/
|
|
1385
|
+
function defaultEventDbPath(props) {
|
|
1386
|
+
const endpoint = props.port === 0 ? randomUUID() : String(props.port);
|
|
1387
|
+
const scope = createHash("sha256").update(`${props.funnelDir}\0${endpoint}`).digest("hex").slice(0, 20);
|
|
1388
|
+
return join(props.tmpDir, "events", `${scope}.db`);
|
|
1389
|
+
}
|
|
1390
|
+
//#endregion
|
|
1413
1391
|
//#region lib/gateway/gateway-server.ts
|
|
1414
1392
|
const DEFAULT_HOST = "127.0.0.1";
|
|
1415
|
-
const LOOPBACK_HOSTS = new Set([
|
|
1393
|
+
const LOOPBACK_HOSTS = /* @__PURE__ */ new Set([
|
|
1416
1394
|
"127.0.0.1",
|
|
1417
1395
|
"localhost",
|
|
1418
1396
|
"::1",
|
|
1419
1397
|
"::ffff:127.0.0.1"
|
|
1420
1398
|
]);
|
|
1421
|
-
const defaultDbPath = () => join(funnelTmpDir(), "events.db");
|
|
1422
1399
|
const defaultOnError = () => {};
|
|
1423
1400
|
/**
|
|
1424
1401
|
* In-process gateway: runs `Bun.serve` (HTTP + WebSocket /ws), boots connector
|
|
@@ -1449,6 +1426,7 @@ var FunnelGatewayServer = class {
|
|
|
1449
1426
|
nowMs;
|
|
1450
1427
|
extraRoutes;
|
|
1451
1428
|
ownsEventLog;
|
|
1429
|
+
diagnosticLog;
|
|
1452
1430
|
startedAt = null;
|
|
1453
1431
|
server = null;
|
|
1454
1432
|
disposed = false;
|
|
@@ -1456,16 +1434,21 @@ var FunnelGatewayServer = class {
|
|
|
1456
1434
|
this.channels = deps.channels;
|
|
1457
1435
|
this.configuredPort = deps.port ?? resolveFunnelPort();
|
|
1458
1436
|
this.configuredHostname = deps.hostname ?? DEFAULT_HOST;
|
|
1459
|
-
this.
|
|
1437
|
+
this.dir = deps.dir ?? FUNNEL_DIR;
|
|
1438
|
+
this.dbPath = deps.dbPath ?? defaultEventDbPath({
|
|
1439
|
+
tmpDir: deps.tmpDir ?? funnelTmpDir(),
|
|
1440
|
+
funnelDir: this.dir,
|
|
1441
|
+
port: this.configuredPort
|
|
1442
|
+
});
|
|
1460
1443
|
this.process = deps.process;
|
|
1461
1444
|
this.logger = deps.logger;
|
|
1462
1445
|
this.onError = deps.onError ?? defaultOnError;
|
|
1463
1446
|
this.selfPid = deps.selfPid ?? globalThis.process.pid;
|
|
1464
|
-
this.dir = deps.dir ?? FUNNEL_DIR;
|
|
1465
1447
|
this.killCompetingSlack = deps.killCompetingSlack ?? true;
|
|
1466
1448
|
this.token = deps.token ?? "";
|
|
1467
1449
|
this.allowInsecureHost = deps.allowInsecureHost ?? false;
|
|
1468
1450
|
this.extraRoutes = deps.extraRoutes ?? null;
|
|
1451
|
+
this.diagnosticLog = deps.diagnosticLog;
|
|
1469
1452
|
const clock = deps.clock;
|
|
1470
1453
|
this.nowMs = clock ? () => clock.millis() : () => Date.now();
|
|
1471
1454
|
if (deps.eventLog) {
|
|
@@ -1658,7 +1641,8 @@ var FunnelGatewayServer = class {
|
|
|
1658
1641
|
registry: this.registry,
|
|
1659
1642
|
channels: this.channels,
|
|
1660
1643
|
uptimeMs: () => this.startedAt ? this.nowMs() - this.startedAt : 0,
|
|
1661
|
-
emit: (input) => this.emit(input)
|
|
1644
|
+
emit: (input) => this.emit(input),
|
|
1645
|
+
diagnosticLog: this.diagnosticLog
|
|
1662
1646
|
});
|
|
1663
1647
|
return next();
|
|
1664
1648
|
});
|
|
@@ -1923,7 +1907,7 @@ var SqliteConnectorDiagnosticLog = class extends ConnectorDiagnosticLog {
|
|
|
1923
1907
|
...ageCap,
|
|
1924
1908
|
...rawMax !== void 0 ? { maxRows: rawMax } : {}
|
|
1925
1909
|
};
|
|
1926
|
-
this.raw = new
|
|
1910
|
+
this.raw = new SqliteEventLog({
|
|
1927
1911
|
path: props.rawPath,
|
|
1928
1912
|
indexes: [
|
|
1929
1913
|
"event_id",
|
|
@@ -1937,7 +1921,7 @@ var SqliteConnectorDiagnosticLog = class extends ConnectorDiagnosticLog {
|
|
|
1937
1921
|
}),
|
|
1938
1922
|
...rawCap
|
|
1939
1923
|
});
|
|
1940
|
-
this.processed = new
|
|
1924
|
+
this.processed = new SqliteEventLog({
|
|
1941
1925
|
path: props.processedPath,
|
|
1942
1926
|
indexes: [
|
|
1943
1927
|
"event_id",
|
|
@@ -1953,7 +1937,7 @@ var SqliteConnectorDiagnosticLog = class extends ConnectorDiagnosticLog {
|
|
|
1953
1937
|
}),
|
|
1954
1938
|
...verdictCap
|
|
1955
1939
|
});
|
|
1956
|
-
this.connection = new
|
|
1940
|
+
this.connection = new SqliteEventLog({
|
|
1957
1941
|
path: props.connectionPath,
|
|
1958
1942
|
indexes: [
|
|
1959
1943
|
"connector_id",
|
|
@@ -2019,10 +2003,13 @@ var SqliteConnectorDiagnosticLog = class extends ConnectorDiagnosticLog {
|
|
|
2019
2003
|
});
|
|
2020
2004
|
}
|
|
2021
2005
|
queryRaw(query) {
|
|
2006
|
+
const where = buildWhere(query);
|
|
2007
|
+
if (query.eventId !== void 0) where.event_id = query.eventId;
|
|
2022
2008
|
return this.raw.query({
|
|
2023
2009
|
...query.type !== void 0 ? { type: query.type } : {},
|
|
2010
|
+
...query.seq !== void 0 ? { seq: query.seq } : {},
|
|
2024
2011
|
...query.limit !== void 0 ? { limit: query.limit } : {},
|
|
2025
|
-
where
|
|
2012
|
+
where,
|
|
2026
2013
|
order: "desc"
|
|
2027
2014
|
}).map((record) => ({
|
|
2028
2015
|
seq: record.seq,
|
|
@@ -2036,11 +2023,14 @@ var SqliteConnectorDiagnosticLog = class extends ConnectorDiagnosticLog {
|
|
|
2036
2023
|
}
|
|
2037
2024
|
queryProcessed(query) {
|
|
2038
2025
|
const where = buildWhere(query);
|
|
2026
|
+
if (query.eventId !== void 0) where.event_id = query.eventId;
|
|
2039
2027
|
if (query.outcome !== void 0) where.outcome = query.outcome;
|
|
2040
2028
|
return this.processed.query({
|
|
2041
2029
|
...query.type !== void 0 ? { type: query.type } : {},
|
|
2030
|
+
...query.seq !== void 0 ? { seq: query.seq } : {},
|
|
2042
2031
|
...query.limit !== void 0 ? { limit: query.limit } : {},
|
|
2043
2032
|
where,
|
|
2033
|
+
...query.outcomePrefix !== void 0 ? { wherePrefix: { outcome: query.outcomePrefix } } : {},
|
|
2044
2034
|
order: "desc"
|
|
2045
2035
|
}).map((record) => ({
|
|
2046
2036
|
seq: record.seq,
|
|
@@ -2058,8 +2048,10 @@ var SqliteConnectorDiagnosticLog = class extends ConnectorDiagnosticLog {
|
|
|
2058
2048
|
if (query.status !== void 0) where.status = query.status;
|
|
2059
2049
|
return this.connection.query({
|
|
2060
2050
|
...query.type !== void 0 ? { type: query.type } : {},
|
|
2051
|
+
...query.seq !== void 0 ? { seq: query.seq } : {},
|
|
2061
2052
|
...query.limit !== void 0 ? { limit: query.limit } : {},
|
|
2062
2053
|
where,
|
|
2054
|
+
...query.statuses !== void 0 ? { whereIn: { status: query.statuses } } : {},
|
|
2063
2055
|
order: "desc"
|
|
2064
2056
|
}).map((record) => ({
|
|
2065
2057
|
seq: record.seq,
|