@interactive-inc/claude-funnel 0.60.1 → 0.64.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 +2 -2
- package/dist/bin.js +428 -761
- package/dist/{channels-2g_BU1N0.d.ts → channels-CRGb6B5_.d.ts} +17 -16
- package/dist/claude.d.ts +5 -7
- package/dist/claude.js +143 -36
- package/dist/{connector-descriptor-6SXJoszo.d.ts → connector-descriptor-BFIhyTfa.d.ts} +49 -10
- package/dist/connector-diagnostics-recorder-COtNEmUp.js +42 -0
- package/dist/connectors/discord.d.ts +31 -37
- package/dist/connectors/discord.js +3 -3
- package/dist/connectors/gh.d.ts +37 -33
- package/dist/connectors/gh.js +3 -3
- package/dist/connectors/schedule.d.ts +9 -57
- package/dist/connectors/schedule.js +3 -3
- package/dist/connectors/slack.d.ts +106 -132
- package/dist/connectors/slack.js +4 -3
- package/dist/diagnostics.d.ts +1 -1
- package/dist/diagnostics.js +1 -1
- package/dist/discord-connector-DIFkYBbi.js +250 -0
- package/dist/discord-connector-schema-D-bOVAKt.d.ts +22 -0
- package/dist/docs.js +1 -1
- package/dist/doctor.d.ts +1 -1
- package/dist/doctor.js +1 -1
- package/dist/{file-process-guard-C_PLxfUX.d.ts → file-process-guard-tVcgckH6.d.ts} +6 -6
- package/dist/{file-system-o51IsM0W.d.ts → file-system-VhwwXZbm.d.ts} +8 -0
- package/dist/flume-source-listener-BNyAII7N.d.ts +133 -0
- package/dist/{funnel-diagnostics-CSiJmPlZ.js → funnel-diagnostics-Cvk6Sk4x.js} +193 -43
- package/dist/{funnel-diagnostics-DpXOsCty.d.ts → funnel-diagnostics-b9ar0Ing.d.ts} +67 -5
- package/dist/{funnel-docs-BxXZ9Ksx.js → funnel-docs-C-ge0MuB.js} +42 -6
- package/dist/{funnel-doctor-CZf_0Luq.d.ts → funnel-doctor-CnRQi4kM.d.ts} +2 -2
- package/dist/{funnel-doctor-DiJCjHsg.js → funnel-doctor-XrI2GBH8.js} +1 -1
- package/dist/funnel-error-0t1MK1R6.js +75 -0
- package/dist/{funnel-recovery-DnLrdWO9.d.ts → funnel-recovery-CMhY8Jfk.d.ts} +1 -1
- package/dist/gateway/daemon.js +167 -527
- package/dist/gateway.d.ts +3 -3
- package/dist/gateway.js +3 -3
- package/dist/gh-connector-BUGCOEWS.js +187 -0
- package/dist/{gh-connector-schema-Rzwc1c1N.js → gh-connector-schema-CAqIhzGr.js} +7 -0
- package/dist/gh-connector-schema-DWQaB6gX.d.ts +16 -0
- package/dist/{index-CgY8NdMz.d.ts → index-Ds6sHhA-.d.ts} +37 -19
- package/dist/index.d.ts +182 -22
- package/dist/index.js +363 -173
- package/dist/{local-config-json-schema-JyLqOQNX.js → local-config-json-schema-DexV8vX3.js} +24 -4
- package/dist/local-config.d.ts +39 -2
- package/dist/local-config.js +53 -2
- package/dist/logger.js +1 -1
- package/dist/loopback-fetch-CVNuN3YZ.js +40 -0
- package/dist/{local-config-sync-Dh1Croqe.d.ts → memory-token-prompter-BoV8Hf-n.d.ts} +30 -3
- package/dist/node-file-system-BOXIHW_Q.js +174 -0
- package/dist/{profiles-DSzTeKQw.js → profiles-ZHLONml4.js} +49 -49
- package/dist/{profiles-Cy5wXQ0L.d.ts → profiles-cVZQkM69.d.ts} +3 -3
- 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/resolve-connector-token-DxDG9mhf.js +22 -0
- package/dist/{schedule-connector-L4uzg5M8.js → schedule-connector-9k3gOIgl.js} +54 -55
- package/dist/schedule-connector-schema-Z0RXLgPI.d.ts +49 -0
- package/dist/settings-reader-BNxjsxCB.d.ts +27 -0
- package/dist/{settings-store-CUKSeTXC.js → settings-store-C2QdOH-t.js} +23 -4
- package/dist/slack-connector-CxpWagbT.js +388 -0
- package/dist/slack-event-processor-BhCf5Wiy.d.ts +95 -0
- package/dist/slack-event-processor-xFDG3US0.js +176 -0
- package/dist/slot-fields-D-pvMgTK.js +249 -0
- package/dist/{memory-diagnostic-log-CI60kNfB.js → sqlite-diagnostic-log-DOTPW-tG.js} +373 -249
- package/dist/{yaml-render-93pX7EF7.js → yaml-render--J1_3BSA.js} +25 -21
- package/package.json +2 -4
- package/dist/discord-connector-BL36yvbL.js +0 -250
- package/dist/gateway-base-url-Dy4Ykuoh.js +0 -14
- package/dist/gh-connector-DpiixfQZ.js +0 -226
- package/dist/http-client-oICicjuO.d.ts +0 -18
- package/dist/memory-token-prompter-B4sjyaAq.d.ts +0 -57
- package/dist/memory-token-prompter-CZde7e6y.js +0 -61
- package/dist/node-file-system-Blr8pAir.js +0 -48
- package/dist/settings-reader-BIFB_j2f.d.ts +0 -18
- package/dist/slack-connector-DQIFPdBF.js +0 -484
- package/dist/slot-fields-CMoRpwuy.js +0 -45
- /package/dist/{connector-adapter-DU9Rvyec.js → connector-adapter-Dvs8N7ew.js} +0 -0
- /package/dist/{connector-listener-DR3aKOuK.js → connector-listener-mPGZYa8e.js} +0 -0
- /package/dist/{diagnostic-sql-reader-C9zR-Csp.js → diagnostic-sql-reader-oXZnWFf_.js} +0 -0
- /package/dist/{discord-connector-schema-B_N6IXLz.js → discord-connector-schema-B4YpWpR3.js} +0 -0
- /package/dist/{error-message-of-Byi4y0Uf.js → error-message-of-ColuYmAk.js} +0 -0
- /package/dist/{funnel-log-sqlite-sink-kqJbx2H7.js → funnel-log-sqlite-sink-DLYkY0pZ.js} +0 -0
- /package/dist/{funnel-recovery-BFdPjL6Z.js → funnel-recovery-DKnEutUS.js} +0 -0
- /package/dist/{node-http-client-lowp60Oa.js → node-http-client-u00atiKx.js} +0 -0
- /package/dist/{schedule-connector-schema-CfyuMCMh.js → schedule-connector-schema-DKEPZnVv.js} +0 -0
- /package/dist/{settings-reader-CtQ-Ix8_.js → settings-reader-9FcX3qS1.js} +0 -0
- /package/dist/{settings-schema-D1xcOqRu.d.ts → settings-schema-BL_c2Udm.d.ts} +0 -0
- /package/dist/{slack-connector-schema-C1zEf4TG.js → slack-connector-schema-Dem8to4P.js} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,23 +1,28 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as gatewayLoopbackUrl, t as loopbackFetch } from "./loopback-fetch-CVNuN3YZ.js";
|
|
2
2
|
import { t as FunnelFileSystem } from "./file-system-Wvzc2ePY.js";
|
|
3
|
-
import { t as NodeFunnelFileSystem } from "./node-file-system-
|
|
3
|
+
import { t as NodeFunnelFileSystem } from "./node-file-system-BOXIHW_Q.js";
|
|
4
4
|
import { t as FunnelLogger } from "./logger-B6iyNbxM.js";
|
|
5
5
|
import { n as FunnelProcessRunner, t as NodeFunnelProcessRunner } from "./node-process-runner-DxTvycoK.js";
|
|
6
|
-
import { n as
|
|
7
|
-
import {
|
|
8
|
-
import { a as
|
|
9
|
-
import { a as
|
|
10
|
-
import { t as
|
|
11
|
-
import { t as
|
|
12
|
-
import { t as
|
|
13
|
-
import {
|
|
14
|
-
import { t as
|
|
15
|
-
import { t as
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import { t as
|
|
19
|
-
import { t as
|
|
20
|
-
import {
|
|
6
|
+
import { n as FunnelHttpClient, t as NodeFunnelHttpClient } from "./node-http-client-u00atiKx.js";
|
|
7
|
+
import { n as FunnelIdGenerator, t as FunnelSettingsReader } from "./settings-reader-9FcX3qS1.js";
|
|
8
|
+
import { a as resolveFunnelDir, c as channelConfigSchema, d as settingsSchema, f as baseConnectorConfigSchema, i as SETTINGS_PATH, l as channelDeliveryModeSchema, n as FUNNEL_DIR, o as resolveFunnelPort, p as NodeFunnelIdGenerator, r as FunnelSettingsStore, s as SETTINGS_VERSION, t as DEFAULT_GATEWAY_PORT, u as profileConfigSchema } from "./settings-store-C2QdOH-t.js";
|
|
9
|
+
import { a as FunnelConnectorTypeMismatchError, c as FunnelTokenCollisionError, i as FunnelConnectorNotFoundError, n as FunnelChannelAlreadyExistsError, o as FunnelError, r as FunnelChannelNotFoundError, s as FunnelGatewayBindError, t as FunnelAuthFailedError } from "./funnel-error-0t1MK1R6.js";
|
|
10
|
+
import { a as FunnelMcp, o as FunnelFileProcessGuard, s as FunnelClaude, t as renderYaml } from "./yaml-render--J1_3BSA.js";
|
|
11
|
+
import { a as toDiagnosticEvent, i as toDiagnosticConnectionError, n as previewOf, r as queryRows, t as FunnelDiagnostics } from "./funnel-diagnostics-Cvk6Sk4x.js";
|
|
12
|
+
import { t as ConnectorDiagnosticSqlReader } from "./diagnostic-sql-reader-oXZnWFf_.js";
|
|
13
|
+
import { t as FunnelDoctor } from "./funnel-doctor-XrI2GBH8.js";
|
|
14
|
+
import { t as FunnelDocs } from "./funnel-docs-C-ge0MuB.js";
|
|
15
|
+
import { a as FunnelTokenPrompter, i as FunnelLocalConfigSync, n as MemoryFunnelTokenPrompter, o as FunnelLocalConfig, r as NodeFunnelTokenPrompter, t as funnelJsonSchema } from "./local-config-json-schema-DexV8vX3.js";
|
|
16
|
+
import { t as discordConnectorSchema } from "./discord-connector-schema-B4YpWpR3.js";
|
|
17
|
+
import { t as ghConnectorSchema } from "./gh-connector-schema-CAqIhzGr.js";
|
|
18
|
+
import { t as slackConnectorSchema } from "./slack-connector-schema-Dem8to4P.js";
|
|
19
|
+
import { t as FunnelProfiles } from "./profiles-ZHLONml4.js";
|
|
20
|
+
import { t as FunnelRecovery } from "./funnel-recovery-DKnEutUS.js";
|
|
21
|
+
import { C as funnelTmpDir, S as connectorRawEventSchema, _ as MemoryConnectorDiagnosticLog, a as DEFAULT_GATEWAY_TOKEN_PATH, b as connectorConnectionEventSchema, c as FunnelListenerRegistry, d as funnelEventSchema, f as FunnelBroadcaster, g as publishResponseSchema, h as publishRequestSchema, i as channelWsUrl, l as SqliteFunnelEventLog, m as FunnelChannelPublisher, n as MemoryFunnelEventLog, o as FunnelGatewayToken, p as requireBearerToken, r as channelWsProtocols, s as FunnelGatewayServer, t as SqliteConnectorDiagnosticLog, u as FunnelEventLog, v as CONNECTOR_CONNECTION_STATUSES, x as connectorProcessedEventSchema, y as ConnectorDiagnosticLog } from "./sqlite-diagnostic-log-DOTPW-tG.js";
|
|
22
|
+
import { t as FunnelConnectorAdapter } from "./connector-adapter-Dvs8N7ew.js";
|
|
23
|
+
import { t as FunnelConnectorListener } from "./connector-listener-mPGZYa8e.js";
|
|
24
|
+
import { t as FunnelSlackEventProcessor } from "./slack-event-processor-xFDG3US0.js";
|
|
25
|
+
import { n as scheduleConnectorSchema, r as scheduleEntrySchema, t as scheduleCatchupPolicySchema } from "./schedule-connector-schema-DKEPZnVv.js";
|
|
21
26
|
import { dirname, join, resolve } from "node:path";
|
|
22
27
|
import { hc } from "hono/client";
|
|
23
28
|
import { appendFileSync, existsSync, mkdirSync } from "node:fs";
|
|
@@ -27,9 +32,32 @@ import { createFactory } from "hono/factory";
|
|
|
27
32
|
import { HTTPException } from "hono/http-exception";
|
|
28
33
|
import { zValidator } from "@hono/zod-validator";
|
|
29
34
|
import { Hono } from "hono";
|
|
35
|
+
//#region lib/engine/time/clock.ts
|
|
36
|
+
/**
|
|
37
|
+
* Time boundary. Default NodeFunnelClock returns `new Date()`; MemoryFunnelClock
|
|
38
|
+
* is settable and `advance(ms)`-able for deterministic schedule / timeout tests.
|
|
39
|
+
*/
|
|
40
|
+
var FunnelClock = class {
|
|
41
|
+
millis() {
|
|
42
|
+
return this.now().getTime();
|
|
43
|
+
}
|
|
44
|
+
iso() {
|
|
45
|
+
return this.now().toISOString();
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region lib/engine/time/node-clock.ts
|
|
50
|
+
var NodeFunnelClock = class extends FunnelClock {
|
|
51
|
+
now() {
|
|
52
|
+
return /* @__PURE__ */ new Date();
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
//#endregion
|
|
30
56
|
//#region lib/engine/connectors/connector-registry.ts
|
|
31
57
|
const defaultFs$1 = new NodeFunnelFileSystem();
|
|
32
58
|
const defaultProcess$1 = new NodeFunnelProcessRunner();
|
|
59
|
+
const defaultHttp = new NodeFunnelHttpClient();
|
|
60
|
+
const defaultClock$2 = new NodeFunnelClock();
|
|
33
61
|
/**
|
|
34
62
|
* Dispatches connector work to injected descriptors by `type`. Replaces the old
|
|
35
63
|
* hard-coded factory: core never imports a concrete connector, so listener and
|
|
@@ -43,15 +71,21 @@ var FunnelConnectorRegistry = class {
|
|
|
43
71
|
descriptors;
|
|
44
72
|
fs;
|
|
45
73
|
process;
|
|
74
|
+
http;
|
|
75
|
+
clock;
|
|
46
76
|
logger;
|
|
47
77
|
diagnosticLog;
|
|
78
|
+
signal;
|
|
48
79
|
dir;
|
|
49
80
|
constructor(deps) {
|
|
50
81
|
this.descriptors = new Map(deps.descriptors.map((descriptor) => [descriptor.type, descriptor]));
|
|
51
82
|
this.fs = deps.fs ?? defaultFs$1;
|
|
52
83
|
this.process = deps.process ?? defaultProcess$1;
|
|
84
|
+
this.http = deps.http ?? defaultHttp;
|
|
85
|
+
this.clock = deps.clock ?? defaultClock$2;
|
|
53
86
|
this.logger = deps.logger;
|
|
54
87
|
this.diagnosticLog = deps.diagnosticLog;
|
|
88
|
+
this.signal = deps.signal;
|
|
55
89
|
this.dir = deps.dir ?? FUNNEL_DIR;
|
|
56
90
|
Object.freeze(this);
|
|
57
91
|
}
|
|
@@ -104,8 +138,11 @@ var FunnelConnectorRegistry = class {
|
|
|
104
138
|
channelId,
|
|
105
139
|
fs: this.fs,
|
|
106
140
|
process: this.process,
|
|
141
|
+
http: this.http,
|
|
142
|
+
clock: this.clock,
|
|
107
143
|
logger: this.logger,
|
|
108
144
|
diagnosticLog: this.diagnosticLog,
|
|
145
|
+
signal: this.signal,
|
|
109
146
|
connectorDir: (channel, connector) => this.connectorDir(channel, connector)
|
|
110
147
|
};
|
|
111
148
|
}
|
|
@@ -113,32 +150,12 @@ var FunnelConnectorRegistry = class {
|
|
|
113
150
|
return {
|
|
114
151
|
fs: this.fs,
|
|
115
152
|
process: this.process,
|
|
153
|
+
http: this.http,
|
|
116
154
|
logger: this.logger
|
|
117
155
|
};
|
|
118
156
|
}
|
|
119
157
|
};
|
|
120
158
|
//#endregion
|
|
121
|
-
//#region lib/engine/time/clock.ts
|
|
122
|
-
/**
|
|
123
|
-
* Time boundary. Default NodeFunnelClock returns `new Date()`; MemoryFunnelClock
|
|
124
|
-
* is settable and `advance(ms)`-able for deterministic schedule / timeout tests.
|
|
125
|
-
*/
|
|
126
|
-
var FunnelClock = class {
|
|
127
|
-
millis() {
|
|
128
|
-
return this.now().getTime();
|
|
129
|
-
}
|
|
130
|
-
iso() {
|
|
131
|
-
return this.now().toISOString();
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
//#endregion
|
|
135
|
-
//#region lib/engine/time/node-clock.ts
|
|
136
|
-
var NodeFunnelClock = class extends FunnelClock {
|
|
137
|
-
now() {
|
|
138
|
-
return /* @__PURE__ */ new Date();
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
|
-
//#endregion
|
|
142
159
|
//#region lib/engine/channels/channels.ts
|
|
143
160
|
const defaultClock$1 = new NodeFunnelClock();
|
|
144
161
|
const defaultIdGenerator = new NodeFunnelIdGenerator();
|
|
@@ -178,40 +195,40 @@ var FunnelChannels = class {
|
|
|
178
195
|
return this.list().find((c) => c.id === id) ?? null;
|
|
179
196
|
}
|
|
180
197
|
add(input) {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
198
|
+
return this.store.update((settings) => {
|
|
199
|
+
if (settings.channels.some((c) => c.name === input.name)) throw new FunnelChannelAlreadyExistsError(input.name);
|
|
200
|
+
const channel = {
|
|
201
|
+
id: this.idGenerator.generate(),
|
|
202
|
+
name: input.name,
|
|
203
|
+
delivery: input.delivery ?? "fanout",
|
|
204
|
+
connectors: []
|
|
205
|
+
};
|
|
206
|
+
settings.channels.push(channel);
|
|
207
|
+
return channel;
|
|
208
|
+
});
|
|
192
209
|
}
|
|
193
210
|
setDelivery(name, delivery) {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
211
|
+
this.store.update((settings) => {
|
|
212
|
+
const channel = this.requireChannel(settings, name);
|
|
213
|
+
channel.delivery = delivery;
|
|
214
|
+
});
|
|
198
215
|
}
|
|
199
216
|
remove(name) {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
217
|
+
this.store.update((settings) => {
|
|
218
|
+
const index = settings.channels.findIndex((c) => c.name === name);
|
|
219
|
+
if (index < 0) throw new FunnelChannelNotFoundError(name);
|
|
220
|
+
const channel = settings.channels[index];
|
|
221
|
+
if (channel && this.profileChecker?.hasChannelRef(channel.id)) throw new Error(`channel "${name}" is referenced by a profile`);
|
|
222
|
+
settings.channels.splice(index, 1);
|
|
223
|
+
});
|
|
207
224
|
}
|
|
208
225
|
rename(oldName, newName) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
226
|
+
this.store.update((settings) => {
|
|
227
|
+
const channel = settings.channels.find((c) => c.name === oldName);
|
|
228
|
+
if (!channel) throw new FunnelChannelNotFoundError(oldName);
|
|
229
|
+
if (settings.channels.some((c) => c.name === newName)) throw new FunnelChannelAlreadyExistsError(newName);
|
|
230
|
+
channel.name = newName;
|
|
231
|
+
});
|
|
215
232
|
}
|
|
216
233
|
listConnectors(channelName) {
|
|
217
234
|
return this.requireChannel(this.store.read(), channelName).connectors;
|
|
@@ -231,35 +248,35 @@ var FunnelChannels = class {
|
|
|
231
248
|
return out;
|
|
232
249
|
}
|
|
233
250
|
addConnector(channelName, input) {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
251
|
+
return this.store.update((settings) => {
|
|
252
|
+
const channel = this.requireChannel(settings, channelName);
|
|
253
|
+
if (channel.connectors.some((c) => c.name === input.name)) throw new Error(`connector "${input.name}" already exists in channel "${channelName}"`);
|
|
254
|
+
const candidate = this.registry.buildConfig(input, {
|
|
255
|
+
id: this.idGenerator.generate(),
|
|
256
|
+
now: this.clock.iso()
|
|
257
|
+
});
|
|
258
|
+
this.assertNoTokenCollision(settings, candidate);
|
|
259
|
+
channel.connectors.push(candidate);
|
|
260
|
+
return candidate;
|
|
240
261
|
});
|
|
241
|
-
this.assertNoTokenCollision(settings, candidate);
|
|
242
|
-
channel.connectors.push(candidate);
|
|
243
|
-
this.store.write(settings);
|
|
244
|
-
return candidate;
|
|
245
262
|
}
|
|
246
263
|
removeConnector(channelName, connectorName) {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
264
|
+
this.store.update((settings) => {
|
|
265
|
+
const channel = this.requireChannel(settings, channelName);
|
|
266
|
+
const index = channel.connectors.findIndex((c) => c.name === connectorName);
|
|
267
|
+
if (index < 0) throw new FunnelConnectorNotFoundError(channelName, connectorName);
|
|
268
|
+
channel.connectors.splice(index, 1);
|
|
269
|
+
});
|
|
253
270
|
}
|
|
254
271
|
renameConnector(channelName, oldName, newName) {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
272
|
+
this.store.update((settings) => {
|
|
273
|
+
const channel = this.requireChannel(settings, channelName);
|
|
274
|
+
const connector = channel.connectors.find((c) => c.name === oldName);
|
|
275
|
+
if (!connector) throw new Error(`connector "${oldName}" not found in channel "${channelName}"`);
|
|
276
|
+
if (channel.connectors.some((c) => c.name === newName)) throw new Error(`connector "${newName}" already exists in channel "${channelName}"`);
|
|
277
|
+
connector.name = newName;
|
|
278
|
+
connector.updatedAt = this.clock.iso();
|
|
279
|
+
});
|
|
263
280
|
}
|
|
264
281
|
/**
|
|
265
282
|
* Update a connector's mutable fields generically. The connector's descriptor
|
|
@@ -267,14 +284,14 @@ var FunnelChannels = class {
|
|
|
267
284
|
* so a slot can move between a literal and an env reference cleanly).
|
|
268
285
|
*/
|
|
269
286
|
updateConnector(channelName, connectorName, fields) {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
287
|
+
this.store.update((settings) => {
|
|
288
|
+
const channel = this.requireChannel(settings, channelName);
|
|
289
|
+
const connector = channel.connectors.find((c) => c.name === connectorName);
|
|
290
|
+
if (!connector) throw new FunnelConnectorNotFoundError(channelName, connectorName);
|
|
291
|
+
const updated = this.registry.applyUpdate(connector, fields, { now: this.clock.iso() });
|
|
292
|
+
this.assertNoTokenCollision(settings, updated);
|
|
293
|
+
this.replaceConnector(channel, connector.name, updated);
|
|
294
|
+
});
|
|
278
295
|
}
|
|
279
296
|
/** Back-compat wrapper for `updateConnector` on a slack connector. */
|
|
280
297
|
updateSlackConnector(channelName, connectorName, fields) {
|
|
@@ -294,23 +311,21 @@ var FunnelChannels = class {
|
|
|
294
311
|
* result; the config is persisted only when the operation actually mutated it.
|
|
295
312
|
*/
|
|
296
313
|
connectorOp(channelName, connectorName, operation, args) {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
314
|
+
return this.store.update((settings) => {
|
|
315
|
+
const channel = this.requireChannel(settings, channelName);
|
|
316
|
+
const connector = channel.connectors.find((c) => c.name === connectorName);
|
|
317
|
+
if (!connector) throw new FunnelConnectorNotFoundError(channelName, connectorName);
|
|
318
|
+
const outcome = this.registry.runOperation(connector, operation, args, {
|
|
319
|
+
generateId: () => this.idGenerator.generate(),
|
|
320
|
+
now: this.clock.iso()
|
|
321
|
+
});
|
|
322
|
+
if (outcome.config !== connector) this.replaceConnector(channel, connector.name, outcome.config);
|
|
323
|
+
return outcome.result;
|
|
304
324
|
});
|
|
305
|
-
if (outcome.config !== connector) {
|
|
306
|
-
this.replaceConnector(channel, connector.name, outcome.config);
|
|
307
|
-
this.store.write(settings);
|
|
308
|
-
}
|
|
309
|
-
return outcome.result;
|
|
310
325
|
}
|
|
311
326
|
async call(channelName, connectorName, input) {
|
|
312
327
|
const connector = this.getConnector(channelName, connectorName);
|
|
313
|
-
if (!connector) throw new
|
|
328
|
+
if (!connector) throw new FunnelConnectorNotFoundError(channelName, connectorName);
|
|
314
329
|
const adapter = this.registry.createAdapter(connector);
|
|
315
330
|
if (!adapter) throw new Error(`connector type "${connector.type}" does not support outbound calls`);
|
|
316
331
|
return await adapter.call(input);
|
|
@@ -338,7 +353,7 @@ var FunnelChannels = class {
|
|
|
338
353
|
}
|
|
339
354
|
requireChannel(settings, name) {
|
|
340
355
|
const channel = settings.channels.find((c) => c.name === name);
|
|
341
|
-
if (!channel) throw new
|
|
356
|
+
if (!channel) throw new FunnelChannelNotFoundError(name);
|
|
342
357
|
return channel;
|
|
343
358
|
}
|
|
344
359
|
replaceConnector(channel, connectorName, next) {
|
|
@@ -418,6 +433,9 @@ var MemoryFunnelFileSystem = class extends FunnelFileSystem {
|
|
|
418
433
|
mode: this.modes.get(path) ?? null
|
|
419
434
|
};
|
|
420
435
|
}
|
|
436
|
+
withFileLock(_lockPath, fn) {
|
|
437
|
+
return fn();
|
|
438
|
+
}
|
|
421
439
|
setMtime(path, mtimeMs) {
|
|
422
440
|
this.mtimes.set(path, mtimeMs);
|
|
423
441
|
}
|
|
@@ -602,6 +620,9 @@ var MockFunnelSettingsReader = class extends FunnelSettingsReader {
|
|
|
602
620
|
write(settings) {
|
|
603
621
|
this.state = settings;
|
|
604
622
|
}
|
|
623
|
+
update(mutator) {
|
|
624
|
+
return mutator(this.state);
|
|
625
|
+
}
|
|
605
626
|
};
|
|
606
627
|
//#endregion
|
|
607
628
|
//#region lib/engine/time/memory-clock.ts
|
|
@@ -622,6 +643,31 @@ var MemoryFunnelClock = class extends FunnelClock {
|
|
|
622
643
|
}
|
|
623
644
|
};
|
|
624
645
|
//#endregion
|
|
646
|
+
//#region lib/engine/http/memory-http-client.ts
|
|
647
|
+
var MemoryFunnelHttpClient = class extends FunnelHttpClient {
|
|
648
|
+
calls = [];
|
|
649
|
+
handler = () => ({
|
|
650
|
+
status: 200,
|
|
651
|
+
body: ""
|
|
652
|
+
});
|
|
653
|
+
on(handler) {
|
|
654
|
+
this.handler = handler;
|
|
655
|
+
return this;
|
|
656
|
+
}
|
|
657
|
+
async fetch(request) {
|
|
658
|
+
this.calls.push(request);
|
|
659
|
+
const response = await this.handler(request);
|
|
660
|
+
const status = response.status ?? 200;
|
|
661
|
+
const body = response.body ?? "";
|
|
662
|
+
return {
|
|
663
|
+
status,
|
|
664
|
+
ok: status >= 200 && status < 300,
|
|
665
|
+
text: async () => body,
|
|
666
|
+
json: async () => JSON.parse(body)
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
//#endregion
|
|
625
671
|
//#region lib/gateway/resolve-daemon-script.ts
|
|
626
672
|
/**
|
|
627
673
|
* Locate the daemon entry script. Works in both dev (running from source)
|
|
@@ -838,7 +884,7 @@ var FunnelListenersClient = class {
|
|
|
838
884
|
async list() {
|
|
839
885
|
if (!this.isDaemonRunning()) return { state: "offline" };
|
|
840
886
|
try {
|
|
841
|
-
const res = await
|
|
887
|
+
const res = await loopbackFetch(`${gatewayLoopbackUrl(this.port)}/listeners`, { headers: this.authHeaders() });
|
|
842
888
|
if (!res.ok) return {
|
|
843
889
|
state: "error",
|
|
844
890
|
reason: `HTTP ${res.status}`
|
|
@@ -880,12 +926,18 @@ var FunnelListenersClient = class {
|
|
|
880
926
|
}
|
|
881
927
|
async call(method, path) {
|
|
882
928
|
try {
|
|
883
|
-
const res = await
|
|
929
|
+
const res = await loopbackFetch(`${gatewayLoopbackUrl(this.port)}${path}`, {
|
|
884
930
|
method,
|
|
885
931
|
headers: this.authHeaders()
|
|
886
|
-
});
|
|
932
|
+
}, 3e4);
|
|
887
933
|
if (!res.ok) {
|
|
888
|
-
|
|
934
|
+
let body = null;
|
|
935
|
+
try {
|
|
936
|
+
body = await res.json();
|
|
937
|
+
} catch {
|
|
938
|
+
body = null;
|
|
939
|
+
}
|
|
940
|
+
const parsed = opErrorBodySchema.safeParse(body);
|
|
889
941
|
return {
|
|
890
942
|
state: "error",
|
|
891
943
|
reason: (parsed.success ? parsed.data.reason : void 0) ?? `HTTP ${res.status}`
|
|
@@ -944,6 +996,7 @@ var Funnel = class Funnel {
|
|
|
944
996
|
process;
|
|
945
997
|
logger;
|
|
946
998
|
clock;
|
|
999
|
+
http;
|
|
947
1000
|
onError;
|
|
948
1001
|
constructor(props = {}) {
|
|
949
1002
|
const dir = props.dir ?? resolveFunnelDir();
|
|
@@ -952,6 +1005,7 @@ var Funnel = class Funnel {
|
|
|
952
1005
|
const process = props.process ?? new NodeFunnelProcessRunner();
|
|
953
1006
|
const clock = props.clock ?? new NodeFunnelClock();
|
|
954
1007
|
const idGenerator = props.idGenerator ?? new NodeFunnelIdGenerator();
|
|
1008
|
+
const http = props.http ?? new NodeFunnelHttpClient();
|
|
955
1009
|
this.paths = {
|
|
956
1010
|
dir,
|
|
957
1011
|
tmpDir,
|
|
@@ -961,6 +1015,7 @@ var Funnel = class Funnel {
|
|
|
961
1015
|
this.process = process;
|
|
962
1016
|
this.logger = props.logger;
|
|
963
1017
|
this.clock = clock;
|
|
1018
|
+
this.http = http;
|
|
964
1019
|
this.onError = props.onError ?? noopOnError;
|
|
965
1020
|
const store = props.store ?? new FunnelSettingsStore({
|
|
966
1021
|
path: this.paths.settings,
|
|
@@ -971,8 +1026,11 @@ var Funnel = class Funnel {
|
|
|
971
1026
|
descriptors: props.connectors ?? [],
|
|
972
1027
|
fs,
|
|
973
1028
|
process,
|
|
1029
|
+
http,
|
|
1030
|
+
clock,
|
|
974
1031
|
logger: this.logger,
|
|
975
1032
|
diagnosticLog: props.diagnosticLog,
|
|
1033
|
+
signal: props.signal,
|
|
976
1034
|
dir
|
|
977
1035
|
});
|
|
978
1036
|
this.profiles = new FunnelProfiles({
|
|
@@ -1020,7 +1078,7 @@ var Funnel = class Funnel {
|
|
|
1020
1078
|
mcp,
|
|
1021
1079
|
gateway: this.gateway,
|
|
1022
1080
|
sessions: this.profiles,
|
|
1023
|
-
guard: new
|
|
1081
|
+
guard: new FunnelFileProcessGuard({
|
|
1024
1082
|
fs,
|
|
1025
1083
|
process,
|
|
1026
1084
|
dir
|
|
@@ -1049,9 +1107,20 @@ var Funnel = class Funnel {
|
|
|
1049
1107
|
Object.freeze(this);
|
|
1050
1108
|
}
|
|
1051
1109
|
/**
|
|
1052
|
-
* Sandboxed Funnel wired with in-memory implementations for every IO
|
|
1053
|
-
* Touches no real disk, processes, wall-clock time,
|
|
1054
|
-
*
|
|
1110
|
+
* Sandboxed Funnel wired with in-memory implementations for every IO
|
|
1111
|
+
* boundary. Touches no real disk, processes, wall-clock time, UUIDs, HTTP,
|
|
1112
|
+
* TTY prompts, or diagnostic SQLite — safe for tests and ad-hoc
|
|
1113
|
+
* experiments. Override individual fields by passing them in `props`.
|
|
1114
|
+
*
|
|
1115
|
+
* NOT covered by `inMemory()`:
|
|
1116
|
+
* - `gatewayServer()` still calls `Bun.serve` and binds a real port; use
|
|
1117
|
+
* `port: 0` to let the OS pick one. The WebSocket subscription path
|
|
1118
|
+
* also crosses the real socket.
|
|
1119
|
+
* - Flume sources opened by listeners (Slack Socket Mode, Discord
|
|
1120
|
+
* Gateway, GitHub poll) still open real WebSockets / HTTP. Pass
|
|
1121
|
+
* `flumeDeps` to the descriptor's options if a test needs them stubbed.
|
|
1122
|
+
* - `funnel.gateway` (daemon process) — `start()` still spawns a child
|
|
1123
|
+
* process; only the in-process `gatewayServer()` is sandbox-friendly.
|
|
1055
1124
|
*/
|
|
1056
1125
|
static inMemory(props = {}) {
|
|
1057
1126
|
return new Funnel({
|
|
@@ -1062,6 +1131,9 @@ var Funnel = class Funnel {
|
|
|
1062
1131
|
logger: props.logger ?? new MemoryFunnelLogger(),
|
|
1063
1132
|
clock: props.clock ?? new MemoryFunnelClock(),
|
|
1064
1133
|
idGenerator: props.idGenerator ?? new MemoryFunnelIdGenerator(),
|
|
1134
|
+
http: props.http ?? new MemoryFunnelHttpClient(),
|
|
1135
|
+
tokenPrompter: props.tokenPrompter ?? new MemoryFunnelTokenPrompter(),
|
|
1136
|
+
diagnosticLog: props.diagnosticLog ?? new MemoryConnectorDiagnosticLog(),
|
|
1065
1137
|
dir: props.dir ?? SANDBOX_DIR,
|
|
1066
1138
|
tmpDir: props.tmpDir ?? SANDBOX_TMP_DIR
|
|
1067
1139
|
});
|
|
@@ -1094,7 +1166,7 @@ var Funnel = class Funnel {
|
|
|
1094
1166
|
* independently of FunnelClaude (e.g. checking if a named profile is running).
|
|
1095
1167
|
*/
|
|
1096
1168
|
createProcessGuard() {
|
|
1097
|
-
return new
|
|
1169
|
+
return new FunnelFileProcessGuard({
|
|
1098
1170
|
fs: this.fs,
|
|
1099
1171
|
process: this.process,
|
|
1100
1172
|
dir: this.paths.dir
|
|
@@ -1182,31 +1254,6 @@ var NoopFunnelLogger = class extends FunnelLogger {
|
|
|
1182
1254
|
error() {}
|
|
1183
1255
|
};
|
|
1184
1256
|
//#endregion
|
|
1185
|
-
//#region lib/engine/http/memory-http-client.ts
|
|
1186
|
-
var MemoryFunnelHttpClient = class extends FunnelHttpClient {
|
|
1187
|
-
calls = [];
|
|
1188
|
-
handler = () => ({
|
|
1189
|
-
status: 200,
|
|
1190
|
-
body: ""
|
|
1191
|
-
});
|
|
1192
|
-
on(handler) {
|
|
1193
|
-
this.handler = handler;
|
|
1194
|
-
return this;
|
|
1195
|
-
}
|
|
1196
|
-
async fetch(request) {
|
|
1197
|
-
this.calls.push(request);
|
|
1198
|
-
const response = await this.handler(request);
|
|
1199
|
-
const status = response.status ?? 200;
|
|
1200
|
-
const body = response.body ?? "";
|
|
1201
|
-
return {
|
|
1202
|
-
status,
|
|
1203
|
-
ok: status >= 200 && status < 300,
|
|
1204
|
-
text: async () => body,
|
|
1205
|
-
json: async () => JSON.parse(body)
|
|
1206
|
-
};
|
|
1207
|
-
}
|
|
1208
|
-
};
|
|
1209
|
-
//#endregion
|
|
1210
1257
|
//#region lib/gateway/service-routes.ts
|
|
1211
1258
|
/**
|
|
1212
1259
|
* Mountable Hono app that exposes the service layer (`FunnelDiagnostics` +
|
|
@@ -1235,24 +1282,65 @@ const buildServiceRoutes = (deps) => {
|
|
|
1235
1282
|
});
|
|
1236
1283
|
app.get("/diagnostics/events", async (c) => {
|
|
1237
1284
|
const channel = c.req.query("channel") ?? null;
|
|
1285
|
+
const connector = c.req.query("connector");
|
|
1238
1286
|
const limit = Number(c.req.query("limit") ?? "20");
|
|
1239
|
-
const events = await deps.diagnostics.recentEvents(channel,
|
|
1287
|
+
const events = await deps.diagnostics.recentEvents(channel, {
|
|
1288
|
+
connector,
|
|
1289
|
+
limit
|
|
1290
|
+
});
|
|
1240
1291
|
return c.json(events);
|
|
1241
1292
|
});
|
|
1242
1293
|
app.get("/diagnostics/dropped", async (c) => {
|
|
1243
1294
|
const channel = c.req.query("channel") ?? null;
|
|
1295
|
+
const connector = c.req.query("connector");
|
|
1244
1296
|
const limit = Number(c.req.query("limit") ?? "20");
|
|
1245
|
-
const events = await deps.diagnostics.droppedEvents(channel,
|
|
1297
|
+
const events = await deps.diagnostics.droppedEvents(channel, {
|
|
1298
|
+
connector,
|
|
1299
|
+
limit
|
|
1300
|
+
});
|
|
1246
1301
|
return c.json(events);
|
|
1247
1302
|
});
|
|
1248
1303
|
app.get("/diagnostics/errors", async (c) => {
|
|
1249
1304
|
const channel = c.req.query("channel") ?? null;
|
|
1305
|
+
const connector = c.req.query("connector");
|
|
1250
1306
|
const limit = Number(c.req.query("limit") ?? "20");
|
|
1251
|
-
const errors = await deps.diagnostics.connectionErrors(channel,
|
|
1307
|
+
const errors = await deps.diagnostics.connectionErrors(channel, {
|
|
1308
|
+
connector,
|
|
1309
|
+
limit
|
|
1310
|
+
});
|
|
1252
1311
|
return c.json(errors);
|
|
1253
1312
|
});
|
|
1313
|
+
app.get("/diagnostics/raw", async (c) => {
|
|
1314
|
+
const channel = c.req.query("channel") ?? null;
|
|
1315
|
+
const connector = c.req.query("connector");
|
|
1316
|
+
const limit = Number(c.req.query("limit") ?? "20");
|
|
1317
|
+
const events = await deps.diagnostics.rawEvents(channel, {
|
|
1318
|
+
connector,
|
|
1319
|
+
limit
|
|
1320
|
+
});
|
|
1321
|
+
return c.json(events);
|
|
1322
|
+
});
|
|
1323
|
+
app.get("/diagnostics/connection", async (c) => {
|
|
1324
|
+
const channel = c.req.query("channel") ?? null;
|
|
1325
|
+
const connector = c.req.query("connector");
|
|
1326
|
+
const limit = Number(c.req.query("limit") ?? "20");
|
|
1327
|
+
const rows = await deps.diagnostics.connectionTimeline(channel, {
|
|
1328
|
+
connector,
|
|
1329
|
+
limit
|
|
1330
|
+
});
|
|
1331
|
+
return c.json(rows);
|
|
1332
|
+
});
|
|
1333
|
+
app.get("/diagnostics/logs", async (c) => {
|
|
1334
|
+
const grep = c.req.query("grep") ?? void 0;
|
|
1335
|
+
const limit = Number(c.req.query("limit") ?? "200");
|
|
1336
|
+
const result = await deps.diagnostics.recentLogs({
|
|
1337
|
+
grep,
|
|
1338
|
+
limit
|
|
1339
|
+
});
|
|
1340
|
+
return c.json(result);
|
|
1341
|
+
});
|
|
1254
1342
|
app.post("/diagnostics/replay", async (c) => {
|
|
1255
|
-
const body = await c
|
|
1343
|
+
const body = await readJsonBody(c);
|
|
1256
1344
|
const channel = typeof body.channel === "string" ? body.channel : null;
|
|
1257
1345
|
const seq = typeof body.seq === "number" ? body.seq : void 0;
|
|
1258
1346
|
if (!channel) return c.json({ error: "channel is required" }, 400);
|
|
@@ -1260,13 +1348,22 @@ const buildServiceRoutes = (deps) => {
|
|
|
1260
1348
|
return c.json(result);
|
|
1261
1349
|
});
|
|
1262
1350
|
app.post("/doctor", async (c) => {
|
|
1263
|
-
const body = await c
|
|
1351
|
+
const body = await readJsonBody(c);
|
|
1264
1352
|
const mode = body.mode === "safe" || body.mode === "aggressive" || body.mode === "off" ? body.mode : "off";
|
|
1265
1353
|
const report = await deps.doctor.run(mode);
|
|
1266
1354
|
return c.json(report);
|
|
1267
1355
|
});
|
|
1268
1356
|
return app;
|
|
1269
1357
|
};
|
|
1358
|
+
const isStringKeyedObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1359
|
+
const readJsonBody = async (c) => {
|
|
1360
|
+
try {
|
|
1361
|
+
const body = await c.req.json();
|
|
1362
|
+
return isStringKeyedObject(body) ? body : {};
|
|
1363
|
+
} catch {
|
|
1364
|
+
return {};
|
|
1365
|
+
}
|
|
1366
|
+
};
|
|
1270
1367
|
//#endregion
|
|
1271
1368
|
//#region lib/cli/factory.ts
|
|
1272
1369
|
const factory = createFactory();
|
|
@@ -1628,7 +1725,7 @@ const channelsConnectorsSetHandler = factory.createHandlers(zValidator$1("param"
|
|
|
1628
1725
|
"bot-token": z.string().optional(),
|
|
1629
1726
|
"app-token": z.string().optional(),
|
|
1630
1727
|
"poll-interval": z.coerce.number().int().positive().optional()
|
|
1631
|
-
}).
|
|
1728
|
+
}).loose()), async (c) => {
|
|
1632
1729
|
const param = c.req.valid("param");
|
|
1633
1730
|
const query = c.req.valid("query");
|
|
1634
1731
|
const funnel = c.env.funnel;
|
|
@@ -1720,7 +1817,7 @@ options:
|
|
|
1720
1817
|
output / valid YAML (or raw text when the adapter returns text)`), zValidator$1("query", z.object({
|
|
1721
1818
|
method: z.string(),
|
|
1722
1819
|
path: z.string().optional()
|
|
1723
|
-
}).
|
|
1820
|
+
}).loose()), async (c) => {
|
|
1724
1821
|
const param = c.req.valid("param");
|
|
1725
1822
|
const query = c.req.valid("query");
|
|
1726
1823
|
const funnel = c.env.funnel;
|
|
@@ -1841,7 +1938,7 @@ const channelsPublishHelpHandler = factory.createHandlers((c) => c.text(help$7))
|
|
|
1841
1938
|
const querySchema = z.object({
|
|
1842
1939
|
content: z.string().min(1, { message: "--content is required" }),
|
|
1843
1940
|
connector: z.string().min(1).optional()
|
|
1844
|
-
}).
|
|
1941
|
+
}).loose();
|
|
1845
1942
|
const channelsPublishHandler = factory.createHandlers(zValidator$1("param", z.object({ channel: z.string() })), zValidator$1("query", querySchema), async (c) => {
|
|
1846
1943
|
const param = c.req.valid("param");
|
|
1847
1944
|
const query = c.req.valid("query");
|
|
@@ -2144,7 +2241,7 @@ const RESERVED_KEYS$1 = ["profile", "channel"];
|
|
|
2144
2241
|
const claudeHandler = factory.createHandlers(helpGuard(claudeHelp), zValidator$1("query", z.object({
|
|
2145
2242
|
profile: z.string().optional(),
|
|
2146
2243
|
channel: z.string().optional()
|
|
2147
|
-
}).
|
|
2244
|
+
}).loose()), async (c) => {
|
|
2148
2245
|
const query = c.req.valid("query");
|
|
2149
2246
|
const { funnel, claude, profiles, localConfig, localConfigSync } = c.env;
|
|
2150
2247
|
const userArgs = queryToCliArgs(c.req.url, RESERVED_KEYS$1);
|
|
@@ -2205,35 +2302,41 @@ const claudeHandler = factory.createHandlers(helpGuard(claudeHelp), zValidator$1
|
|
|
2205
2302
|
});
|
|
2206
2303
|
//#endregion
|
|
2207
2304
|
//#region lib/cli/routes/debug.ts
|
|
2208
|
-
const debugHelp = `funnel debug / per-channel inspection (events, drops, connection
|
|
2305
|
+
const debugHelp = `funnel debug / per-channel inspection (events, drops, connection lifecycle, logs, replay)
|
|
2209
2306
|
|
|
2210
|
-
usage / funnel debug [subcommand] [--channel <name>] [--all] [--limit <N>]
|
|
2307
|
+
usage / funnel debug [subcommand] [--channel <name>] [--connector <name>] [--all] [--limit <N>]
|
|
2211
2308
|
|
|
2212
2309
|
subcommands:
|
|
2213
2310
|
(none) / full diagnosis for one channel (or --all for every channel)
|
|
2214
2311
|
events / last N processed events with outcome
|
|
2215
2312
|
dropped / events filtered out (skip:*) with payload
|
|
2216
|
-
errors / listener auth-failed and error
|
|
2313
|
+
errors / listener auth-failed and error rows
|
|
2314
|
+
connection / full connection lifecycle (started / connected / disconnected / stopped + errors)
|
|
2315
|
+
raw / raw inbound events before any processing (pre-processor drops)
|
|
2316
|
+
logs / tail of the gateway daemon log (FunnelLogger + flume internal logs)
|
|
2217
2317
|
replay / re-send a past event into a channel
|
|
2218
2318
|
|
|
2219
2319
|
options:
|
|
2220
2320
|
--channel <name> / channel to inspect (auto-selected when only one exists)
|
|
2321
|
+
--connector <name> / restrict events/dropped/errors/connection/raw to one connector
|
|
2221
2322
|
--all / diagnose every channel
|
|
2222
|
-
--limit <N> / number of rows (default 5 for diagnosis, 20 for subcommands)
|
|
2323
|
+
--limit <N> / number of rows (default 5 for diagnosis, 20 for subcommands, 200 for logs)
|
|
2223
2324
|
|
|
2224
2325
|
For the common case, prefer fnl doctor — it runs a full diagnosis and can apply
|
|
2225
2326
|
safe fixes in one shot. fnl debug is the lower-level view.
|
|
2226
2327
|
|
|
2227
2328
|
output / valid YAML
|
|
2228
2329
|
|
|
2229
|
-
programmable / funnel.diagnostics.diagnose() / .diagnoseAll() / .recentEvents() / .droppedEvents() / .connectionErrors() / .replay()
|
|
2330
|
+
programmable / funnel.diagnostics.diagnose() / .diagnoseAll() / .recentEvents() / .droppedEvents() / .rawEvents() / .connectionErrors() / .connectionTimeline() / .recentLogs() / .replay()
|
|
2230
2331
|
|
|
2231
2332
|
examples:
|
|
2232
2333
|
funnel debug
|
|
2233
2334
|
funnel debug --all
|
|
2234
2335
|
funnel debug --channel ops
|
|
2235
2336
|
funnel debug events --channel ops --limit 50
|
|
2236
|
-
funnel debug dropped --channel ops
|
|
2337
|
+
funnel debug dropped --channel ops
|
|
2338
|
+
funnel debug connection --channel ops --connector slack-prod
|
|
2339
|
+
funnel debug logs --grep slack`;
|
|
2237
2340
|
const debugEventsHelp = `funnel debug events / last N processed events
|
|
2238
2341
|
|
|
2239
2342
|
usage / funnel debug events [--channel <name>] [--limit <N>]
|
|
@@ -2257,8 +2360,30 @@ const debugReplayHelp = `funnel debug replay / re-publish a past event into a ch
|
|
|
2257
2360
|
usage / funnel debug replay --channel <name> [--seq <N>]
|
|
2258
2361
|
|
|
2259
2362
|
programmable / funnel.diagnostics.replay(channel, seq?)`;
|
|
2363
|
+
const debugRawHelp = `funnel debug raw / raw inbound events before any processing
|
|
2364
|
+
|
|
2365
|
+
usage / funnel debug raw [--channel <name>] [--connector <name>] [--limit <N>]
|
|
2366
|
+
|
|
2367
|
+
shows every event the listener received, including those dropped pre-processor
|
|
2368
|
+
(envelope shape changes, pre-READY, malformed payloads).
|
|
2369
|
+
|
|
2370
|
+
programmable / funnel.diagnostics.rawEvents(channel, { connector, limit })`;
|
|
2371
|
+
const debugConnectionHelp = `funnel debug connection / full lifecycle (started / connected / disconnected / stopped + auth-failed / error)
|
|
2372
|
+
|
|
2373
|
+
usage / funnel debug connection [--channel <name>] [--connector <name>] [--limit <N>]
|
|
2374
|
+
|
|
2375
|
+
programmable / funnel.diagnostics.connectionTimeline(channel, { connector, limit })`;
|
|
2376
|
+
const debugLogsHelp = `funnel debug logs / tail of the gateway daemon log
|
|
2377
|
+
|
|
2378
|
+
usage / funnel debug logs [--grep <substr>] [--limit <N>]
|
|
2379
|
+
|
|
2380
|
+
shows funnel.log entries — structured FunnelLogger output and forwarded flume
|
|
2381
|
+
logs. Use --grep to filter (case-insensitive substring).
|
|
2382
|
+
|
|
2383
|
+
programmable / funnel.diagnostics.recentLogs({ grep, limit })`;
|
|
2260
2384
|
const channelLimitQuery = z.object({
|
|
2261
2385
|
channel: z.string().optional(),
|
|
2386
|
+
connector: z.string().optional(),
|
|
2262
2387
|
limit: z.string().optional()
|
|
2263
2388
|
});
|
|
2264
2389
|
const resolveTargetChannel = (c, channelArg) => {
|
|
@@ -2333,7 +2458,10 @@ const debugEventsHandler = factory.createHandlers(helpGuard(debugEventsHelp), zV
|
|
|
2333
2458
|
const limit = query.limit ? Math.max(1, Number(query.limit)) : 20;
|
|
2334
2459
|
const resolved = resolveTargetChannel(c, query.channel);
|
|
2335
2460
|
if (resolved.kind === "error") return c.text(renderYaml(resolved.payload));
|
|
2336
|
-
const events = await funnel.diagnostics.recentEvents(resolved.name,
|
|
2461
|
+
const events = await funnel.diagnostics.recentEvents(resolved.name, {
|
|
2462
|
+
connector: query.connector,
|
|
2463
|
+
limit
|
|
2464
|
+
});
|
|
2337
2465
|
return c.text(renderYaml({ events }));
|
|
2338
2466
|
});
|
|
2339
2467
|
const debugDroppedHandler = factory.createHandlers(helpGuard(debugDroppedHelp), zValidator$1("query", channelLimitQuery), async (c) => {
|
|
@@ -2342,7 +2470,10 @@ const debugDroppedHandler = factory.createHandlers(helpGuard(debugDroppedHelp),
|
|
|
2342
2470
|
const limit = query.limit ? Math.max(1, Number(query.limit)) : 20;
|
|
2343
2471
|
const resolved = resolveTargetChannel(c, query.channel);
|
|
2344
2472
|
if (resolved.kind === "error") return c.text(renderYaml(resolved.payload));
|
|
2345
|
-
const events = await funnel.diagnostics.droppedEvents(resolved.name,
|
|
2473
|
+
const events = await funnel.diagnostics.droppedEvents(resolved.name, {
|
|
2474
|
+
connector: query.connector,
|
|
2475
|
+
limit
|
|
2476
|
+
});
|
|
2346
2477
|
return c.text(renderYaml({ dropped: events }));
|
|
2347
2478
|
});
|
|
2348
2479
|
const debugErrorsHandler = factory.createHandlers(helpGuard(debugErrorsHelp), zValidator$1("query", channelLimitQuery), async (c) => {
|
|
@@ -2351,7 +2482,10 @@ const debugErrorsHandler = factory.createHandlers(helpGuard(debugErrorsHelp), zV
|
|
|
2351
2482
|
const limit = query.limit ? Math.max(1, Number(query.limit)) : 20;
|
|
2352
2483
|
const resolved = resolveTargetChannel(c, query.channel);
|
|
2353
2484
|
if (resolved.kind === "error") return c.text(renderYaml(resolved.payload));
|
|
2354
|
-
const errors = await funnel.diagnostics.connectionErrors(resolved.name,
|
|
2485
|
+
const errors = await funnel.diagnostics.connectionErrors(resolved.name, {
|
|
2486
|
+
connector: query.connector,
|
|
2487
|
+
limit
|
|
2488
|
+
});
|
|
2355
2489
|
return c.text(renderYaml({ errors }));
|
|
2356
2490
|
});
|
|
2357
2491
|
const debugReplayHandler = factory.createHandlers(helpGuard(debugReplayHelp), zValidator$1("query", z.object({
|
|
@@ -2367,6 +2501,43 @@ const debugReplayHandler = factory.createHandlers(helpGuard(debugReplayHelp), zV
|
|
|
2367
2501
|
const result = await funnel.diagnostics.replay(resolved.name, seq);
|
|
2368
2502
|
return c.text(renderYaml(result));
|
|
2369
2503
|
});
|
|
2504
|
+
const debugRawHandler = factory.createHandlers(helpGuard(debugRawHelp), zValidator$1("query", channelLimitQuery), async (c) => {
|
|
2505
|
+
const query = c.req.valid("query");
|
|
2506
|
+
const funnel = c.env.funnel;
|
|
2507
|
+
const limit = query.limit ? Math.max(1, Number(query.limit)) : 20;
|
|
2508
|
+
const resolved = resolveTargetChannel(c, query.channel);
|
|
2509
|
+
if (resolved.kind === "error") return c.text(renderYaml(resolved.payload));
|
|
2510
|
+
const events = await funnel.diagnostics.rawEvents(resolved.name, {
|
|
2511
|
+
connector: query.connector,
|
|
2512
|
+
limit
|
|
2513
|
+
});
|
|
2514
|
+
return c.text(renderYaml({ raw: events }));
|
|
2515
|
+
});
|
|
2516
|
+
const debugConnectionHandler = factory.createHandlers(helpGuard(debugConnectionHelp), zValidator$1("query", channelLimitQuery), async (c) => {
|
|
2517
|
+
const query = c.req.valid("query");
|
|
2518
|
+
const funnel = c.env.funnel;
|
|
2519
|
+
const limit = query.limit ? Math.max(1, Number(query.limit)) : 20;
|
|
2520
|
+
const resolved = resolveTargetChannel(c, query.channel);
|
|
2521
|
+
if (resolved.kind === "error") return c.text(renderYaml(resolved.payload));
|
|
2522
|
+
const timeline = await funnel.diagnostics.connectionTimeline(resolved.name, {
|
|
2523
|
+
connector: query.connector,
|
|
2524
|
+
limit
|
|
2525
|
+
});
|
|
2526
|
+
return c.text(renderYaml({ connection: timeline }));
|
|
2527
|
+
});
|
|
2528
|
+
const debugLogsHandler = factory.createHandlers(helpGuard(debugLogsHelp), zValidator$1("query", z.object({
|
|
2529
|
+
grep: z.string().optional(),
|
|
2530
|
+
limit: z.string().optional()
|
|
2531
|
+
})), async (c) => {
|
|
2532
|
+
const query = c.req.valid("query");
|
|
2533
|
+
const funnel = c.env.funnel;
|
|
2534
|
+
const limit = query.limit ? Math.max(1, Number(query.limit)) : 200;
|
|
2535
|
+
const result = await funnel.diagnostics.recentLogs({
|
|
2536
|
+
grep: query.grep,
|
|
2537
|
+
limit
|
|
2538
|
+
});
|
|
2539
|
+
return c.text(renderYaml(result));
|
|
2540
|
+
});
|
|
2370
2541
|
const docsIndexHandler = factory.createHandlers(helpGuard(`funnel docs / embedded documentation
|
|
2371
2542
|
|
|
2372
2543
|
usage / funnel docs [topic]
|
|
@@ -2453,14 +2624,21 @@ examples:
|
|
|
2453
2624
|
funnel gateway logs
|
|
2454
2625
|
funnel gateway sql --preset recent`;
|
|
2455
2626
|
const renderGatewayStatus = async (c) => {
|
|
2456
|
-
const
|
|
2627
|
+
const funnel = c.env.funnel;
|
|
2628
|
+
const status = funnel.gateway.getStatus();
|
|
2457
2629
|
if (!status.running) return c.text(renderYaml({ running: false }), 503);
|
|
2458
|
-
const
|
|
2459
|
-
|
|
2630
|
+
const token = funnel.gatewayToken.read();
|
|
2631
|
+
let res = null;
|
|
2632
|
+
try {
|
|
2633
|
+
res = await loopbackFetch(`${gatewayLoopbackUrl(status.port)}/status`, { headers: token ? { authorization: `Bearer ${token}` } : {} });
|
|
2634
|
+
} catch {
|
|
2635
|
+
res = null;
|
|
2636
|
+
}
|
|
2637
|
+
if (!res || !res.ok) return c.text(renderYaml({
|
|
2460
2638
|
running: true,
|
|
2461
2639
|
pid: status.pid,
|
|
2462
2640
|
port: status.port,
|
|
2463
|
-
error: "
|
|
2641
|
+
error: res ? `status check failed (${res.status})` : "status check failed"
|
|
2464
2642
|
}));
|
|
2465
2643
|
const data = await res.json();
|
|
2466
2644
|
return c.text(renderYaml({
|
|
@@ -2770,7 +2948,13 @@ const HEALTH_POLL_INTERVAL_MS = 100;
|
|
|
2770
2948
|
const waitForHealth = async (port) => {
|
|
2771
2949
|
const deadline = Date.now() + HEALTH_TIMEOUT_MS;
|
|
2772
2950
|
while (Date.now() < deadline) {
|
|
2773
|
-
|
|
2951
|
+
let ok = false;
|
|
2952
|
+
try {
|
|
2953
|
+
ok = (await loopbackFetch(`${gatewayLoopbackUrl(port)}/health`)).ok;
|
|
2954
|
+
} catch {
|
|
2955
|
+
ok = false;
|
|
2956
|
+
}
|
|
2957
|
+
if (ok) return true;
|
|
2774
2958
|
await new Promise((resolve) => setTimeout(resolve, HEALTH_POLL_INTERVAL_MS));
|
|
2775
2959
|
}
|
|
2776
2960
|
return false;
|
|
@@ -2938,7 +3122,7 @@ const launchHelp = `funnel profiles <name> run — launch a profile (sugar for f
|
|
|
2938
3122
|
usage: funnel profiles <name> run [additional claude args...]
|
|
2939
3123
|
funnel profiles <name> (alias)`;
|
|
2940
3124
|
const RESERVED_KEYS = [];
|
|
2941
|
-
const profilesLaunchHandler = factory.createHandlers(zValidator$1("param", z.object({ profile: z.string() })), helpGuard(launchHelp), zValidator$1("query", z.object({}).
|
|
3125
|
+
const profilesLaunchHandler = factory.createHandlers(zValidator$1("param", z.object({ profile: z.string() })), helpGuard(launchHelp), zValidator$1("query", z.object({}).loose()), async (c) => {
|
|
2942
3126
|
const param = c.req.valid("param");
|
|
2943
3127
|
c.env.funnel;
|
|
2944
3128
|
const { profiles, claude } = c.env;
|
|
@@ -3114,7 +3298,13 @@ const buildStatusReport = async (funnel, profiles) => {
|
|
|
3114
3298
|
const gatewayStatus = funnel.gateway.getStatus();
|
|
3115
3299
|
let gatewayData = null;
|
|
3116
3300
|
if (gatewayStatus.running) {
|
|
3117
|
-
const
|
|
3301
|
+
const token = funnel.gatewayToken.read();
|
|
3302
|
+
let res = null;
|
|
3303
|
+
try {
|
|
3304
|
+
res = await loopbackFetch(`${gatewayLoopbackUrl(gatewayStatus.port)}/status`, { headers: token ? { authorization: `Bearer ${token}` } : {} });
|
|
3305
|
+
} catch {
|
|
3306
|
+
res = null;
|
|
3307
|
+
}
|
|
3118
3308
|
if (res && res.ok) {
|
|
3119
3309
|
const body = await res.json();
|
|
3120
3310
|
if (isGatewayStatus(body)) gatewayData = body;
|
|
@@ -3216,6 +3406,6 @@ const updateHandler = factory.createHandlers(helpGuard(updateHelp), async (c) =>
|
|
|
3216
3406
|
const routes = factory.createApp().onError((error, c) => {
|
|
3217
3407
|
if (error instanceof HTTPException) return c.text(error.message, error.status);
|
|
3218
3408
|
return c.text(`error: ${error instanceof Error ? error.message : String(error)}`, 400);
|
|
3219
|
-
}).get("/claude", ...claudeHandler).get("/channels", ...channelsGroupHandler).post("/channels/add", ...channelsAddHelpHandler).post("/channels/add/:channel", ...channelsAddHandler).post("/channels/remove", ...channelsRemoveHelpHandler).post("/channels/remove/:channel", ...channelsRemoveHandler).post("/channels/rename/:channel/:newName", ...channelsRenameHandler).post("/channels/:channel/rename/:newName", ...channelsRenameHandler).post("/channels/rename", ...channelsRenameHelpHandler).post("/channels/:channel/rename", ...channelsChannelRenameHelpHandler).post("/channels/:channel/set/delivery/:mode", ...channelsSetDeliveryHandler).post("/channels/publish", ...channelsPublishHelpHandler).post("/channels/:channel/publish", ...channelsPublishHandler).get("/channels/:channel/validate", ...channelsValidateHandler).get("/channels/validate", ...channelsValidateHelpHandler).get("/channels/:channel", ...channelsShowHandler).get("/channels/:channel/connectors", ...channelsConnectorsGroupHandler).post("/channels/:channel/connectors/add", ...channelsConnectorsAddHelpHandler).post("/channels/:channel/connectors/add/:connector", ...channelsConnectorsAddHandler).post("/channels/:channel/connectors/remove", ...channelsConnectorsRemoveHelpHandler).post("/channels/:channel/connectors/remove/:connector", ...channelsConnectorsRemoveHandler).post("/channels/:channel/connectors/set", ...channelsConnectorsSetHelpHandler).post("/channels/:channel/connectors/set/:connector", ...channelsConnectorsSetHandler).post("/channels/:channel/connectors/rename/:connector/:newName", ...channelsConnectorsRenameHandler).post("/channels/:channel/connectors/:connector/rename/:newName", ...channelsConnectorsRenameHandler).post("/channels/:channel/connectors/rename", ...channelsConnectorsRenameHelpHandler).post("/channels/:channel/connectors/:connector/rename", ...channelsConnectorRenameHelpHandler).post("/channels/:channel/connectors/:connector/request", ...channelsConnectorsRequestHandler).get("/channels/:channel/connectors/:connector", ...channelsConnectorsShowHandler).get("/channels/:channel/connectors/:connector/schedules", ...channelsConnectorsSchedulesGroupHandler).post("/channels/:channel/connectors/:connector/schedules/add", ...channelsConnectorSchedulesAddHelpHandler).post("/channels/:channel/connectors/:connector/schedules/add/:id", ...channelsConnectorsSchedulesAddHandler).post("/channels/:channel/connectors/:connector/schedules/remove", ...channelsConnectorSchedulesRemoveHelpHandler).post("/channels/:channel/connectors/:connector/schedules/remove/:id", ...channelsConnectorsSchedulesRemoveHandler).get("/profiles", ...profilesGroupHandler).post("/profiles/add", ...profilesAddHelpHandler).post("/profiles/add/:profile", ...profilesAddHandler).post("/profiles/set", ...profilesSetHelpHandler).post("/profiles/set/:profile", ...profilesSetHandler).post("/profiles/remove", ...profilesRemoveHelpHandler).post("/profiles/remove/:profile", ...profilesRemoveHandler).post("/profiles/rename/:profile/:newName", ...profilesRenameHandler).post("/profiles/:profile/rename/:newName", ...profilesRenameHandler).post("/profiles/rename", ...profilesRenameHelpHandler).post("/profiles/:profile/rename", ...profilesProfileRenameHelpHandler).post("/profiles/:profile/as-default", ...profilesAsDefaultHandler).get("/profiles/:profile/run", ...profilesLaunchHandler).get("/profiles/:profile", ...profilesLaunchHandler).get("/gateway", ...gatewayGroupHandler).get("/gateway/status", ...gatewayStatusHandler).get("/gateway/start", ...gatewayStartHandler).get("/gateway/stop", ...gatewayStopHandler).get("/gateway/restart", ...gatewayRestartHandler).get("/gateway/run", ...gatewayRunHandler).get("/gateway/logs", ...gatewayLogsHandler).get("/gateway/sql", ...gatewaySqlHandler).get("/gateway/listeners", ...gatewayListenersHandler).get("/debug", ...debugHandler).get("/debug/events", ...debugEventsHandler).get("/debug/dropped", ...debugDroppedHandler).get("/debug/errors", ...debugErrorsHandler).get("/debug/replay", ...debugReplayHandler).get("/docs", ...docsIndexHandler).get("/docs/:topic", ...docsTopicHandler).get("/doctor", ...doctorHandler).get("/schema", ...schemaHandler).get("/status", ...statusHandler).get("/update", ...updateHandler);
|
|
3409
|
+
}).get("/claude", ...claudeHandler).get("/channels", ...channelsGroupHandler).post("/channels/add", ...channelsAddHelpHandler).post("/channels/add/:channel", ...channelsAddHandler).post("/channels/remove", ...channelsRemoveHelpHandler).post("/channels/remove/:channel", ...channelsRemoveHandler).post("/channels/rename/:channel/:newName", ...channelsRenameHandler).post("/channels/:channel/rename/:newName", ...channelsRenameHandler).post("/channels/rename", ...channelsRenameHelpHandler).post("/channels/:channel/rename", ...channelsChannelRenameHelpHandler).post("/channels/:channel/set/delivery/:mode", ...channelsSetDeliveryHandler).post("/channels/publish", ...channelsPublishHelpHandler).post("/channels/:channel/publish", ...channelsPublishHandler).get("/channels/:channel/validate", ...channelsValidateHandler).get("/channels/validate", ...channelsValidateHelpHandler).get("/channels/:channel", ...channelsShowHandler).get("/channels/:channel/connectors", ...channelsConnectorsGroupHandler).post("/channels/:channel/connectors/add", ...channelsConnectorsAddHelpHandler).post("/channels/:channel/connectors/add/:connector", ...channelsConnectorsAddHandler).post("/channels/:channel/connectors/remove", ...channelsConnectorsRemoveHelpHandler).post("/channels/:channel/connectors/remove/:connector", ...channelsConnectorsRemoveHandler).post("/channels/:channel/connectors/set", ...channelsConnectorsSetHelpHandler).post("/channels/:channel/connectors/set/:connector", ...channelsConnectorsSetHandler).post("/channels/:channel/connectors/rename/:connector/:newName", ...channelsConnectorsRenameHandler).post("/channels/:channel/connectors/:connector/rename/:newName", ...channelsConnectorsRenameHandler).post("/channels/:channel/connectors/rename", ...channelsConnectorsRenameHelpHandler).post("/channels/:channel/connectors/:connector/rename", ...channelsConnectorRenameHelpHandler).post("/channels/:channel/connectors/:connector/request", ...channelsConnectorsRequestHandler).get("/channels/:channel/connectors/:connector", ...channelsConnectorsShowHandler).get("/channels/:channel/connectors/:connector/schedules", ...channelsConnectorsSchedulesGroupHandler).post("/channels/:channel/connectors/:connector/schedules/add", ...channelsConnectorSchedulesAddHelpHandler).post("/channels/:channel/connectors/:connector/schedules/add/:id", ...channelsConnectorsSchedulesAddHandler).post("/channels/:channel/connectors/:connector/schedules/remove", ...channelsConnectorSchedulesRemoveHelpHandler).post("/channels/:channel/connectors/:connector/schedules/remove/:id", ...channelsConnectorsSchedulesRemoveHandler).get("/profiles", ...profilesGroupHandler).post("/profiles/add", ...profilesAddHelpHandler).post("/profiles/add/:profile", ...profilesAddHandler).post("/profiles/set", ...profilesSetHelpHandler).post("/profiles/set/:profile", ...profilesSetHandler).post("/profiles/remove", ...profilesRemoveHelpHandler).post("/profiles/remove/:profile", ...profilesRemoveHandler).post("/profiles/rename/:profile/:newName", ...profilesRenameHandler).post("/profiles/:profile/rename/:newName", ...profilesRenameHandler).post("/profiles/rename", ...profilesRenameHelpHandler).post("/profiles/:profile/rename", ...profilesProfileRenameHelpHandler).post("/profiles/:profile/as-default", ...profilesAsDefaultHandler).get("/profiles/:profile/run", ...profilesLaunchHandler).get("/profiles/:profile", ...profilesLaunchHandler).get("/gateway", ...gatewayGroupHandler).get("/gateway/status", ...gatewayStatusHandler).get("/gateway/start", ...gatewayStartHandler).get("/gateway/stop", ...gatewayStopHandler).get("/gateway/restart", ...gatewayRestartHandler).get("/gateway/run", ...gatewayRunHandler).get("/gateway/logs", ...gatewayLogsHandler).get("/gateway/sql", ...gatewaySqlHandler).get("/gateway/listeners", ...gatewayListenersHandler).get("/debug", ...debugHandler).get("/debug/events", ...debugEventsHandler).get("/debug/dropped", ...debugDroppedHandler).get("/debug/errors", ...debugErrorsHandler).get("/debug/replay", ...debugReplayHandler).get("/debug/raw", ...debugRawHandler).get("/debug/connection", ...debugConnectionHandler).get("/debug/logs", ...debugLogsHandler).get("/docs", ...docsIndexHandler).get("/docs/:topic", ...docsTopicHandler).get("/doctor", ...doctorHandler).get("/schema", ...schemaHandler).get("/status", ...statusHandler).get("/update", ...updateHandler);
|
|
3220
3410
|
//#endregion
|
|
3221
|
-
export { CONNECTOR_CONNECTION_STATUSES, ConnectorDiagnosticLog, ConnectorDiagnosticSqlReader, DEFAULT_GATEWAY_PORT, DEFAULT_GATEWAY_TOKEN_PATH, FUNNEL_DIR, Funnel, FunnelBroadcaster, FunnelChannelPublisher, FunnelChannels, FunnelClock, FunnelConnectorAdapter, FunnelConnectorListener, FunnelConnectorRegistry, FunnelDiagnostics, FunnelDocs, FunnelDoctor, FunnelEventLog, FunnelFileSystem, FunnelGateway, FunnelGatewayServer, FunnelGatewayToken, FunnelHttpClient, FunnelIdGenerator,
|
|
3411
|
+
export { CONNECTOR_CONNECTION_STATUSES, ConnectorDiagnosticLog, ConnectorDiagnosticSqlReader, DEFAULT_GATEWAY_PORT, DEFAULT_GATEWAY_TOKEN_PATH, FUNNEL_DIR, Funnel, FunnelAuthFailedError, FunnelBroadcaster, FunnelChannelAlreadyExistsError, FunnelChannelNotFoundError, FunnelChannelPublisher, FunnelChannels, FunnelClock, FunnelConnectorAdapter, FunnelConnectorListener, FunnelConnectorNotFoundError, FunnelConnectorRegistry, FunnelConnectorTypeMismatchError, FunnelDiagnostics, FunnelDocs, FunnelDoctor, FunnelError, FunnelEventLog, FunnelFileSystem, FunnelGateway, FunnelGatewayBindError, FunnelGatewayServer, FunnelGatewayToken, FunnelHttpClient, FunnelIdGenerator, FunnelListenerRegistry, FunnelListenersClient, FunnelLogger, FunnelProcessRunner, FunnelRecovery, FunnelSettingsReader, FunnelSettingsStore, FunnelSlackEventProcessor, FunnelTokenCollisionError, FunnelTokenPrompter, MemoryConnectorDiagnosticLog, MemoryFunnelClock, MemoryFunnelEventLog, MemoryFunnelFileSystem, MemoryFunnelHttpClient, MemoryFunnelIdGenerator, MemoryFunnelLogger, MemoryFunnelProcessRunner, MemoryFunnelTokenPrompter, MockFunnelSettingsReader, NodeFunnelClock, NodeFunnelFileSystem, NodeFunnelHttpClient, NodeFunnelIdGenerator, NodeFunnelLogger, NodeFunnelProcessRunner, NodeFunnelTokenPrompter, NoopFunnelLogger, SETTINGS_PATH, SETTINGS_VERSION, SqliteConnectorDiagnosticLog, SqliteFunnelEventLog, baseConnectorConfigSchema, buildServiceRoutes, channelConfigSchema, channelDeliveryModeSchema, channelWsProtocols, channelWsUrl, routes as cliRoutes, connectorConnectionEventSchema, connectorProcessedEventSchema, connectorRawEventSchema, createSettings, discordConnectorSchema, factory, funnelEventSchema, gatewayLoopbackUrl, ghConnectorSchema, previewOf, profileConfigSchema, publishRequestSchema, publishResponseSchema, queryRows, queryToCliArgs, resolveFunnelDir, resolveFunnelPort, scheduleCatchupPolicySchema, scheduleConnectorSchema, scheduleEntrySchema, settingsSchema, slackConnectorSchema, toDiagnosticConnectionError, toDiagnosticEvent, toRequest };
|