serverless-ircd 0.3.0 → 0.5.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/.github/workflows/ci.yml +2 -2
- package/.github/workflows/deploy-aws.yml +1 -3
- package/.github/workflows/deploy-cf-tcp.yml +87 -0
- package/.github/workflows/deploy-cf.yml +1 -1
- package/.node-version +1 -0
- package/.nvmrc +1 -0
- package/CHANGELOG.md +349 -18
- package/README.md +132 -30
- package/apps/aws-stack/README.md +6 -5
- package/apps/aws-stack/bin/aws.ts +7 -0
- package/apps/aws-stack/package.json +4 -4
- package/apps/aws-stack/src/aws-stack.ts +150 -10
- package/apps/aws-stack/tests/stack.test.ts +145 -4
- package/apps/cf-tcp-container/Dockerfile +69 -0
- package/apps/cf-tcp-container/package.json +34 -0
- package/apps/cf-tcp-container/src/config-loader.ts +145 -0
- package/apps/cf-tcp-container/src/container-do.ts +38 -0
- package/apps/cf-tcp-container/src/container-server.ts +363 -0
- package/apps/cf-tcp-container/src/main.ts +77 -0
- package/apps/cf-tcp-container/src/persistence.ts +144 -0
- package/apps/cf-tcp-container/src/worker.ts +41 -0
- package/apps/cf-tcp-container/terraform/provider.tf +24 -0
- package/apps/cf-tcp-container/terraform/spectrum.tf +81 -0
- package/apps/cf-tcp-container/tests/config-loader.test.ts +217 -0
- package/apps/cf-tcp-container/tests/container-server.test.ts +465 -0
- package/apps/cf-tcp-container/tests/persistence.test.ts +227 -0
- package/apps/cf-tcp-container/tests/tls-e2e.test.ts +275 -0
- package/apps/cf-tcp-container/tsconfig.build.json +17 -0
- package/apps/cf-tcp-container/tsconfig.test.json +15 -0
- package/apps/cf-tcp-container/vitest.config.ts +26 -0
- package/apps/cf-tcp-container/wrangler.toml +63 -0
- package/apps/cf-worker/package.json +1 -1
- package/apps/cf-worker/wrangler.test.toml +6 -0
- package/apps/cf-worker/wrangler.toml +28 -2
- package/apps/local-cli/package.json +1 -1
- package/apps/local-cli/src/config-loader.ts +10 -0
- package/apps/local-cli/src/server.ts +149 -24
- package/apps/local-cli/tests/e2e.test.ts +1 -1
- package/apps/local-cli/tests/ws-subprotocol.test.ts +257 -0
- package/package.json +14 -10
- package/packages/aws-adapter/package.json +3 -3
- package/packages/aws-adapter/src/account-store.ts +1 -1
- package/packages/aws-adapter/src/admission.ts +74 -0
- package/packages/aws-adapter/src/aws-runtime.ts +75 -4
- package/packages/aws-adapter/src/config-loader.ts +32 -0
- package/packages/aws-adapter/src/dynamo-account-store.ts +35 -96
- package/packages/aws-adapter/src/handlers/connect.ts +96 -9
- package/packages/aws-adapter/src/handlers/default.ts +98 -7
- package/packages/aws-adapter/src/handlers/index.ts +109 -4
- package/packages/aws-adapter/src/handlers/nlb-stream.ts +490 -0
- package/packages/aws-adapter/src/handlers/ping-checker.ts +1 -1
- package/packages/aws-adapter/src/index.ts +8 -0
- package/packages/aws-adapter/src/serialize.ts +11 -1
- package/packages/aws-adapter/src/stats.ts +80 -0
- package/packages/aws-adapter/tests/account-store-dynamo.test.ts +45 -34
- package/packages/aws-adapter/tests/account-store.test.ts +19 -20
- package/packages/aws-adapter/tests/admission.test.ts +70 -0
- package/packages/aws-adapter/tests/aws-harness.ts +13 -1
- package/packages/aws-adapter/tests/aws-integration.test.ts +1 -1
- package/packages/aws-adapter/tests/aws-runtime.test.ts +61 -0
- package/packages/aws-adapter/tests/config-loader.test.ts +20 -0
- package/packages/aws-adapter/tests/connect.test.ts +174 -0
- package/packages/aws-adapter/tests/disconnect-fanout.test.ts +47 -40
- package/packages/aws-adapter/tests/gone-exception.test.ts +31 -26
- package/packages/aws-adapter/tests/handlers.test.ts +302 -53
- package/packages/aws-adapter/tests/nlb-stream.test.ts +480 -0
- package/packages/aws-adapter/tests/ping-checker.test.ts +34 -29
- package/packages/aws-adapter/tests/stats.test.ts +317 -0
- package/packages/aws-adapter/tests/sweeper.test.ts +25 -18
- package/packages/aws-adapter/tests/transactions.test.ts +25 -20
- package/packages/cf-adapter/package.json +5 -1
- package/packages/cf-adapter/src/cf-runtime.ts +68 -5
- package/packages/cf-adapter/src/channel-do.ts +2 -2
- package/packages/cf-adapter/src/config-loader.ts +33 -0
- package/packages/cf-adapter/src/connection-do.ts +278 -85
- package/packages/cf-adapter/src/d1-account-store.ts +198 -0
- package/packages/cf-adapter/src/env.ts +54 -11
- package/packages/cf-adapter/src/index.ts +11 -8
- package/packages/cf-adapter/src/registry-do.ts +22 -3
- package/packages/cf-adapter/src/sharding.ts +1 -2
- package/packages/cf-adapter/src/stats.ts +65 -0
- package/packages/cf-adapter/tests/cf-harness.ts +12 -2
- package/packages/cf-adapter/tests/cf-integration.test.ts +6 -5
- package/packages/cf-adapter/tests/cf-runtime.test.ts +38 -2
- package/packages/cf-adapter/tests/channel-do.test.ts +2 -2
- package/packages/cf-adapter/tests/config-loader.test.ts +22 -0
- package/packages/cf-adapter/tests/connection-do-channel-registration.test.ts +37 -0
- package/packages/cf-adapter/tests/connection-do-no-batching-reservation.test.ts +52 -0
- package/packages/cf-adapter/tests/connection-do-sasl-d1.test.ts +166 -0
- package/packages/cf-adapter/tests/connection-do-ws-spec-contract.test.ts +289 -0
- package/packages/cf-adapter/tests/connection-do-ws-subprotocol.test.ts +184 -0
- package/packages/cf-adapter/tests/connection-do.test.ts +27 -2
- package/packages/cf-adapter/tests/d1-account-store.test.ts +226 -0
- package/packages/cf-adapter/tests/raw-modules.d.ts +11 -0
- package/packages/cf-adapter/tests/registry-do.test.ts +4 -4
- package/packages/cf-adapter/tests/sharding.test.ts +1 -1
- package/packages/cf-adapter/tests/stats.test.ts +120 -0
- package/packages/cf-adapter/tests/worker/main.ts +15 -8
- package/packages/cf-adapter/tests/worker/stubs/channel-stub.ts +2 -2
- package/packages/cf-adapter/tests/worker/stubs/registry-stub.ts +8 -2
- package/packages/cf-adapter/wrangler.test.toml +15 -0
- package/packages/in-memory-runtime/package.json +1 -1
- package/packages/in-memory-runtime/src/in-memory-runtime.ts +39 -0
- package/packages/in-memory-runtime/tests/in-memory-runtime.test.ts +259 -0
- package/packages/irc-core/package.json +6 -1
- package/packages/irc-core/scripts/generate-build-info.mjs +31 -0
- package/packages/irc-core/src/admission.ts +16 -15
- package/packages/irc-core/src/caps/capabilities.ts +24 -3
- package/packages/irc-core/src/cloak.ts +1 -1
- package/packages/irc-core/src/commands/cap.ts +8 -1
- package/packages/irc-core/src/commands/index.ts +17 -0
- package/packages/irc-core/src/commands/invite.ts +2 -4
- package/packages/irc-core/src/commands/ison.ts +61 -0
- package/packages/irc-core/src/commands/isupport.ts +6 -2
- package/packages/irc-core/src/commands/kick.ts +2 -4
- package/packages/irc-core/src/commands/kill.ts +127 -0
- package/packages/irc-core/src/commands/list.ts +1 -1
- package/packages/irc-core/src/commands/lusers.ts +204 -0
- package/packages/irc-core/src/commands/mode.ts +4 -8
- package/packages/irc-core/src/commands/names.ts +3 -5
- package/packages/irc-core/src/commands/part.ts +2 -4
- package/packages/irc-core/src/commands/quit.ts +12 -0
- package/packages/irc-core/src/commands/registration.ts +18 -12
- package/packages/irc-core/src/commands/rehash.ts +119 -0
- package/packages/irc-core/src/commands/sasl.ts +72 -9
- package/packages/irc-core/src/commands/server-info.ts +129 -0
- package/packages/irc-core/src/commands/setname.ts +109 -0
- package/packages/irc-core/src/commands/stats.ts +152 -0
- package/packages/irc-core/src/commands/topic.ts +2 -4
- package/packages/irc-core/src/commands/trace.ts +137 -0
- package/packages/irc-core/src/commands/userhost.ts +84 -0
- package/packages/irc-core/src/commands/wallops.ts +118 -0
- package/packages/irc-core/src/commands/whowas.ts +113 -0
- package/packages/irc-core/src/config.ts +65 -0
- package/packages/irc-core/src/credential-hashing.ts +124 -0
- package/packages/irc-core/src/effects.ts +33 -30
- package/packages/irc-core/src/index.ts +3 -0
- package/packages/irc-core/src/ports.ts +360 -12
- package/packages/irc-core/src/protocol/numerics.ts +48 -11
- package/packages/irc-core/src/protocol/outbound.ts +20 -3
- package/packages/irc-core/src/types.ts +46 -2
- package/packages/irc-core/src/ws-framing.ts +132 -0
- package/packages/irc-core/src/ws-subprotocol.ts +66 -0
- package/packages/irc-core/tests/account-store.test.ts +45 -2
- package/packages/irc-core/tests/admission.test.ts +18 -0
- package/packages/irc-core/tests/caps/capabilities.test.ts +4 -3
- package/packages/irc-core/tests/commands/cap.test.ts +33 -1
- package/packages/irc-core/tests/commands/ison.test.ts +166 -0
- package/packages/irc-core/tests/commands/kill.test.ts +243 -0
- package/packages/irc-core/tests/commands/lusers.test.ts +368 -0
- package/packages/irc-core/tests/commands/mode.test.ts +57 -0
- package/packages/irc-core/tests/commands/quit.test.ts +69 -2
- package/packages/irc-core/tests/commands/registration.test.ts +151 -6
- package/packages/irc-core/tests/commands/rehash.test.ts +171 -0
- package/packages/irc-core/tests/commands/sasl.test.ts +118 -10
- package/packages/irc-core/tests/commands/server-info.test.ts +274 -0
- package/packages/irc-core/tests/commands/setname.test.ts +225 -0
- package/packages/irc-core/tests/commands/stats.test.ts +294 -0
- package/packages/irc-core/tests/commands/tagmsg.test.ts +9 -35
- package/packages/irc-core/tests/commands/trace.test.ts +282 -0
- package/packages/irc-core/tests/commands/userhost.test.ts +264 -0
- package/packages/irc-core/tests/commands/wallops.test.ts +231 -0
- package/packages/irc-core/tests/commands/whowas.test.ts +312 -0
- package/packages/irc-core/tests/config.test.ts +95 -1
- package/packages/irc-core/tests/credential-hashing.test.ts +170 -0
- package/packages/irc-core/tests/dropped-s2s-and-obsolete-verbs.test.ts +90 -0
- package/packages/irc-core/tests/effects.test.ts +14 -27
- package/packages/irc-core/tests/nick-history-store.test.ts +162 -0
- package/packages/irc-core/tests/numerics.test.ts +102 -0
- package/packages/irc-core/tests/outbound.test.ts +51 -0
- package/packages/irc-core/tests/ports.test.ts +22 -0
- package/packages/irc-core/tests/raw-modules.d.ts +11 -0
- package/packages/irc-core/tests/stats-store.test.ts +222 -0
- package/packages/irc-core/tests/types.test.ts +35 -1
- package/packages/irc-core/tests/ws-framing.test.ts +213 -0
- package/packages/irc-core/tests/ws-subprotocol.test.ts +111 -0
- package/packages/irc-core/tsconfig.build.json +1 -1
- package/packages/irc-core/tsconfig.test.json +1 -1
- package/packages/irc-server/package.json +1 -1
- package/packages/irc-server/src/actor.ts +393 -16
- package/packages/irc-server/src/dispatch.ts +1 -3
- package/packages/irc-server/src/index.ts +10 -2
- package/packages/irc-server/src/routing.ts +15 -0
- package/packages/irc-server/src/runtime.ts +31 -0
- package/packages/irc-server/src/transport.ts +104 -0
- package/packages/irc-server/tests/actor.test.ts +1489 -4
- package/packages/irc-server/tests/dispatch.test.ts +37 -17
- package/packages/irc-server/tests/raw-modules.d.ts +11 -0
- package/packages/irc-server/tests/routing.test.ts +5 -0
- package/packages/irc-server/tests/runtime.test.ts +7 -0
- package/packages/irc-server/tests/transport.test.ts +230 -0
- package/packages/irc-test-support/package.json +1 -1
- package/packages/irc-test-support/src/harness.ts +44 -9
- package/packages/irc-test-support/src/in-memory-harness.ts +73 -9
- package/packages/irc-test-support/src/index.ts +3 -0
- package/packages/irc-test-support/src/scenarios.ts +141 -3
- package/packages/irc-test-support/tests/in-memory-harness.test.ts +2 -1
- package/packages/irc-test-support/tests/in-memory-scenarios.test.ts +23 -9
- package/pnpm-workspace.yaml +10 -1
- package/tools/ci-hardening/package.json +1 -1
- package/tools/package.json +9 -0
- package/tools/seed-aws-accounts.ts +5 -6
- package/tools/seed-cf-accounts.ts +107 -0
- package/tools/tcp-ws-forwarder/package.json +1 -1
- package/tools/tcp-ws-forwarder/src/forwarder.ts +57 -9
- package/tools/tcp-ws-forwarder/tests/forwarder.test.ts +34 -1
- package/tools/tcp-ws-forwarder/tests/framing.test.ts +65 -1
- package/docs/ADR-001-pure-reducers-and-effect-system.md +0 -74
- package/docs/ADR-002-location-of-authority.md +0 -82
- package/docs/ADR-003-durable-object-sharding.md +0 -93
- package/docs/ADR-004-dynamodb-schema.md +0 -96
- package/docs/ADR-005-wss-only-transport-v1.md +0 -83
- package/docs/ADR-006-sasl-mechanism-scope.md +0 -86
- package/docs/ADR-007-deterministic-ports.md +0 -82
- package/docs/ADR-008-monorepo-tooling.md +0 -60
- package/docs/AWS-Adapter-Architecture.md +0 -496
- package/docs/AWS-Deployment.md +0 -1186
- package/docs/Cloudflare-Deployment-Guide.md +0 -660
- package/docs/Home.md +0 -11
- package/docs/Observability.md +0 -87
- package/docs/PlanIRCv3Websocket.md +0 -489
- package/docs/PlanWebClient.md +0 -451
- package/docs/Release-Process.md +0 -443
|
@@ -35,13 +35,16 @@ import {
|
|
|
35
35
|
type Nick,
|
|
36
36
|
type RawLine,
|
|
37
37
|
type RosterEntry,
|
|
38
|
+
type ServerConfig,
|
|
38
39
|
toSnapshot,
|
|
39
40
|
} from '@serverless-ircd/irc-core';
|
|
40
41
|
import type { IrcRuntime } from '@serverless-ircd/irc-server';
|
|
42
|
+
import type { CfConfigEnv } from './config-loader.js';
|
|
43
|
+
import { loadServerConfigFromCfEnv } from './config-loader.js';
|
|
41
44
|
import type { ChannelRegistryRpc, Env, RegistryRpc } from './env.js';
|
|
42
|
-
import { DEFAULT_REGISTRY_SHARDS, registryKeyForNick, shardNick } from './sharding.js';
|
|
43
45
|
import type { PersistedConnectionState } from './serialize.js';
|
|
44
46
|
import { deserialize } from './serialize.js';
|
|
47
|
+
import { DEFAULT_REGISTRY_SHARDS, registryKeyForNick, shardNick } from './sharding.js';
|
|
45
48
|
|
|
46
49
|
/** Per-connection transport callbacks the ConnectionDO wires up. */
|
|
47
50
|
export interface CfConnectionHandlers {
|
|
@@ -144,6 +147,48 @@ export class CfRuntime implements IrcRuntime {
|
|
|
144
147
|
}
|
|
145
148
|
}
|
|
146
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Global cross-connection fan-out for `WALLOPS`. Enumerates every registry
|
|
152
|
+
* shard to collect all live connection ids, fetches each connection's
|
|
153
|
+
* state to honour the `+w` recipient gate, and delivers via the
|
|
154
|
+
* ConnectionDO `deliver` RPC. `except` (the originator) is skipped, as is
|
|
155
|
+
* the bound connection's own live state shortcut.
|
|
156
|
+
*
|
|
157
|
+
* Cost: this is N shard RPCs + one `getConnState` per online connection +
|
|
158
|
+
* one `deliver` per `+w` recipient. At very high connection counts the
|
|
159
|
+
* per-WALLOPS cost grows linearly with the fleet; deployments should bound
|
|
160
|
+
* the oper's WALLOPS rate (an oper flooding WALLOPS is a self-DoS). The
|
|
161
|
+
* shard walk is parallelised via `Promise.all` so wall-clock stays near one
|
|
162
|
+
* round-trip for the enumeration phase.
|
|
163
|
+
*/
|
|
164
|
+
async broadcastWallops(lines: RawLine[], except?: ConnId): Promise<void> {
|
|
165
|
+
// Phase 1 — enumerate every connId across all registry shards.
|
|
166
|
+
const shardEntries = await Promise.all(
|
|
167
|
+
Array.from({ length: this.registryShards }, (_, i) => this.registryShardRpc(i).listEntries()),
|
|
168
|
+
);
|
|
169
|
+
const seen = new Set<ConnId>();
|
|
170
|
+
for (const entries of shardEntries) {
|
|
171
|
+
for (const [, connId] of entries) {
|
|
172
|
+
seen.add(connId);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Phase 2 — fetch each candidate's state, filter +w, deliver.
|
|
177
|
+
// Bound the per-call fan-out by skipping the excepted/bound connection
|
|
178
|
+
// up front (the bound connection's own +w never needs a self-RPC).
|
|
179
|
+
await Promise.all(
|
|
180
|
+
Array.from(seen, async (connId) => {
|
|
181
|
+
if (connId === except || connId === this.connId) return;
|
|
182
|
+
const stub = this.env.CONNECTION_DO.get(this.env.CONNECTION_DO.idFromString(connId));
|
|
183
|
+
const dto = await (stub as unknown as ConnectionRpc).getConnState();
|
|
184
|
+
if (dto === null) return;
|
|
185
|
+
const state = deserialize(dto);
|
|
186
|
+
if (!state.userModes.wallops) return;
|
|
187
|
+
await (stub as unknown as ConnectionRpc).deliver(lines);
|
|
188
|
+
}),
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
147
192
|
// -------------------------------------------------------------------------
|
|
148
193
|
// Nick registry
|
|
149
194
|
// -------------------------------------------------------------------------
|
|
@@ -247,9 +292,7 @@ export class CfRuntime implements IrcRuntime {
|
|
|
247
292
|
const out = new Map<ConnId, ConnectionState>();
|
|
248
293
|
await Promise.all(
|
|
249
294
|
memberIds.map(async (id) => {
|
|
250
|
-
const connStub = this.env.CONNECTION_DO.get(
|
|
251
|
-
this.env.CONNECTION_DO.idFromString(id),
|
|
252
|
-
);
|
|
295
|
+
const connStub = this.env.CONNECTION_DO.get(this.env.CONNECTION_DO.idFromString(id));
|
|
253
296
|
const dto = await (connStub as unknown as ConnectionRpc).getConnState();
|
|
254
297
|
if (dto !== null) {
|
|
255
298
|
out.set(id, deserialize(dto));
|
|
@@ -267,6 +310,16 @@ export class CfRuntime implements IrcRuntime {
|
|
|
267
310
|
return snapshots.filter((s): s is ChanSnapshot => s !== null);
|
|
268
311
|
}
|
|
269
312
|
|
|
313
|
+
/**
|
|
314
|
+
* Re-reads the bound Workers env (vars + secrets, the config source for
|
|
315
|
+
* Cloudflare deployments) and reparses it through the shared schema. The
|
|
316
|
+
* actor swaps its live config with the result; a rejection leaves the
|
|
317
|
+
* previous config in effect.
|
|
318
|
+
*/
|
|
319
|
+
async reloadConfig(): Promise<ServerConfig> {
|
|
320
|
+
return loadServerConfigFromCfEnv(this.env as unknown as CfConfigEnv);
|
|
321
|
+
}
|
|
322
|
+
|
|
270
323
|
// -------------------------------------------------------------------------
|
|
271
324
|
// Internal
|
|
272
325
|
// -------------------------------------------------------------------------
|
|
@@ -283,6 +336,16 @@ export class CfRuntime implements IrcRuntime {
|
|
|
283
336
|
return stub as unknown as RegistryRpc;
|
|
284
337
|
}
|
|
285
338
|
|
|
339
|
+
/**
|
|
340
|
+
* Returns the registry DO RPC stub for shard index `i` (`0 <= i < shards`).
|
|
341
|
+
* Used by global fan-out paths (WALLOPS) that must enumerate every shard
|
|
342
|
+
* rather than address the one owning a specific nick.
|
|
343
|
+
*/
|
|
344
|
+
private registryShardRpc(i: number): RegistryRpc {
|
|
345
|
+
const stub = this.env.REGISTRY_DO.get(this.env.REGISTRY_DO.idFromName(`s${i}`));
|
|
346
|
+
return stub as unknown as RegistryRpc;
|
|
347
|
+
}
|
|
348
|
+
|
|
286
349
|
/** Returns the channel DO RPC stub for `name` (keyed by lowercased name). */
|
|
287
350
|
private channelRpc(name: ChanName): {
|
|
288
351
|
broadcast(lines: unknown[], except?: string): Promise<void>;
|
|
@@ -321,7 +384,7 @@ export function makeCfRuntime(
|
|
|
321
384
|
handlers: CfConnectionHandlers,
|
|
322
385
|
): IrcRuntime {
|
|
323
386
|
// `_registryKey` is ignored — the production CfRuntime always shards the
|
|
324
|
-
// registry by nick (the prior per-conn key was a
|
|
387
|
+
// registry by nick (the prior per-conn key was a scaffolding
|
|
325
388
|
// convention that the real RegistryDO does not use).
|
|
326
389
|
void _registryKey;
|
|
327
390
|
return new CfRuntime(env, connId, handlers);
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
* RPC return-type note: snapshot reads return the JSON-friendly
|
|
31
31
|
* {@link ChannelSnapshotDto} (members/banMasks/pendingInvites as
|
|
32
32
|
* arrays) so they survive the DO RPC boundary without relying on
|
|
33
|
-
* structured-clone of `Map`/`Set`. The CfRuntime
|
|
33
|
+
* structured-clone of `Map`/`Set`. The CfRuntime
|
|
34
34
|
* rehydrates these into a full {@link ChanSnapshot} at the call site.
|
|
35
35
|
*/
|
|
36
36
|
|
|
@@ -89,7 +89,7 @@ export interface ConnectionDeliveryRpc {
|
|
|
89
89
|
* JSON-friendly snapshot DTO returned by `getChannelSnapshot`. Maps and
|
|
90
90
|
* Sets are flattened to arrays so the value survives the DO RPC
|
|
91
91
|
* boundary in both production and the test pool. The CfRuntime
|
|
92
|
-
*
|
|
92
|
+
* rehydrates this into a {@link ChanSnapshot} at the
|
|
93
93
|
* call site.
|
|
94
94
|
*/
|
|
95
95
|
export interface ChannelSnapshotDto {
|
|
@@ -22,6 +22,17 @@ import { type ParsedServerConfig, parseServerConfig } from '@serverless-ircd/irc
|
|
|
22
22
|
export interface CfConfigEnv {
|
|
23
23
|
SERVER_NAME?: string;
|
|
24
24
|
NETWORK_NAME?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Server version surfaced in `002`/`004`/`351`/`371`. When unset the
|
|
27
|
+
* schema default ({@link DEFAULT_SERVER_VERSION}) applies.
|
|
28
|
+
*/
|
|
29
|
+
SERVER_VERSION?: string;
|
|
30
|
+
/**
|
|
31
|
+
* "Created" text for `003 RPL_CREATED`. A numeric string is parsed into
|
|
32
|
+
* an epoch-ms number so the reducer formats it as a UTC timestamp; any
|
|
33
|
+
* other value is passed through verbatim.
|
|
34
|
+
*/
|
|
35
|
+
CREATED_AT?: string;
|
|
25
36
|
MOTD_LINES?: string;
|
|
26
37
|
MAX_CLIENTS?: string;
|
|
27
38
|
CHANNEL_PREFIXES?: string;
|
|
@@ -56,6 +67,12 @@ function buildConfigInput(env: CfConfigEnv): Record<string, unknown> {
|
|
|
56
67
|
serverName: env.SERVER_NAME,
|
|
57
68
|
networkName: env.NETWORK_NAME,
|
|
58
69
|
};
|
|
70
|
+
if (env.SERVER_VERSION !== undefined) {
|
|
71
|
+
input.serverVersion = env.SERVER_VERSION;
|
|
72
|
+
}
|
|
73
|
+
if (env.CREATED_AT !== undefined) {
|
|
74
|
+
input.createdAt = parseCreatedAt(env.CREATED_AT);
|
|
75
|
+
}
|
|
59
76
|
if (env.MOTD_LINES !== undefined && env.MOTD_LINES.length > 0) {
|
|
60
77
|
input.motdLines = env.MOTD_LINES.split('\n');
|
|
61
78
|
}
|
|
@@ -102,6 +119,22 @@ function buildConfigInput(env: CfConfigEnv): Record<string, unknown> {
|
|
|
102
119
|
return input;
|
|
103
120
|
}
|
|
104
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Parses the `CREATED_AT` env var into the schema's `createdAt` field.
|
|
124
|
+
*
|
|
125
|
+
* A purely numeric string is treated as epoch-ms (returned as a number so
|
|
126
|
+
* the reducer formats it as a UTC timestamp); any other value is returned
|
|
127
|
+
* verbatim as a human-readable string. Empty strings fall through to the
|
|
128
|
+
* schema default (the caller only invokes this when the env var is set).
|
|
129
|
+
*/
|
|
130
|
+
function parseCreatedAt(raw: string): string | number {
|
|
131
|
+
if (/^\d+$/.test(raw.trim())) {
|
|
132
|
+
const n = Number(raw.trim());
|
|
133
|
+
if (Number.isFinite(n)) return n;
|
|
134
|
+
}
|
|
135
|
+
return raw;
|
|
136
|
+
}
|
|
137
|
+
|
|
105
138
|
/**
|
|
106
139
|
* Parses a newline-delimited `username:password` string into the config's
|
|
107
140
|
* `saslAccounts` shape. Malformed entries are skipped so a trailing
|