serverless-ircd 0.4.0 → 0.6.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 +34 -2
- package/.github/workflows/deploy-aws.yml +1 -2
- package/.github/workflows/deploy-cf-tcp.yml +1 -5
- package/.github/workflows/deploy-cf.yml +1 -2
- package/CHANGELOG.md +435 -0
- package/README.md +206 -27
- package/apps/aws-stack/README.md +37 -3
- package/apps/aws-stack/package.json +1 -1
- package/apps/aws-stack/src/aws-stack.ts +106 -13
- package/apps/aws-stack/tests/coverage-command.test.ts +155 -0
- package/apps/aws-stack/tests/stack.test.ts +49 -3
- package/apps/aws-stack/tests/synth-no-bundle.test.ts +129 -0
- package/apps/aws-stack/tests/vitest.setup.ts +18 -0
- package/apps/aws-stack/vitest.config.ts +3 -0
- package/apps/cf-tcp-container/package.json +1 -1
- package/apps/cf-tcp-container/src/config-loader.ts +6 -7
- package/apps/cf-tcp-container/src/container-server.ts +3 -0
- package/apps/cf-tcp-container/tests/config-loader.test.ts +10 -3
- package/apps/cf-tcp-container/wrangler.toml +1 -1
- package/apps/cf-worker/package.json +2 -1
- package/apps/cf-worker/vitest.config.ts +1 -1
- package/apps/cf-worker/wrangler.toml +5 -3
- package/apps/local-cli/package.json +1 -1
- package/apps/local-cli/src/config-loader.ts +6 -6
- package/apps/local-cli/src/main.ts +20 -0
- package/apps/local-cli/src/server.ts +138 -28
- package/apps/local-cli/tests/e2e.test.ts +113 -29
- package/apps/local-cli/tests/tcp.test.ts +71 -19
- package/apps/local-cli/tests/ws-subprotocol.test.ts +262 -0
- package/biome.json +1 -0
- package/docs/ADR-001-pure-reducers-and-effect-system.md +74 -0
- package/docs/ADR-002-location-of-authority.md +82 -0
- package/docs/ADR-003-durable-object-sharding.md +110 -0
- package/docs/ADR-004-dynamodb-schema.md +96 -0
- package/docs/ADR-005-wss-only-transport-v1.md +83 -0
- package/docs/ADR-006-sasl-mechanism-scope.md +96 -0
- package/docs/ADR-007-deterministic-ports.md +82 -0
- package/docs/ADR-008-monorepo-tooling.md +60 -0
- package/docs/ADR-009-dual-transport-wss-and-irc-tls.md +138 -0
- package/docs/ADR-Index.md +15 -0
- package/docs/AWS-Adapter-Architecture.md +496 -0
- package/docs/AWS-Deployment.md +1275 -0
- package/docs/AWS-TCP-Deployment.md +410 -0
- package/docs/Cloudflare-Deployment-Guide.md +719 -0
- package/docs/Cloudflare-TCP-Deployment.md +510 -0
- package/docs/Home.md +15 -0
- package/docs/Observability.md +87 -0
- package/docs/PlanExtensions.md +812 -0
- package/docs/PlanIRCv3Websocket.md +503 -0
- package/docs/PlanWebClient.md +451 -0
- package/docs/Release-Process.md +443 -0
- package/package.json +2 -2
- package/packages/aws-adapter/package.json +1 -1
- package/packages/aws-adapter/src/aws-runtime.ts +69 -0
- package/packages/aws-adapter/src/handlers/connect.ts +36 -5
- package/packages/aws-adapter/src/handlers/default.ts +66 -5
- package/packages/aws-adapter/src/handlers/index.ts +41 -2
- package/packages/aws-adapter/src/handlers/nlb-stream.ts +18 -0
- package/packages/aws-adapter/src/index.ts +2 -0
- package/packages/aws-adapter/src/serialize.ts +40 -2
- package/packages/aws-adapter/src/stats.ts +80 -0
- package/packages/aws-adapter/tests/account-store-dynamo.test.ts +49 -8
- package/packages/aws-adapter/tests/account-store.test.ts +4 -7
- package/packages/aws-adapter/tests/aws-harness.ts +5 -2
- package/packages/aws-adapter/tests/aws-integration.test.ts +8 -4
- package/packages/aws-adapter/tests/aws-runtime.test.ts +140 -0
- package/packages/aws-adapter/tests/config-loader.test.ts +11 -2
- package/packages/aws-adapter/tests/connect.test.ts +100 -4
- package/packages/aws-adapter/tests/disconnect-fanout.test.ts +3 -4
- package/packages/aws-adapter/tests/global-setup.ts +55 -30
- package/packages/aws-adapter/tests/gone-exception.test.ts +4 -9
- package/packages/aws-adapter/tests/handlers.test.ts +238 -4
- package/packages/aws-adapter/tests/message-store.test.ts +6 -5
- package/packages/aws-adapter/tests/nlb-stream.test.ts +62 -8
- package/packages/aws-adapter/tests/stats.test.ts +317 -0
- package/packages/cf-adapter/package.json +6 -1
- package/packages/cf-adapter/src/cf-runtime.ts +66 -1
- package/packages/cf-adapter/src/channel-do.ts +2 -2
- package/packages/cf-adapter/src/connection-do.ts +185 -54
- package/packages/cf-adapter/src/env.ts +25 -6
- package/packages/cf-adapter/src/index.ts +2 -0
- package/packages/cf-adapter/src/registry-do.ts +22 -3
- package/packages/cf-adapter/src/serialize.ts +25 -4
- 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 +1 -1
- package/packages/cf-adapter/tests/cf-integration.test.ts +4 -4
- package/packages/cf-adapter/tests/cf-runtime.test.ts +307 -2
- package/packages/cf-adapter/tests/channel-do.test.ts +119 -2
- package/packages/cf-adapter/tests/config-loader.test.ts +49 -0
- package/packages/cf-adapter/tests/connection-do-channel-registration.test.ts +2 -2
- package/packages/cf-adapter/tests/connection-do-no-batching-reservation.test.ts +2 -2
- package/packages/cf-adapter/tests/connection-do-pure.test.ts +91 -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 +48 -0
- package/packages/cf-adapter/tests/registry-do.test.ts +108 -4
- package/packages/cf-adapter/tests/serialize.test.ts +308 -0
- 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 +7 -7
- 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/vitest.config.ts +1 -1
- package/packages/cf-adapter/wrangler.test.toml +7 -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 +1 -1
- package/packages/irc-core/src/admission.ts +16 -15
- package/packages/irc-core/src/caps/capabilities.ts +38 -4
- package/packages/irc-core/src/caps/index.ts +1 -0
- package/packages/irc-core/src/caps/sts.ts +84 -0
- package/packages/irc-core/src/commands/account-notify.ts +53 -0
- package/packages/irc-core/src/commands/away.ts +9 -3
- package/packages/irc-core/src/commands/cap.ts +23 -5
- package/packages/irc-core/src/commands/chathistory.ts +40 -11
- package/packages/irc-core/src/commands/index.ts +42 -0
- package/packages/irc-core/src/commands/invite.ts +2 -4
- package/packages/irc-core/src/commands/isupport.ts +59 -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 +12 -9
- package/packages/irc-core/src/commands/monitor.ts +327 -0
- package/packages/irc-core/src/commands/multiline.ts +256 -0
- 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/pre-away.ts +112 -0
- package/packages/irc-core/src/commands/privmsg.ts +19 -12
- package/packages/irc-core/src/commands/read-marker.ts +108 -0
- package/packages/irc-core/src/commands/registration.ts +8 -0
- package/packages/irc-core/src/commands/rehash.ts +119 -0
- package/packages/irc-core/src/commands/sasl.ts +24 -1
- 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/tagmsg.ts +71 -1
- 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/wallops.ts +118 -0
- package/packages/irc-core/src/commands/whois.ts +5 -0
- package/packages/irc-core/src/config.ts +72 -10
- package/packages/irc-core/src/effects.ts +41 -1
- package/packages/irc-core/src/index.ts +2 -0
- package/packages/irc-core/src/ports.ts +568 -0
- package/packages/irc-core/src/protocol/index.ts +14 -0
- package/packages/irc-core/src/protocol/labeled-response.ts +133 -0
- package/packages/irc-core/src/protocol/numerics.ts +57 -11
- package/packages/irc-core/src/protocol/outbound.ts +36 -4
- package/packages/irc-core/src/protocol/standard-replies.ts +277 -0
- package/packages/irc-core/src/state/connection.ts +32 -1
- package/packages/irc-core/src/types.ts +120 -1
- package/packages/irc-core/src/ws-framing.ts +132 -0
- package/packages/irc-core/src/ws-subprotocol.ts +66 -0
- package/packages/irc-core/stryker.commands.conf.json +1 -2
- package/packages/irc-core/tests/admission.test.ts +18 -0
- package/packages/irc-core/tests/away-store.test.ts +73 -0
- package/packages/irc-core/tests/caps/capabilities.test.ts +119 -2
- package/packages/irc-core/tests/caps/sts.test.ts +123 -0
- package/packages/irc-core/tests/commands/account-notify.test.ts +171 -0
- package/packages/irc-core/tests/commands/away.test.ts +85 -2
- package/packages/irc-core/tests/commands/cap.test.ts +165 -0
- package/packages/irc-core/tests/commands/chathistory.test.ts +148 -1
- package/packages/irc-core/tests/commands/echo-message.test.ts +9 -3
- package/packages/irc-core/tests/commands/isupport.test.ts +80 -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 +129 -0
- package/packages/irc-core/tests/commands/monitor.test.ts +411 -0
- package/packages/irc-core/tests/commands/multiline.test.ts +428 -0
- package/packages/irc-core/tests/commands/pre-away.test.ts +241 -0
- package/packages/irc-core/tests/commands/privmsg.test.ts +154 -3
- package/packages/irc-core/tests/commands/read-marker.test.ts +211 -0
- package/packages/irc-core/tests/commands/registration.test.ts +64 -0
- package/packages/irc-core/tests/commands/rehash.test.ts +171 -0
- package/packages/irc-core/tests/commands/sasl.test.ts +116 -2
- 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 +357 -0
- package/packages/irc-core/tests/commands/trace.test.ts +282 -0
- package/packages/irc-core/tests/commands/wallops.test.ts +231 -0
- package/packages/irc-core/tests/commands/whois.test.ts +34 -0
- package/packages/irc-core/tests/config.test.ts +103 -13
- package/packages/irc-core/tests/dropped-s2s-and-obsolete-verbs.test.ts +90 -0
- package/packages/irc-core/tests/effects.test.ts +14 -0
- package/packages/irc-core/tests/labeled-response.test.ts +181 -0
- package/packages/irc-core/tests/message-tags.test.ts +114 -0
- package/packages/irc-core/tests/monitor-store.test.ts +200 -0
- package/packages/irc-core/tests/numerics.test.ts +90 -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/read-marker-store.test.ts +108 -0
- package/packages/irc-core/tests/standard-replies.test.ts +412 -0
- package/packages/irc-core/tests/stats-store.test.ts +222 -0
- package/packages/irc-core/tests/types.test.ts +27 -0
- 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-server/package.json +1 -1
- package/packages/irc-server/src/actor.ts +699 -19
- package/packages/irc-server/src/dispatch.ts +109 -16
- package/packages/irc-server/src/routing.ts +3 -0
- package/packages/irc-server/src/runtime.ts +31 -0
- package/packages/irc-server/src/transport.ts +10 -7
- package/packages/irc-server/tests/actor.test.ts +2523 -42
- package/packages/irc-server/tests/dispatch.test.ts +300 -2
- package/packages/irc-server/tests/raw-modules.d.ts +11 -0
- package/packages/irc-server/tests/routing.test.ts +1 -0
- package/packages/irc-server/tests/runtime.test.ts +7 -0
- package/packages/irc-test-support/package.json +1 -1
- package/packages/irc-test-support/src/index.ts +6 -0
- package/packages/irc-test-support/src/scenarios.ts +9 -1
- package/packages/irc-test-support/src/test-config.ts +54 -0
- package/packages/irc-test-support/tests/in-memory-scenarios.test.ts +1 -1
- package/packages/irc-test-support/tests/test-config.test.ts +51 -0
- package/pnpm-workspace.yaml +1 -0
- package/tools/ci-hardening/package.json +1 -1
- package/tools/ci-hardening/tests/ddb-local.test.ts +82 -0
- package/tools/load-test/package.json +33 -0
- package/tools/load-test/src/client.ts +351 -0
- package/tools/load-test/src/config.ts +313 -0
- package/tools/load-test/src/harness.ts +116 -0
- package/tools/load-test/src/main.ts +120 -0
- package/tools/load-test/src/metrics.ts +168 -0
- package/tools/load-test/src/report.ts +106 -0
- package/tools/load-test/tests/client.test.ts +212 -0
- package/tools/load-test/tests/config.test.ts +152 -0
- package/tools/load-test/tests/framing.test.ts +37 -0
- package/tools/load-test/tests/harness.test.ts +165 -0
- package/tools/load-test/tests/metrics.test.ts +174 -0
- package/tools/load-test/tests/report.test.ts +161 -0
- package/tools/load-test/tests/smoke.test.ts +67 -0
- package/tools/load-test/tsconfig.build.json +12 -0
- package/tools/load-test/tsconfig.test.json +10 -0
- package/tools/load-test/vitest.config.ts +29 -0
- package/tools/package.json +6 -1
- package/tools/seed-cf-accounts.ts +4 -1
- 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/.github/workflows/ci.yml
CHANGED
|
@@ -42,6 +42,32 @@ jobs:
|
|
|
42
42
|
node-version: 24
|
|
43
43
|
cache: pnpm
|
|
44
44
|
|
|
45
|
+
# DynamoDB Local capability for `aws-adapter` coverage.
|
|
46
|
+
#
|
|
47
|
+
# The `aws-adapter` package's vitest `globalSetup` boots a real
|
|
48
|
+
# DynamoDB Local instance so the integration suite (handlers,
|
|
49
|
+
# aws-runtime, transactions, …) can be exercised under coverage.
|
|
50
|
+
# Without it, 171 of 294 tests `describe.skipIf` away and the
|
|
51
|
+
# package drops to ~42% coverage, blowing the 90% gate.
|
|
52
|
+
#
|
|
53
|
+
# The self-hosted Gitea runner image (`ubuntu-latest`) ships with
|
|
54
|
+
# neither Docker (testcontainers' Ryuk reaper fails with "Failed
|
|
55
|
+
# to connect to Reaper" without a `docker.sock` mount or
|
|
56
|
+
# privileged mode) nor a JRE. We install a JRE here via the
|
|
57
|
+
# canonical `setup-java` action so the globalSetup's ZIP fallback
|
|
58
|
+
# can fire — this is the only strategy the runner image can
|
|
59
|
+
# support without host-level privileged-mode configuration.
|
|
60
|
+
#
|
|
61
|
+
# `DDB_LOCAL_STRATEGY=zip` is pinned on the coverage step below
|
|
62
|
+
# so the globalSetup skips the testcontainers probe entirely
|
|
63
|
+
# (otherwise it blocks for ~60s waiting for Ryuk before falling
|
|
64
|
+
# back, which is flaky and wastes CI minutes).
|
|
65
|
+
- name: Setup Java (JRE for DynamoDB Local ZIP fallback)
|
|
66
|
+
uses: actions/setup-java@v4
|
|
67
|
+
with:
|
|
68
|
+
distribution: temurin
|
|
69
|
+
java-version: '11'
|
|
70
|
+
|
|
45
71
|
- name: Install dependencies
|
|
46
72
|
run: pnpm install --frozen-lockfile
|
|
47
73
|
|
|
@@ -52,6 +78,12 @@ jobs:
|
|
|
52
78
|
run: pnpm typecheck
|
|
53
79
|
|
|
54
80
|
- name: Test with coverage
|
|
81
|
+
# `DDB_LOCAL_STRATEGY=zip` pins the DynamoDB Local boot to the
|
|
82
|
+
# Java ZIP fallback (see the `Setup Java` step above for why).
|
|
83
|
+
# This skips the testcontainers probe so the runner does not
|
|
84
|
+
# block ~60s waiting for Ryuk before falling back.
|
|
85
|
+
env:
|
|
86
|
+
DDB_LOCAL_STRATEGY: zip
|
|
55
87
|
run: pnpm coverage
|
|
56
88
|
|
|
57
89
|
- name: Coverage gate (coverage-thresholds enforced per package)
|
|
@@ -90,7 +122,7 @@ jobs:
|
|
|
90
122
|
|
|
91
123
|
- name: Upload coverage
|
|
92
124
|
if: always()
|
|
93
|
-
uses: actions/upload-artifact@
|
|
125
|
+
uses: actions/upload-artifact@v3
|
|
94
126
|
with:
|
|
95
127
|
name: coverage
|
|
96
128
|
path: |
|
|
@@ -135,7 +167,7 @@ jobs:
|
|
|
135
167
|
|
|
136
168
|
- name: Upload mutation report
|
|
137
169
|
if: always()
|
|
138
|
-
uses: actions/upload-artifact@
|
|
170
|
+
uses: actions/upload-artifact@v3
|
|
139
171
|
with:
|
|
140
172
|
name: mutation-report
|
|
141
173
|
path: packages/irc-core/reports/mutation
|
|
@@ -16,11 +16,7 @@ name: deploy-cf-tcp
|
|
|
16
16
|
# CF_TCP_ORIGIN_ADDRESS Hostname/IP of the container origin.
|
|
17
17
|
|
|
18
18
|
on:
|
|
19
|
-
push
|
|
20
|
-
branches: [main]
|
|
21
|
-
paths:
|
|
22
|
-
- 'apps/cf-tcp-container/**'
|
|
23
|
-
- '.github/workflows/deploy-cf-tcp.yml'
|
|
19
|
+
# Automatic push trigger disabled; deploy only runs manually.
|
|
24
20
|
workflow_dispatch:
|
|
25
21
|
|
|
26
22
|
concurrency:
|
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,441 @@ For the release process itself — versioning policy, pre-release checklist,
|
|
|
10
10
|
cutting a tag, rolling back — see [`docs/release.md`](docs/release.md).
|
|
11
11
|
Cross-reference `progress.md` / `tickets.md` for per-ticket detail.
|
|
12
12
|
|
|
13
|
+
## [0.6.0] - 2026-08-03
|
|
14
|
+
|
|
15
|
+
The headline is the **IRCv3 extension sweep (Phase 12)**: ten negotiated
|
|
16
|
+
caps and the user-mode-`S` TLS indicator land in one release, taking the
|
|
17
|
+
negotiated capability surface from "modern baseline" to "draft-leading-
|
|
18
|
+
edge". Alongside it: the **required-`serverName` config gate** (the
|
|
19
|
+
last open v0.5.0 follow-up), a new **`tools/load-test`** client farm
|
|
20
|
+
(Phase 7's 10k-connection harness), and the **coverage / CI unblocks**
|
|
21
|
+
that lift `aws-adapter` over the 90% gate and switch `cf-adapter` /
|
|
22
|
+
`cf-worker` to istanbul (clearing the v0.5.0 workerd-incompatibility
|
|
23
|
+
caveat). Deploy workflows are now **manual-only** (`workflow_dispatch`).
|
|
24
|
+
|
|
25
|
+
### Added — IRCv3 extensions (`@serverless-ircd/irc-core`, `@serverless-ircd/irc-server`)
|
|
26
|
+
|
|
27
|
+
The ten Phase 12 cap tickets light up the remaining negotiated-cap
|
|
28
|
+
surface, and the two non-cap Phase 12 tickets (ISUPPORT tokens and
|
|
29
|
+
user mode `S`) round out the wire-visible advertisement. Each cap
|
|
30
|
+
ships a pure reducer (where applicable), an actor route case,
|
|
31
|
+
advertisement in `SUPPORTED_CAPABILITIES` (or conditional
|
|
32
|
+
advertisement for `sts`), and unit + actor coverage. The
|
|
33
|
+
pure-reducer / dispatch pipeline is unchanged — every cap is plumbed
|
|
34
|
+
through `ctx` and emitted `Effect[]`, never performed in the handler.
|
|
35
|
+
|
|
36
|
+
- **`account-notify`**: pushes `:nick ACCOUNT <name|*>`
|
|
37
|
+
to peers in shared channels (excluding the sender unless
|
|
38
|
+
`echo-message`) on SASL login / logout. Closes the
|
|
39
|
+
`account-tag` / `extended-join` / `account-notify` triple modern
|
|
40
|
+
clients render fully.
|
|
41
|
+
- **`msgid`**: every PRIVMSG / NOTICE / TAGMSG fanned out
|
|
42
|
+
to a cap-enabled peer carries `@+msgid=<id>` from
|
|
43
|
+
`IdFactory.nonce()`. The nonce is **shared between the live fanout
|
|
44
|
+
and the `draft/chathistory` record** so a peer sees the same id live
|
|
45
|
+
and on replay. Legacy peers see no `msgid` tag.
|
|
46
|
+
- **`standard-replies`**: a data-driven
|
|
47
|
+
`numericToStandardReply` table replaces a curated subset of bare
|
|
48
|
+
numerics (`461`, `403`, `432`, `433`, SASL failures, …) with
|
|
49
|
+
`FAIL`/`WARN`/`NOTE COMMAND code context :description` for
|
|
50
|
+
cap-enabled clients. Legacy clients still receive the unchanged
|
|
51
|
+
numeric. Numeric-only replies (MOTD lines, NAMES, …) stay on their
|
|
52
|
+
numeric form.
|
|
53
|
+
- **`MONITOR`**: the modern `ISON` replacement. Implements
|
|
54
|
+
`MONITOR + nick{,nick}` / `- nick` / `C` / `L` / `S` with the
|
|
55
|
+
`730 RPL_MONONLINE` / `731 RPL_MONOFFLINE` / `732 RPL_MONLIST` /
|
|
56
|
+
`734 ERR_MONLISTFULL` numerics. Online/offline transitions push
|
|
57
|
+
`730`/`731` **asynchronously** via the Registry's nick reserve /
|
|
58
|
+
release hooks (a new `MonitorStore` port + push callback). The
|
|
59
|
+
ceiling is config-driven (`MONITOR=<n>`, default 30).
|
|
60
|
+
- **`labeled-response`**: a client-sent `+label=<id>` is
|
|
61
|
+
plumbed through `ctx` and every reply caused by that message is
|
|
62
|
+
wrapped in a single `BATCH +id labeled-response … BATCH -id`. A
|
|
63
|
+
command that produces no reply emits an empty labeled batch (spec-
|
|
64
|
+
mandated). The label travels on every reducer's emitted effects,
|
|
65
|
+
so multi-reply commands accumulate under one batch.
|
|
66
|
+
- **`sts`**: Strict Transport Security. The cap is
|
|
67
|
+
**conditionally advertised** — only when `ServerConfig.sts`
|
|
68
|
+
(`{ duration, port, preload? }`) is supplied. On a plaintext
|
|
69
|
+
listener a compliant client upgrades; on the TLS listener the
|
|
70
|
+
duration is still sent to lock in the policy. Defaults:
|
|
71
|
+
`duration = 30 days`, `port = 6697`.
|
|
72
|
+
- **`draft/typing`**: `TAGMSG <target> +draft/typing=
|
|
73
|
+
active|paused|done` broadcasts to channel members (or routes to a
|
|
74
|
+
nick target), excluding the sender unless `echo-message`. The
|
|
75
|
+
`+draft/typing=*` client tag is whitelisted for clients without
|
|
76
|
+
`message-tags` (per the spec's client-tag exception). Broadcast
|
|
77
|
+
delivery uses **OR-semantics**: a recipient qualifies if it
|
|
78
|
+
negotiated `message-tags` **or** `draft/typing` (a new `caps` field
|
|
79
|
+
on `BroadcastEffect`).
|
|
80
|
+
- **`draft/multiline`**: a cap-enabled
|
|
81
|
+
client sends `BATCH +id draft/multiline :target` + N PRIVMSG/NOTICE
|
|
82
|
+
lines + `BATCH -id`. The server concatenates per spec (with `\n`),
|
|
83
|
+
enforces a configurable byte budget (`multilineMaxBytes`, default
|
|
84
|
+
4096), and broadcasts the batched replay to multiline peers / a
|
|
85
|
+
single joined PRIVMSG (carrying `+draft/multiline`) to legacy
|
|
86
|
+
peers. **Nick-target routing**, **chathistory recording** (one
|
|
87
|
+
record per batch carrying the joined body, assigned `msgid`, and
|
|
88
|
+
the `+draft/multiline` client tag), and **tag gating** (the
|
|
89
|
+
`+draft/multiline` tag is stripped for peers without
|
|
90
|
+
`message-tags`) all land in the completion ticket.
|
|
91
|
+
- **`draft/read-marker`**: persists the per-`(account,
|
|
92
|
+
channel)` last-read marker in a new `ReadMarkerStore` port,
|
|
93
|
+
propagates updates via `+draft/read-marker=<msgid>` tags, and
|
|
94
|
+
seeds a fresh connection's marker from the persisted value at
|
|
95
|
+
identify time. `CHATHISTORY BEFORE` honours the marker when no
|
|
96
|
+
explicit pivot is supplied.
|
|
97
|
+
- **`draft/pre-away`**: persists the away reason in a
|
|
98
|
+
new `AwayStore` port keyed by account. On identify (or SASL login)
|
|
99
|
+
the server re-applies the away state and emits the `AWAY` line +
|
|
100
|
+
`306 RPL_NOWAWAY` as if the user had sent `AWAY :reason`
|
|
101
|
+
themselves. `AWAY` (unset) clears the persisted reason.
|
|
102
|
+
- **ISUPPORT tokens for the new caps**: `005
|
|
103
|
+
RPL_ISUPPORT` now advertises `STATUSMSG=@+`, `EXTBAN=<prefix>,q`,
|
|
104
|
+
`ACCOUNTEXTBAN=a` (services-gated), `TYPING`, and `MULTILINE`.
|
|
105
|
+
`MONITOR=<n>` honours `serverConfig.monitorLimit`. Tokens are
|
|
106
|
+
config-derived where applicable.
|
|
107
|
+
- **User mode `S` (TLS connected)**: the transport's
|
|
108
|
+
TLS fact is surfaced end-to-end as a read-only user mode. Set
|
|
109
|
+
once by the registration reducer from `ConnectionState.secure`;
|
|
110
|
+
emitted in `221 … +S`; rejected by `MODE nick +/-S` with `501
|
|
111
|
+
ERR_UMODEUNKNOWNFLAG`; surfaced in WHOIS via the new `276
|
|
112
|
+
RPL_WHOISSECURE`. Each adapter asserts `secure: true` where the
|
|
113
|
+
platform terminates TLS (API Gateway, CF edge, Spectrum, NLB TLS
|
|
114
|
+
listener).
|
|
115
|
+
|
|
116
|
+
### Changed — Required server identity
|
|
117
|
+
|
|
118
|
+
The last open v0.5.0 follow-up closes. The `irc.example.com`
|
|
119
|
+
placeholder `DEFAULT_SERVER_CONFIG` is **removed** from
|
|
120
|
+
`irc-core`; the shared `ServerConfigSchema` rejects a missing
|
|
121
|
+
`serverName` / `networkName` so every adapter **fails fast at boot**
|
|
122
|
+
with a readable, field-listing error.
|
|
123
|
+
|
|
124
|
+
- **`@serverless-ircd/irc-core`**: `DEFAULT_SERVER_CONFIG` removed.
|
|
125
|
+
- **`@serverless-ircd/irc-test-support`**: ships a clearly test-scoped
|
|
126
|
+
`makeTestServerConfig()` baseline (`irc.test.local`) so unit tests
|
|
127
|
+
construct a `ServerConfig` without re-introducing a production
|
|
128
|
+
default.
|
|
129
|
+
- `apps/cf-worker` + `apps/cf-tcp-container`: loaders require
|
|
130
|
+
`SERVER_NAME`; `wrangler.toml` samples switched to
|
|
131
|
+
`irc.your-domain.invalid`.
|
|
132
|
+
- `apps/aws-stack` + `apps/local-cli`: keep obviously-local fallbacks
|
|
133
|
+
(`irc.localhost`) documented as *"production MUST override"*;
|
|
134
|
+
`local-cli` gains `--server-name` / `--network-name` flags.
|
|
135
|
+
|
|
136
|
+
### Added — Load-test harness (`@serverless-ircd/load-test`)
|
|
137
|
+
|
|
138
|
+
PLAN §7 / Phase 7's 10k-connection harness. A synthetic WebSocket IRC
|
|
139
|
+
client farm: opens N connections, registers (NICK/USER), joins a
|
|
140
|
+
channel, and optionally chats. Captures **p50 / p95 / p99 latency per
|
|
141
|
+
phase** (connect / register / join / message) plus the **drop rate**,
|
|
142
|
+
and prints a markdown report to stdout (or `--report <path>`).
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
pnpm --filter load-test start -- \
|
|
146
|
+
--target wss://irc.staging.example.com/ \
|
|
147
|
+
--connections 10000 --concurrency 200 --ramp-ms 60000 \
|
|
148
|
+
--channel '#loadtest' --messages 3 --platform cf-staging \
|
|
149
|
+
--report reports/cf-staging-2026-08-03.md
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
The package ships its own vitest suite (config parsing, framing,
|
|
153
|
+
harness, metrics, report) at ≥90% coverage; no production source in
|
|
154
|
+
the irc-core / irc-server packages changed to support it.
|
|
155
|
+
|
|
156
|
+
### Added — Coverage / CI unblocks
|
|
157
|
+
|
|
158
|
+
- **`aws-adapter` clears the 90% gate.** The self-hosted runner image
|
|
159
|
+
ships with neither Docker nor a JRE, so the package's
|
|
160
|
+
testcontainers / Java-ZIP DynamoDB Local boot fell through to
|
|
161
|
+
strategy 3 and 171 of 294 integration tests `describe.skipIf`-ed
|
|
162
|
+
away — dropping coverage to ~42% and blowing the gate. CI now
|
|
163
|
+
installs Temurin JRE 11 via `actions/setup-java@v4` and pins
|
|
164
|
+
`DDB_LOCAL_STRATEGY=zip` on the coverage step so the ZIP fallback
|
|
165
|
+
fires deterministically. The full aws-adapter suite now runs on
|
|
166
|
+
every coverage job. New integration tests cover
|
|
167
|
+
`broadcastWallops` fan-out, `reserveNick` non-conditional error
|
|
168
|
+
propagation, `refreshChannel` empty-members / topic-preservation
|
|
169
|
+
paths, NLB header fallbacks, scan-row type guards, and
|
|
170
|
+
`CREATED_AT` overflow handling. `tools/ci-hardening` gained a
|
|
171
|
+
self-check asserting the JRE install + strategy pin remain wired.
|
|
172
|
+
- **`aws-stack` coverage command repaired.** The CDK `NodejsFunction`
|
|
173
|
+
in the test synth re-bundled the Lambda asset via esbuild ~80
|
|
174
|
+
times per coverage run and OOM-ed CI before vitest could print a
|
|
175
|
+
report. A new `makeLambda()` factory switches between
|
|
176
|
+
`NodejsFunction` (production synth) and an inline-zip `Function`
|
|
177
|
+
stub (tests) via the `IRC_AWS_STACK_TEST_NO_BUNDLE` env var. The
|
|
178
|
+
stub preserves every CloudFormation shape the suite asserts on
|
|
179
|
+
while making bundling a no-op. New
|
|
180
|
+
`tests/synth-no-bundle.test.ts` + `tests/coverage-command.test.ts`
|
|
181
|
+
lock both branches and assert the `pnpm coverage` run prints an
|
|
182
|
+
`All files` row.
|
|
183
|
+
- **`cf-adapter` / `cf-worker` switch to istanbul coverage.** This
|
|
184
|
+
**resolves the v0.5.0 known limitation**: `@vitest/coverage-v8`
|
|
185
|
+
v4.1.x imports `node:inspector/promises`, which the
|
|
186
|
+
`@cloudflare/vitest-pool-workers` (workerd) pool cannot resolve.
|
|
187
|
+
Both packages now use `@vitest/coverage-istanbul` so `pnpm
|
|
188
|
+
coverage` loads under workerd. Edge-case suites were expanded
|
|
189
|
+
(serialize/deserialize/migrate, connection-do pure helpers,
|
|
190
|
+
`broadcastWallops` fan-out, `changeNick` shard routing,
|
|
191
|
+
ChannelDO broadcast/cache, RegistryDO `listEntries`, SASL seed
|
|
192
|
+
parsing).
|
|
193
|
+
|
|
194
|
+
### Changed — Deploy workflows are now manual-only
|
|
195
|
+
|
|
196
|
+
`deploy-cf.yml`, `deploy-cf-tcp.yml`, and `deploy-aws.yml` dropped
|
|
197
|
+
their `push: branches: [main]` triggers and now run on
|
|
198
|
+
`workflow_dispatch` only. Staging deploys are no longer fired
|
|
199
|
+
automatically on every merge to `main`; a maintainer kicks them off
|
|
200
|
+
by hand. The release runbook (`docs/Release-Process.md`) is the
|
|
201
|
+
canonical reference either way — there was never a CI auto-deploy to
|
|
202
|
+
production.
|
|
203
|
+
|
|
204
|
+
### Changed — `@vitest/coverage-istanbul` peer
|
|
205
|
+
|
|
206
|
+
The root lockfile (`pnpm-lock.yaml`) registers the
|
|
207
|
+
`@vitest/coverage-istanbul` peer introduced by the cf-adapter /
|
|
208
|
+
cf-worker coverage switch. No operator action; `pnpm install`
|
|
209
|
+
resolves it.
|
|
210
|
+
|
|
211
|
+
### ⚠️ Migration required
|
|
212
|
+
|
|
213
|
+
- **`serverName` is now required at boot.** Operators who relied on
|
|
214
|
+
the silent `irc.example.com` placeholder must supply an explicit
|
|
215
|
+
value via their adapter's config knob:
|
|
216
|
+
- **Cloudflare Worker / TCP container**: set `SERVER_NAME` (and
|
|
217
|
+
`NETWORK_NAME` if desired) in `wrangler.toml` `[vars]` or via
|
|
218
|
+
`wrangler secret put`. The samples switched to
|
|
219
|
+
`irc.your-domain.invalid` — replace with your real hostname.
|
|
220
|
+
- **AWS**: the CDK stack's `serverName` prop / `SERVER_NAME` env
|
|
221
|
+
var. The local fallback is `irc.localhost` and is explicitly
|
|
222
|
+
documented as "production MUST override".
|
|
223
|
+
- **`local-cli`**: new `--server-name <h>` / `--network-name <n>`
|
|
224
|
+
flags (default `irc.localhost` / `LocalNet`).
|
|
225
|
+
A missing value now throws an aggregated `"Invalid server
|
|
226
|
+
config:"` error at boot listing every offending field.
|
|
227
|
+
- **No persisted-state schema change.** `PERSISTED_STATE_VERSION`
|
|
228
|
+
stays `1`. The user-mode-`S` work adds a `secure` field and a
|
|
229
|
+
`userModes.tls` field to the persisted shape, but both are purely
|
|
230
|
+
**additive with `false` defaults** and the cf-adapter `migrate()`
|
|
231
|
+
path backfills them on pre-feature records. **Code rollback across
|
|
232
|
+
this release is safe.**
|
|
233
|
+
- No toolchain change. Node ≥ 24 / pnpm 11 (from v0.4.0) still apply.
|
|
234
|
+
|
|
235
|
+
### Known limitations
|
|
236
|
+
|
|
237
|
+
- Same transport limits as v0.5.0: the **CF TCP path requires
|
|
238
|
+
Cloudflare Spectrum (Enterprise tier)** plus a stateful Container
|
|
239
|
+
origin; the **AWS TCP path** uses NLB + Lambda streaming and is
|
|
240
|
+
subject to Lambda idle-timeout / stream-duration limits. The
|
|
241
|
+
WebSocket path remains the zero-extra-deps default.
|
|
242
|
+
- **mTLS (for SASL `EXTERNAL`) requires a custom domain + uploaded
|
|
243
|
+
CA/trust-store** on both platforms and is not enabled by default.
|
|
244
|
+
- `STATS` ships the `u` + `l` query letters; the full RFC matrix
|
|
245
|
+
(`k`, `K`, `q`, `g`, `x`, `z`, …) is intentionally out of scope for
|
|
246
|
+
v1 — unknown letters get the charybdis-style empty body + `219`.
|
|
247
|
+
- **Client compatibility sweep** (WeeChat / HexChat / IRCCloud /
|
|
248
|
+
TheLounge / matrix-IRC bridge) remains pending.
|
|
249
|
+
- **Coverage hardening is partial.** `aws-adapter` and `aws-stack`
|
|
250
|
+
now clear the 90% gate, and `cf-adapter` / `cf-worker` run under
|
|
251
|
+
istanbul; the remaining packages (`cf-adapter`, `local-cli`,
|
|
252
|
+
`load-test`, `cf-tcp-container`, `tcp-ws-forwarder`,
|
|
253
|
+
`irc-test-support`) are **above the gate but below 100%** —
|
|
254
|
+
follow-ups drive each to 100%.
|
|
255
|
+
- The IRC services (NickServ / ChanServ / HostServ / OperServ /
|
|
256
|
+
MemoServ) Phase 13 work is pending; `draft/read-marker` and
|
|
257
|
+
`draft/pre-away` ship with in-memory reference stores, so marker /
|
|
258
|
+
away persistence does not survive an adapter restart until a
|
|
259
|
+
services backend lands.
|
|
260
|
+
- The web client Phase 14 work (vendor Kiwi IRC, serve SPA from the
|
|
261
|
+
Worker, WS Origin allowlist) is pending.
|
|
262
|
+
|
|
263
|
+
### Security
|
|
264
|
+
|
|
265
|
+
- None. No vulnerabilities have been reported or fixed in this
|
|
266
|
+
release. The new caps add surface area but ship no new auth path
|
|
267
|
+
(the SASL `PLAIN` / `EXTERNAL` paths and the oper gate are
|
|
268
|
+
unchanged); the required-`serverName` change rejects misconfigured
|
|
269
|
+
deploys at boot rather than advertising a placeholder identity.
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## [0.5.0] - 2026-08-02
|
|
274
|
+
|
|
275
|
+
The headline is **protocol completion**: the deferred IRC verbs land
|
|
276
|
+
(Phase 11), and the S2S / obsolete RFC 2812 verbs are **formally
|
|
277
|
+
dropped** rather than left "deferred". With this release every standard
|
|
278
|
+
IRC verb a modern client expects is implemented — the only remaining
|
|
279
|
+
`421 ERR_UNKNOWNCOMMAND` paths are the deliberately-unimplemented S2S
|
|
280
|
+
and obsolete verbs. The roadmap's 0.x protocol surface is complete;
|
|
281
|
+
what remains is the load/compat sweep (10k-connection load test +
|
|
282
|
+
client compatibility matrix) and the required-`serverName` config gate.
|
|
283
|
+
|
|
284
|
+
### Added — Deferred IRC verbs (`@serverless-ircd/irc-core`, `@serverless-ircd/irc-server`)
|
|
285
|
+
|
|
286
|
+
Six Phase 11 tickets light up the remaining command surface. Each ships
|
|
287
|
+
a pure reducer, an actor route case (no more `421`), new numerics in
|
|
288
|
+
`protocol/numerics.ts`, and unit + actor coverage. (The remaining two
|
|
289
|
+
Phase 11 tickets are drops — see below.)
|
|
290
|
+
|
|
291
|
+
- **`KILL`** (oper-gated force-disconnect): `KILL <nick>
|
|
292
|
+
<comment>` resolves the target via the nick registry + a live
|
|
293
|
+
connection fetch (mirroring WHOIS), checks the oper gate (`481
|
|
294
|
+
ERR_NOPRIVILEGES`), and emits a `Disconnect` effect carrying the
|
|
295
|
+
classic `Killed (<oper> (<comment>))` reason. Peer `QUIT` fanout in
|
|
296
|
+
the target's shared channels happens via the runtime's existing
|
|
297
|
+
`disconnect` path. Missing params → `461`; unknown nick → `401`; an
|
|
298
|
+
oper may `KILL` themselves (RFC-permitted).
|
|
299
|
+
**Platform asymmetry:** on Cloudflare the `disconnect` RPC closes the
|
|
300
|
+
target DO's socket immediately; on AWS a `$default` Lambda invocation
|
|
301
|
+
cannot close a *remote* APIGW WebSocket, so the target's
|
|
302
|
+
live socket only closes on its next `$disconnect` / sweeper cycle —
|
|
303
|
+
the QUIT fanout to peers still fires. The reducer is identical; the
|
|
304
|
+
difference is the bound runtime's `disconnect` semantics.
|
|
305
|
+
- **`REHASH`** (oper-gated config reload): emits `382
|
|
306
|
+
RPL_REHASHING :<source>` and re-fetches `ServerConfig` from the
|
|
307
|
+
adapter's bound source via a new `IrcRuntime.reloadConfig()` port
|
|
308
|
+
method. The refreshed value swaps into the actor's live config
|
|
309
|
+
reference so subsequent commands observe it (rotated oper passwords,
|
|
310
|
+
new MOTD source, etc.). On reload failure the previous config stays
|
|
311
|
+
in effect and a graceful error-suffixed `382` follows — the oper is
|
|
312
|
+
**not** disconnected (a bad store read must never sever a live link).
|
|
313
|
+
Already-open connections keep their negotiated caps and registration;
|
|
314
|
+
transport/TLS reload requires a redeploy.
|
|
315
|
+
- **`LUSERS` + `STATS`** (network statistics): backed by a
|
|
316
|
+
new async `ServerStats` port (`getStats(): Promise<ServerStatsSnapshot>`)
|
|
317
|
+
and an `InMemoryStats` reference impl. `LUSERS` emits the full
|
|
318
|
+
`251`–`255` sequence (only the non-zero counts, per RFC) plus the
|
|
319
|
+
optional `265` / `266` local/global counts. `STATS <query>` supports
|
|
320
|
+
the `u` (uptime, `242 RPL_STATSUPTIME`) and `l` (link info,
|
|
321
|
+
`211 RPL_STATSLINKINFO`) letters; unknown letters get the
|
|
322
|
+
charybdis-style empty body terminated by `219 RPL_ENDOFSTATS`. A
|
|
323
|
+
`<server>` argument that does not match the local server (case-
|
|
324
|
+
insensitive) yields `402 ERR_NOSUCHSERVER` (single-server network —
|
|
325
|
+
S2S aggregation is a PLAN non-goal). The `computeStatsSnapshot`
|
|
326
|
+
helper centralizes the oper/invisible/unknown classification so each
|
|
327
|
+
adapter's backend only has to gather raw counts.
|
|
328
|
+
- **`TRACE`** (routing diagnostics): in a single-server
|
|
329
|
+
serverless IRCd `TRACE` collapses to a local-server line + the
|
|
330
|
+
`262 RPL_ENDOFTRACE` terminator. Per-connection `204
|
|
331
|
+
RPL_TRACEOPERATOR` / `205 RPL_TRACEUSER` detail is **oper-gated** —
|
|
332
|
+
non-opers see only the server line + `262` (no enumeration of `+i`
|
|
333
|
+
users they don't share a channel with). `TRACE <server>` where
|
|
334
|
+
`<server>` is not the local server → `402`.
|
|
335
|
+
- **`WALLOPS`** (oper broadcast): `WALLOPS :<message>` is
|
|
336
|
+
oper-only to send (modern ircd convention — non-oper → `481`);
|
|
337
|
+
delivery fans out to every connection whose `+w` user mode is set via
|
|
338
|
+
a new `BroadcastWallops` effect interpreted by the runtime's
|
|
339
|
+
`broadcastWallops` method (global cross-connection fanout, not
|
|
340
|
+
channel-scoped). The originator is always excluded (skip-self,
|
|
341
|
+
matching NOTICE/PRIVMSG semantics). Empty message → `461`. The `+w`
|
|
342
|
+
user mode was already accepted by `MODE` and advertised in `004
|
|
343
|
+
RPL_MYINFO`; this lights up the consumer.
|
|
344
|
+
- **`SETNAME`** (realname change): `SETNAME :<realname>`
|
|
345
|
+
updates `state.realname` so a subsequent `WHOIS` reflects the new
|
|
346
|
+
value in `311 RPL_WHOISUSER`. No broadcast is emitted in v1 (there
|
|
347
|
+
is no standard IRCv3 cap for relaying a realname change — a
|
|
348
|
+
`draft/setname` relay is a documented follow-up). Empty/missing
|
|
349
|
+
realname → `461`; the registration-time realname length cap applies.
|
|
350
|
+
|
|
351
|
+
### Changed — S2S & obsolete verbs formally dropped (`@serverless-ircd/irc-core`)
|
|
352
|
+
|
|
353
|
+
The remaining two Phase 11 tickets convert the "deferred" framing into
|
|
354
|
+
an explicit **drop**. There is no behaviour change on the wire — the verbs
|
|
355
|
+
already returned `421 ERR_UNKNOWNCOMMAND` — but the framing, comments,
|
|
356
|
+
and reserved numerics are cleaned up so the codebase no longer carries
|
|
357
|
+
dead scaffolding.
|
|
358
|
+
|
|
359
|
+
- **S2S verbs** (`CONNECT`, `SQUIT`, `LINKS`): dropped as a PLAN
|
|
360
|
+
non-goal (single-server serverless IRCd; no mesh to connect, split,
|
|
361
|
+
or list). The now-unused numerics `RPL_LINKS (364)`,
|
|
362
|
+
`RPL_ENDOFLINKS (365)`, and `ERR_CANTKILLSERVER (483)` are removed
|
|
363
|
+
from `numerics.ts` and its auto-derived `numericToName` reverse map.
|
|
364
|
+
`ERR_NOSUCHSERVER (402)` is retained — `LUSERS` / `STATS` / `TRACE`
|
|
365
|
+
use it for remote-server gating.
|
|
366
|
+
- **Obsolete RFC 2812 verbs** (`SERVICE`, `SUMMON`, `USERS`): dropped
|
|
367
|
+
(never widely implemented; no modern client uses them). The now-unused
|
|
368
|
+
numerics `RPL_YOURESERVICE (383)`, `ERR_NOSUCHSERVICE (408)`,
|
|
369
|
+
`ERR_SUMMONDISABLED (445)`, and `ERR_USERSDISABLED (446)` are removed.
|
|
370
|
+
- The `actor.ts` default-branch triage comment was rewritten: the
|
|
371
|
+
six verbs are documented as **deliberately unimplemented** rather
|
|
372
|
+
than "deferred".
|
|
373
|
+
- Source-level regression guards
|
|
374
|
+
(`packages/irc-core/tests/dropped-s2s-and-obsolete-verbs.test.ts`)
|
|
375
|
+
and a behaviour guard in `actor.test.ts` (the verbs still emit
|
|
376
|
+
`421`) pin the drop so the numerics or the "deferred" framing cannot
|
|
377
|
+
creep back in.
|
|
378
|
+
|
|
379
|
+
### Added — Runtime ports for the new verbs
|
|
380
|
+
|
|
381
|
+
- **`ServerStats` port** (`packages/irc-core/src/ports.ts`): async
|
|
382
|
+
`getStats()` returning `ServerStatsSnapshot` (users / invisible /
|
|
383
|
+
opers / unknown / channels / servers / local+global conn counts /
|
|
384
|
+
uptime anchor). Asynchronous because the aggregation crosses every
|
|
385
|
+
connection and channel — it cannot be pre-loaded into a synchronous
|
|
386
|
+
view the way MOTD or a credential table can. Each adapter implements
|
|
387
|
+
it against its authoritative store; `InMemoryStats` is the reference
|
|
388
|
+
impl. The `computeStatsSnapshot` helper holds the shared
|
|
389
|
+
classification logic (oper / invisible / unknown).
|
|
390
|
+
- **`reloadConfig()` on `IrcRuntime`** (`packages/irc-server/src/runtime.ts`):
|
|
391
|
+
request/response port method the `REHASH` route calls to re-fetch
|
|
392
|
+
`ServerConfig` from the adapter's bound source (CF: KV/secret env;
|
|
393
|
+
AWS: Secrets Manager/SSM env; local-cli: the config file/options).
|
|
394
|
+
Modelled as a runtime method rather than a fire-and-forget effect
|
|
395
|
+
because the refreshed value must come back to the actor.
|
|
396
|
+
|
|
397
|
+
### ⚠️ Migration required
|
|
398
|
+
|
|
399
|
+
- **For adapter authors wiring the new ports.** `ServerStats` and
|
|
400
|
+
`reloadConfig` are optional at the type level (the actor falls back
|
|
401
|
+
to a zero-count snapshot when no `ServerStats` is bound, and
|
|
402
|
+
`REHASH` still emits `382` even if `reloadConfig` rejects — the
|
|
403
|
+
previous config is retained). To surface real counts and live
|
|
404
|
+
reloads, each adapter wires its own backend. No Durable-Object
|
|
405
|
+
persisted-state schema change (`PERSISTED_STATE_VERSION` stays `1`);
|
|
406
|
+
code rollback across this release is safe.
|
|
407
|
+
- No toolchain change. Node ≥ 24 / pnpm 11 (from v0.4.0) still apply.
|
|
408
|
+
|
|
409
|
+
### Known limitations
|
|
410
|
+
|
|
411
|
+
- Same as v0.4.0's transport limits: the **CF TCP path requires
|
|
412
|
+
Cloudflare Spectrum (Enterprise tier)** plus a stateful Container
|
|
413
|
+
origin; the **AWS TCP path** uses NLB + Lambda streaming and is
|
|
414
|
+
subject to Lambda idle-timeout / stream-duration limits. The
|
|
415
|
+
WebSocket path remains the zero-extra-deps default.
|
|
416
|
+
- **mTLS (for SASL `EXTERNAL`) requires a custom domain + uploaded
|
|
417
|
+
CA/trust-store** on both platforms and is not enabled by default.
|
|
418
|
+
- `serverName` still defaults to the `irc.example.com` placeholder when
|
|
419
|
+
an adapter config omits it (pending).
|
|
420
|
+
- `STATS` ships the `u` + `l` query letters; the full RFC matrix
|
|
421
|
+
(`k`, `K`, `q`, `g`, `x`, `z`, …) is intentionally out of scope for
|
|
422
|
+
v1 — unknown letters get the charybdis-style empty body + `219`.
|
|
423
|
+
- Load testing (10k concurrent connections) and the client
|
|
424
|
+
compatibility sweep (WeeChat / HexChat / IRCCloud / TheLounge)
|
|
425
|
+
remain pending.
|
|
426
|
+
- **Local coverage instrumentation on the Cloudflare-backed packages
|
|
427
|
+
(`@serverless-ircd/cf-adapter`, `@serverless-ircd/cf-worker`) is
|
|
428
|
+
incompatible with the current vitest toolchain.** `@vitest/coverage-v8`
|
|
429
|
+
v4.1.x imports `node:inspector/promises`, which the
|
|
430
|
+
`@cloudflare/vitest-pool-workers` (workerd) test pool cannot resolve.
|
|
431
|
+
The packages' test suites themselves pass (cf-adapter 185/185,
|
|
432
|
+
cf-worker 3/3); only `pnpm coverage` fails to load the coverage
|
|
433
|
+
module under the workerd pool. This is a documented [vitest-pool-workers
|
|
434
|
+
known issue](https://developers.cloudflare.com/workers/testing/vitest-integration/known-issues/#module-resolution)
|
|
435
|
+
and is expected to resolve with an upstream `@vitest/coverage-v8` or
|
|
436
|
+
pool-workers release. No production code is affected; CI behavior
|
|
437
|
+
depends on its installed versions.
|
|
438
|
+
|
|
439
|
+
### Security
|
|
440
|
+
|
|
441
|
+
- None. No vulnerabilities have been reported or fixed in this release.
|
|
442
|
+
The dropped S2S / obsolete verbs and their reserved numerics carried
|
|
443
|
+
no reachable code path; their removal reduces surface area but fixes
|
|
444
|
+
no defect.
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
13
448
|
## [0.4.0] - 2026-07-31
|
|
14
449
|
|
|
15
450
|
The headline is **dual transport**: both adapters now speak a real
|