@interactive-inc/claude-funnel 0.29.0 → 0.30.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/dist/index.d.ts CHANGED
@@ -1122,7 +1122,8 @@ declare class FunnelGateway {
1122
1122
  type Deps$3 = {
1123
1123
  channels: FunnelChannels;
1124
1124
  settings: FunnelSettingsReader;
1125
- port?: number; /** SQLite event store file path. Parent directory is created on demand. Defaults to `<os.tmpdir()>/funnel/events.db`. Ignored when `eventLog` is supplied. */
1125
+ port?: number; /** Bind address for `Bun.serve`. Defaults to `127.0.0.1` (loopback only). Set to `0.0.0.0` to expose on the network. */
1126
+ hostname?: string; /** SQLite event store file path. Parent directory is created on demand. Defaults to `<os.tmpdir()>/funnel/events.db`. Ignored when `eventLog` is supplied. */
1126
1127
  dbPath?: string; /** Durable replay log. Defaults to a `SqliteFunnelEventLog` at `dbPath`. Inject a `MemoryFunnelEventLog` (or any `FunnelEventLog`) to swap or disable persistence. */
1127
1128
  eventLog?: FunnelEventLog;
1128
1129
  process?: FunnelProcessRunner;
@@ -1163,6 +1164,7 @@ declare class FunnelGatewayServer {
1163
1164
  private readonly channels;
1164
1165
  private readonly settings;
1165
1166
  private readonly port;
1167
+ private readonly hostname;
1166
1168
  private readonly dbPath;
1167
1169
  private readonly process?;
1168
1170
  private readonly logger;
@@ -1445,7 +1447,8 @@ declare class Funnel {
1445
1447
  * useful for tests, embedding, or custom hosts.
1446
1448
  */
1447
1449
  gatewayServer(options?: {
1448
- port?: number;
1450
+ port?: number; /** Bind address. Defaults to `127.0.0.1` (loopback only). Set to `0.0.0.0` to expose on the network. */
1451
+ hostname?: string;
1449
1452
  dbPath?: string;
1450
1453
  killCompetingSlack?: boolean; /** Override the auth token. Defaults to the persisted gateway.token. Pass "" to disable auth (tests). */
1451
1454
  token?: string; /** Durable replay log. Defaults to a SqliteFunnelEventLog at dbPath; inject a MemoryFunnelEventLog (or any FunnelEventLog) to swap or disable persistence. */
package/dist/index.js CHANGED
@@ -187,7 +187,7 @@ var FunnelSettingsStore = class extends FunnelSettingsReader {
187
187
  ...settings,
188
188
  version: 1
189
189
  };
190
- this.fs.writeFileSync(this.path, `${JSON.stringify(versioned, null, 2)}\n`);
190
+ this.fs.writeSecretFileSync(this.path, `${JSON.stringify(versioned, null, 2)}\n`);
191
191
  }
192
192
  };
193
193
  //#endregion
@@ -3047,6 +3047,13 @@ const gatewayRoutes = factory$1.createApp().get("/health", ...healthHandler).get
3047
3047
  //#endregion
3048
3048
  //#region lib/gateway/gateway-server.ts
3049
3049
  const DEFAULT_PORT = 9742;
3050
+ const DEFAULT_HOST = "127.0.0.1";
3051
+ const LOOPBACK_HOSTS = new Set([
3052
+ "127.0.0.1",
3053
+ "localhost",
3054
+ "::1",
3055
+ "::ffff:127.0.0.1"
3056
+ ]);
3050
3057
  const defaultDbPath = () => join(funnelTmpDir(), "events.db");
3051
3058
  const defaultOnError = () => {};
3052
3059
  /**
@@ -3063,6 +3070,7 @@ var FunnelGatewayServer = class {
3063
3070
  channels;
3064
3071
  settings;
3065
3072
  port;
3073
+ hostname;
3066
3074
  dbPath;
3067
3075
  process;
3068
3076
  logger;
@@ -3082,6 +3090,7 @@ var FunnelGatewayServer = class {
3082
3090
  this.channels = deps.channels;
3083
3091
  this.settings = deps.settings;
3084
3092
  this.port = deps.port ?? DEFAULT_PORT;
3093
+ this.hostname = deps.hostname ?? DEFAULT_HOST;
3085
3094
  this.dbPath = deps.dbPath ?? defaultDbPath();
3086
3095
  this.process = deps.process;
3087
3096
  this.logger = deps.logger;
@@ -3126,10 +3135,12 @@ var FunnelGatewayServer = class {
3126
3135
  }
3127
3136
  async start() {
3128
3137
  if (this.server) return this.server;
3138
+ if (!this.token && !LOOPBACK_HOSTS.has(this.hostname)) this.logger?.warn("gateway auth is disabled on a non-loopback bind — every endpoint is reachable without a token", { hostname: this.hostname });
3129
3139
  const app = this.buildApp();
3130
3140
  this.startedAt = this.nowMs();
3131
3141
  this.server = Bun.serve({
3132
3142
  port: this.port,
3143
+ hostname: this.hostname,
3133
3144
  development: false,
3134
3145
  fetch: (request, server) => this.handleFetch(request, server, app),
3135
3146
  websocket: {
@@ -3734,6 +3745,7 @@ var Funnel = class Funnel {
3734
3745
  channels: this.channels,
3735
3746
  settings: this.store,
3736
3747
  port: options.port,
3748
+ hostname: options.hostname,
3737
3749
  dbPath: options.dbPath,
3738
3750
  eventLog: options.eventLog,
3739
3751
  process: this.process,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@interactive-inc/claude-funnel",
3
- "version": "0.29.0",
3
+ "version": "0.30.0",
4
4
  "description": "Hub CLI that routes external events (Slack / GitHub / Discord) to Claude Code agents through subscription channels over MCP.",
5
5
  "keywords": [
6
6
  "bun",