serverless-ircd 0.1.0 → 0.2.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 +96 -2
- package/.github/workflows/deploy-aws.yml +129 -0
- package/.github/workflows/deploy-cf.yml +0 -2
- package/.gitmodules +3 -0
- package/AGENTS.md +5 -0
- package/CHANGELOG.md +352 -0
- package/MOTD.txt +3 -0
- package/PLAN-FIXES.md +358 -0
- package/PLAN.md +420 -0
- package/README.md +115 -81
- package/apps/aws-stack/README.md +73 -0
- package/apps/aws-stack/bin/aws.ts +49 -0
- package/apps/aws-stack/cdk.json +10 -0
- package/apps/aws-stack/package.json +41 -0
- package/apps/aws-stack/scripts/smoke-helpers.d.mts +22 -0
- package/apps/aws-stack/scripts/smoke-helpers.mjs +89 -0
- package/apps/aws-stack/scripts/smoke.mjs +142 -0
- package/apps/aws-stack/src/aws-stack.ts +263 -0
- package/apps/aws-stack/src/tables.ts +10 -0
- package/apps/aws-stack/tests/localstack.test.ts +46 -0
- package/apps/aws-stack/tests/smoke-helpers.test.ts +98 -0
- package/apps/aws-stack/tests/stack.test.ts +464 -0
- package/apps/aws-stack/tsconfig.build.json +11 -0
- package/apps/aws-stack/tsconfig.test.json +8 -0
- package/apps/aws-stack/vitest.config.ts +20 -0
- package/apps/cf-worker/package.json +1 -1
- package/apps/cf-worker/wrangler.toml +25 -0
- package/apps/local-cli/package.json +1 -1
- package/apps/local-cli/src/config-loader.ts +56 -0
- package/apps/local-cli/src/server.ts +241 -32
- package/apps/local-cli/tests/config-loader.test.ts +107 -0
- package/apps/local-cli/tests/e2e.test.ts +74 -0
- package/apps/local-cli/tests/security-e2e.test.ts +239 -0
- package/biome.json +3 -1
- package/dashboards/cloudwatch-irc.json +139 -0
- package/docs/AWS-Adapter-Architecture.md +494 -0
- package/docs/AWS-Deployment.md +1107 -0
- package/docs/Cloudflare-Deployment-Guide.md +660 -0
- package/docs/Home.md +1 -0
- package/docs/Observability.md +87 -0
- package/docs/PlanIRCv3Websocket.md +489 -0
- package/docs/PlanWebClient.md +451 -0
- package/docs/Release-Process.md +440 -0
- package/package.json +8 -2
- package/packages/aws-adapter/README.md +35 -0
- package/packages/aws-adapter/package.json +52 -0
- package/packages/aws-adapter/src/aws-runtime.ts +783 -0
- package/packages/aws-adapter/src/cdk-table-defs.ts +69 -0
- package/packages/aws-adapter/src/config-loader.ts +96 -0
- package/packages/aws-adapter/src/dynamo.ts +61 -0
- package/packages/aws-adapter/src/handlers/connect.ts +44 -0
- package/packages/aws-adapter/src/handlers/default.ts +322 -0
- package/packages/aws-adapter/src/handlers/disconnect.ts +29 -0
- package/packages/aws-adapter/src/handlers/index.ts +248 -0
- package/packages/aws-adapter/src/handlers/ping-checker.ts +217 -0
- package/packages/aws-adapter/src/handlers/state.ts +13 -0
- package/packages/aws-adapter/src/handlers/sweeper.ts +84 -0
- package/packages/aws-adapter/src/index.ts +67 -0
- package/packages/aws-adapter/src/message-store.ts +34 -0
- package/packages/aws-adapter/src/serialize.ts +283 -0
- package/packages/aws-adapter/src/tables.ts +53 -0
- package/packages/aws-adapter/tests/aws-harness.ts +408 -0
- package/packages/aws-adapter/tests/aws-integration.test.ts +17 -0
- package/packages/aws-adapter/tests/aws-runtime.test.ts +654 -0
- package/packages/aws-adapter/tests/config-loader.test.ts +158 -0
- package/packages/aws-adapter/tests/dynamo.test.ts +57 -0
- package/packages/aws-adapter/tests/global-setup.ts +301 -0
- package/packages/aws-adapter/tests/gone-exception.test.ts +271 -0
- package/packages/aws-adapter/tests/handlers.test.ts +427 -0
- package/packages/aws-adapter/tests/message-store.test.ts +55 -0
- package/packages/aws-adapter/tests/ping-checker.test.ts +571 -0
- package/packages/aws-adapter/tests/serialize.test.ts +249 -0
- package/packages/aws-adapter/tests/smoke.test.ts +48 -0
- package/packages/aws-adapter/tests/sweeper.test.ts +420 -0
- package/packages/aws-adapter/tests/tables.test.ts +74 -0
- package/packages/aws-adapter/tests/transactions.test.ts +446 -0
- package/packages/aws-adapter/tsconfig.build.json +16 -0
- package/packages/aws-adapter/tsconfig.test.json +14 -0
- package/packages/aws-adapter/vitest.config.ts +23 -0
- package/packages/cf-adapter/package.json +2 -1
- package/packages/cf-adapter/src/config-loader.ts +106 -0
- package/packages/cf-adapter/src/connection-do.ts +34 -0
- package/packages/cf-adapter/tests/cf-harness.ts +2 -2
- package/packages/cf-adapter/tests/cf-integration.test.ts +2 -2
- package/packages/cf-adapter/tests/config-loader.test.ts +149 -0
- package/packages/cf-adapter/tests/connection-do.test.ts +42 -0
- package/packages/in-memory-runtime/package.json +1 -1
- package/packages/in-memory-runtime/src/in-memory-runtime.ts +108 -3
- package/packages/in-memory-runtime/src/index.ts +1 -1
- package/packages/in-memory-runtime/tests/in-memory-runtime.test.ts +115 -0
- package/packages/irc-core/package.json +12 -2
- package/packages/irc-core/src/admission.ts +216 -0
- package/packages/irc-core/src/caps/capabilities.ts +1 -0
- package/packages/irc-core/src/cloak.ts +81 -0
- package/packages/irc-core/src/commands/cap.ts +1 -2
- package/packages/irc-core/src/commands/chathistory.ts +305 -0
- package/packages/irc-core/src/commands/index.ts +7 -0
- package/packages/irc-core/src/commands/join.ts +59 -7
- package/packages/irc-core/src/commands/privmsg.ts +24 -0
- package/packages/irc-core/src/commands/registration.ts +71 -14
- package/packages/irc-core/src/commands/sasl.ts +251 -0
- package/packages/irc-core/src/config.ts +247 -0
- package/packages/irc-core/src/flood-control.ts +175 -0
- package/packages/irc-core/src/index.ts +5 -0
- package/packages/irc-core/src/ports.ts +655 -0
- package/packages/irc-core/src/protocol/base64.ts +16 -0
- package/packages/irc-core/src/protocol/index.ts +2 -1
- package/packages/irc-core/src/protocol/numerics.ts +11 -0
- package/packages/irc-core/src/protocol/parser.ts +27 -2
- package/packages/irc-core/src/state/connection.ts +41 -0
- package/packages/irc-core/src/types.ts +66 -2
- package/packages/irc-core/stryker.commands.conf.json +41 -0
- package/packages/irc-core/stryker.protocol.conf.json +26 -0
- package/packages/irc-core/tests/admission.test.ts +229 -0
- package/packages/irc-core/tests/caps/capabilities.test.ts +22 -0
- package/packages/irc-core/tests/cloak.test.ts +78 -0
- package/packages/irc-core/tests/commands/chathistory.test.ts +996 -0
- package/packages/irc-core/tests/commands/join.test.ts +246 -2
- package/packages/irc-core/tests/commands/privmsg.test.ts +146 -2
- package/packages/irc-core/tests/commands/registration.test.ts +277 -9
- package/packages/irc-core/tests/commands/sasl.test.ts +536 -0
- package/packages/irc-core/tests/config.test.ts +646 -0
- package/packages/irc-core/tests/flood-control.test.ts +394 -0
- package/packages/irc-core/tests/message-store.test.ts +530 -0
- package/packages/irc-core/tests/parser.test.ts +44 -1
- package/packages/irc-core/tests/ports.test.ts +263 -0
- package/packages/irc-server/package.json +1 -1
- package/packages/irc-server/src/actor.ts +162 -44
- package/packages/irc-server/src/dispatch.ts +89 -5
- package/packages/irc-server/src/index.ts +2 -0
- package/packages/irc-server/src/routing.ts +151 -0
- package/packages/irc-server/tests/actor.test.ts +470 -14
- package/packages/irc-server/tests/dispatch.test.ts +84 -0
- package/packages/irc-server/tests/routing.test.ts +201 -0
- package/packages/irc-test-support/README.md +32 -0
- package/packages/irc-test-support/package.json +37 -0
- package/packages/{cf-adapter/tests/integration → irc-test-support/src}/in-memory-harness.ts +1 -1
- package/packages/irc-test-support/src/index.ts +24 -0
- package/packages/{cf-adapter/tests/integration/harness.test.ts → irc-test-support/tests/in-memory-harness.test.ts} +1 -1
- package/packages/{cf-adapter/tests/integration/scenarios.test.ts → irc-test-support/tests/in-memory-scenarios.test.ts} +1 -2
- package/packages/irc-test-support/tests/smoke.test.ts +11 -0
- package/packages/irc-test-support/tsconfig.build.json +16 -0
- package/packages/irc-test-support/tsconfig.test.json +14 -0
- package/packages/irc-test-support/vitest.config.ts +20 -0
- package/progress.md +107 -0
- package/tickets.md +2485 -0
- package/tools/ci-hardening/package.json +30 -0
- package/tools/ci-hardening/src/index.ts +6 -0
- package/tools/ci-hardening/src/validate.ts +103 -0
- package/tools/ci-hardening/tests/__no_thresholds__.txt +11 -0
- package/tools/ci-hardening/tests/__partial_thresholds__.txt +16 -0
- package/tools/ci-hardening/tests/__stryker_bad__.json +4 -0
- package/tools/ci-hardening/tests/validate.test.ts +177 -0
- package/tools/ci-hardening/tsconfig.build.json +12 -0
- package/tools/ci-hardening/tsconfig.test.json +10 -0
- package/tools/ci-hardening/vitest.config.ts +21 -0
- package/tools/tcp-ws-forwarder/package.json +1 -1
- package/tools/tcp-ws-forwarder/src/forwarder.ts +34 -23
- package/tools/tcp-ws-forwarder/src/logger.ts +155 -0
- package/tools/tcp-ws-forwarder/src/main.ts +33 -14
- package/tools/tcp-ws-forwarder/tests/forwarder.test.ts +86 -0
- package/tools/tcp-ws-forwarder/tests/logger.test.ts +136 -0
- package/webircgateway/LICENSE +201 -0
- package/webircgateway/Makefile +44 -0
- package/webircgateway/README.md +134 -0
- package/webircgateway/config.conf.example +135 -0
- package/webircgateway/go.mod +16 -0
- package/webircgateway/go.sum +89 -0
- package/webircgateway/main.go +118 -0
- package/webircgateway/pkg/dnsbl/dnsbl.go +121 -0
- package/webircgateway/pkg/identd/identd.go +86 -0
- package/webircgateway/pkg/identd/rpcclient.go +59 -0
- package/webircgateway/pkg/irc/isupport.go +56 -0
- package/webircgateway/pkg/irc/message.go +217 -0
- package/webircgateway/pkg/irc/state.go +79 -0
- package/webircgateway/pkg/proxy/proxy.go +129 -0
- package/webircgateway/pkg/proxy/server.go +237 -0
- package/webircgateway/pkg/recaptcha/recaptcha.go +59 -0
- package/webircgateway/pkg/webircgateway/client.go +741 -0
- package/webircgateway/pkg/webircgateway/client_command_handlers.go +495 -0
- package/webircgateway/pkg/webircgateway/config.go +385 -0
- package/webircgateway/pkg/webircgateway/gateway.go +278 -0
- package/webircgateway/pkg/webircgateway/gateway_utils.go +133 -0
- package/webircgateway/pkg/webircgateway/hooks.go +152 -0
- package/webircgateway/pkg/webircgateway/letsencrypt.go +41 -0
- package/webircgateway/pkg/webircgateway/messagetags.go +103 -0
- package/webircgateway/pkg/webircgateway/transport_kiwiirc.go +206 -0
- package/webircgateway/pkg/webircgateway/transport_sockjs.go +107 -0
- package/webircgateway/pkg/webircgateway/transport_tcp.go +113 -0
- package/webircgateway/pkg/webircgateway/transport_websocket.go +126 -0
- package/webircgateway/pkg/webircgateway/utils.go +147 -0
- package/webircgateway/plugins/example/plugin.go +11 -0
- package/webircgateway/plugins/stats/plugin.go +52 -0
- package/webircgateway/staticcheck.conf +1 -0
- package/webircgateway/webircgateway.svg +3 -0
- package/packages/cf-adapter/tests/integration/index.ts +0 -17
- /package/packages/{cf-adapter/tests/integration → irc-test-support/src}/harness.ts +0 -0
- /package/packages/{cf-adapter/tests/integration → irc-test-support/src}/scenarios.ts +0 -0
package/.github/workflows/ci.yml
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
name: CI
|
|
2
2
|
|
|
3
|
+
# Cross-cutting verification pipeline (coverage gate + contract suite
|
|
4
|
+
# on every PR + mutation-testing spot-check on irc-core).
|
|
5
|
+
#
|
|
6
|
+
# Failure modes (any of these blocks the merge):
|
|
7
|
+
# - biome lint
|
|
8
|
+
# - tsc strict typecheck across the workspace
|
|
9
|
+
# - any package unit/integration test
|
|
10
|
+
# - vitest per-package coverage threshold regression
|
|
11
|
+
# (100% on irc-core/irc-server/in-memory-runtime, >=90% elsewhere)
|
|
12
|
+
# - integration contract suite (packages/cf-adapter/tests/integration)
|
|
13
|
+
# - Stryker mutation score < 80% on irc-core/protocol or
|
|
14
|
+
# irc-core/commands
|
|
15
|
+
#
|
|
16
|
+
# The coverage gate is split into its own named step so the GitHub
|
|
17
|
+
# Actions UI surfaces "Coverage gate" as the failing step instead of
|
|
18
|
+
# the generic "Test with coverage" name. The mutation job runs in
|
|
19
|
+
# parallel because Stryker is the slowest single task in the pipeline
|
|
20
|
+
# and is independent of the typecheck/lint/coverage chain.
|
|
21
|
+
|
|
3
22
|
on:
|
|
4
23
|
push:
|
|
5
24
|
branches: [main]
|
|
@@ -16,8 +35,6 @@ jobs:
|
|
|
16
35
|
|
|
17
36
|
- name: Setup pnpm
|
|
18
37
|
uses: pnpm/action-setup@v4
|
|
19
|
-
with:
|
|
20
|
-
version: 9
|
|
21
38
|
|
|
22
39
|
- name: Setup Node
|
|
23
40
|
uses: actions/setup-node@v4
|
|
@@ -37,6 +54,40 @@ jobs:
|
|
|
37
54
|
- name: Test with coverage
|
|
38
55
|
run: pnpm coverage
|
|
39
56
|
|
|
57
|
+
- name: Coverage gate (coverage-thresholds enforced per package)
|
|
58
|
+
# Vitest enforces 100% line/function/branch/statement coverage
|
|
59
|
+
# on irc-core/irc-server/in-memory-runtime and >=90% on
|
|
60
|
+
# cf-adapter/local-cli/tcp-ws-forwarder via the `thresholds`
|
|
61
|
+
# block in each package's vitest.config.ts. The previous step
|
|
62
|
+
# exits non-zero on any regression; this named no-op marker
|
|
63
|
+
# makes the gate explicit in the Actions UI and reserves a
|
|
64
|
+
# place to plug in a future aggregate-coverage check.
|
|
65
|
+
if: success()
|
|
66
|
+
run: |
|
|
67
|
+
echo "coverage-thresholds: PASSED"
|
|
68
|
+
echo " irc-core: 100% (lines/functions/branches/statements)"
|
|
69
|
+
echo " irc-server: 100% (lines/functions/branches/statements)"
|
|
70
|
+
echo " in-memory-runtime: 100% (lines/functions/branches/statements)"
|
|
71
|
+
echo " cf-adapter: >=90% (lines/functions/branches/statements)"
|
|
72
|
+
echo " local-cli: >=90% (lines/functions/branches/statements)"
|
|
73
|
+
|
|
74
|
+
- name: Contract tests (parametrized integration suite)
|
|
75
|
+
# The parametrized integration contract suite
|
|
76
|
+
# (packages/cf-adapter/tests/integration) runs the same IRC
|
|
77
|
+
# scenarios against every runtime via a runtime factory, so
|
|
78
|
+
# any contract regression in irc-core surfaces here even when
|
|
79
|
+
# unit coverage is 100%. Invoked explicitly here so the step
|
|
80
|
+
# name shows up in the Actions UI; the underlying test files
|
|
81
|
+
# are also exercised by `pnpm coverage` above.
|
|
82
|
+
run: pnpm --filter @serverless-ircd/cf-adapter test
|
|
83
|
+
|
|
84
|
+
- name: CI hardening config self-check
|
|
85
|
+
# Validates that the coverage gate and mutation-testing
|
|
86
|
+
# configs exist and meet the documented thresholds. Catches
|
|
87
|
+
# drift (someone lowering a threshold or dropping a Stryker
|
|
88
|
+
# config) before it reaches main.
|
|
89
|
+
run: pnpm --filter @serverless-ircd/ci-hardening test
|
|
90
|
+
|
|
40
91
|
- name: Upload coverage
|
|
41
92
|
if: always()
|
|
42
93
|
uses: actions/upload-artifact@v4
|
|
@@ -45,3 +96,46 @@ jobs:
|
|
|
45
96
|
path: |
|
|
46
97
|
packages/*/coverage
|
|
47
98
|
apps/*/coverage
|
|
99
|
+
|
|
100
|
+
mutation:
|
|
101
|
+
name: mutation spot-check (irc-core)
|
|
102
|
+
runs-on: ubuntu-latest
|
|
103
|
+
# Stryker is the slowest single task; it is independent of the
|
|
104
|
+
# typecheck/lint/coverage chain and runs in parallel.
|
|
105
|
+
steps:
|
|
106
|
+
- name: Checkout
|
|
107
|
+
uses: actions/checkout@v4
|
|
108
|
+
|
|
109
|
+
- name: Setup pnpm
|
|
110
|
+
uses: pnpm/action-setup@v4
|
|
111
|
+
|
|
112
|
+
- name: Setup Node
|
|
113
|
+
uses: actions/setup-node@v4
|
|
114
|
+
with:
|
|
115
|
+
node-version: 20
|
|
116
|
+
cache: pnpm
|
|
117
|
+
|
|
118
|
+
- name: Install dependencies
|
|
119
|
+
run: pnpm install --frozen-lockfile
|
|
120
|
+
|
|
121
|
+
- name: Build workspace (irc-core mutation targets)
|
|
122
|
+
run: pnpm build
|
|
123
|
+
|
|
124
|
+
- name: Stryker spot-check on irc-core/protocol
|
|
125
|
+
# Mutation score threshold >=80% is enforced by the
|
|
126
|
+
# stryker.protocol.conf.json `thresholds.break` field. The
|
|
127
|
+
# job fails if the score drops below the gate.
|
|
128
|
+
run: pnpm mutation:protocol
|
|
129
|
+
|
|
130
|
+
- name: Stryker spot-check on irc-core/commands
|
|
131
|
+
# Mutation score threshold >=80% is enforced by the
|
|
132
|
+
# stryker.commands.conf.json `thresholds.break` field. The
|
|
133
|
+
# job fails if the score drops below the gate.
|
|
134
|
+
run: pnpm mutation:commands
|
|
135
|
+
|
|
136
|
+
- name: Upload mutation report
|
|
137
|
+
if: always()
|
|
138
|
+
uses: actions/upload-artifact@v4
|
|
139
|
+
with:
|
|
140
|
+
name: mutation-report
|
|
141
|
+
path: packages/irc-core/reports/mutation
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
name: deploy-aws
|
|
2
|
+
|
|
3
|
+
# AWS CDK deploy pipeline.
|
|
4
|
+
#
|
|
5
|
+
# On every push to `main`:
|
|
6
|
+
# 1. Install deps (frozen lockfile).
|
|
7
|
+
# 2. Build the aws-adapter + irc-core/irc-server so the CDK stack
|
|
8
|
+
# typechecks against real workspace packages.
|
|
9
|
+
# 3. `cdk deploy --all` the `apps/aws-stack` stack (API Gateway v2
|
|
10
|
+
# WebSocket API, Lambda, DynamoDB tables) to the staging AWS
|
|
11
|
+
# account/region.
|
|
12
|
+
# 4. Replay the smoke e2e (`scripts/smoke.mjs`) against the deployed
|
|
13
|
+
# WebSocket endpoint — CONNECT/REGISTER/JOIN/PRIVMSG/QUIT. Failure
|
|
14
|
+
# blocks the merge (the deploy job is required on `main`).
|
|
15
|
+
#
|
|
16
|
+
# Secrets / variables (configure under repo Settings → Secrets and
|
|
17
|
+
# variables → Actions):
|
|
18
|
+
# AWS_ACCESS_KEY_ID Static AWS access key with permission to deploy
|
|
19
|
+
# the stack (IAM, APIGW, Lambda, DynamoDB).
|
|
20
|
+
# Required unless OIDC is used (see below).
|
|
21
|
+
# AWS_SECRET_ACCESS_KEY Companion secret key. Required unless OIDC.
|
|
22
|
+
# AWS_DEPLOY_ROLE_ARN Optional. When set, the job assumes this role
|
|
23
|
+
# via OIDC web identity instead of using static
|
|
24
|
+
# access keys. Requires `permissions.id-token:
|
|
25
|
+
# write` (declared below) and an OIDC trust
|
|
26
|
+
# policy on the role granting
|
|
27
|
+
# `sts:AssumeRoleWithWebIdentity` to this repo's
|
|
28
|
+
# GitHub OIDC provider.
|
|
29
|
+
# AWS_REGION AWS region to deploy into (e.g. us-east-1).
|
|
30
|
+
#
|
|
31
|
+
# Repo variable (Settings → Secrets and variables → Variables):
|
|
32
|
+
# AWS_SMOKE_URL Optional. The wss:// URL of the deployed
|
|
33
|
+
# WebSocket stage. When unset the workflow
|
|
34
|
+
# falls back to reading the stack's `ConnectUrl`
|
|
35
|
+
# CloudFormation output via the AWS CLI; if that
|
|
36
|
+
# also fails the smoke step is skipped with a
|
|
37
|
+
# warning (mirrors the CF pipeline's skip
|
|
38
|
+
# behaviour).
|
|
39
|
+
|
|
40
|
+
on:
|
|
41
|
+
push:
|
|
42
|
+
branches: [main]
|
|
43
|
+
workflow_dispatch:
|
|
44
|
+
|
|
45
|
+
# OIDC web identity requires id-token write; contents:read for checkout.
|
|
46
|
+
permissions:
|
|
47
|
+
id-token: write
|
|
48
|
+
contents: read
|
|
49
|
+
|
|
50
|
+
# Prevent two deploys racing the same CloudFormation stack.
|
|
51
|
+
concurrency:
|
|
52
|
+
group: aws-staging
|
|
53
|
+
cancel-in-progress: false
|
|
54
|
+
|
|
55
|
+
jobs:
|
|
56
|
+
deploy-staging:
|
|
57
|
+
name: cdk deploy --all (staging)
|
|
58
|
+
runs-on: ubuntu-latest
|
|
59
|
+
timeout-minutes: 10
|
|
60
|
+
steps:
|
|
61
|
+
- name: Checkout
|
|
62
|
+
uses: actions/checkout@v4
|
|
63
|
+
|
|
64
|
+
- name: Setup pnpm
|
|
65
|
+
uses: pnpm/action-setup@v4
|
|
66
|
+
with:
|
|
67
|
+
version: 9
|
|
68
|
+
|
|
69
|
+
- name: Setup Node
|
|
70
|
+
uses: actions/setup-node@v4
|
|
71
|
+
with:
|
|
72
|
+
node-version: 20
|
|
73
|
+
cache: pnpm
|
|
74
|
+
|
|
75
|
+
- name: Install dependencies
|
|
76
|
+
run: pnpm install --frozen-lockfile
|
|
77
|
+
|
|
78
|
+
- name: Build workspace
|
|
79
|
+
run: pnpm build
|
|
80
|
+
|
|
81
|
+
- name: Typecheck
|
|
82
|
+
run: pnpm typecheck
|
|
83
|
+
|
|
84
|
+
- name: Test
|
|
85
|
+
run: pnpm test
|
|
86
|
+
|
|
87
|
+
# When AWS_DEPLOY_ROLE_ARN is set, assume it via OIDC web identity
|
|
88
|
+
# (ignores the static access keys). Otherwise fall back to the
|
|
89
|
+
# static access-key pair. Both shapes are handled by the action:
|
|
90
|
+
# an empty role-to-assume is treated as unset.
|
|
91
|
+
- name: Configure AWS credentials
|
|
92
|
+
uses: aws-actions/configure-aws-credentials@v4
|
|
93
|
+
with:
|
|
94
|
+
aws-region: ${{ secrets.AWS_REGION }}
|
|
95
|
+
role-to-assume: ${{ secrets.AWS_DEPLOY_ROLE_ARN }}
|
|
96
|
+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
97
|
+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
98
|
+
|
|
99
|
+
- name: Deploy to staging
|
|
100
|
+
run: pnpm deploy:aws:staging -- -c environmentName=staging
|
|
101
|
+
|
|
102
|
+
- name: Resolve smoke URL
|
|
103
|
+
id: smoke-url
|
|
104
|
+
env:
|
|
105
|
+
AWS_SMOKE_URL: ${{ vars.AWS_SMOKE_URL }}
|
|
106
|
+
run: |
|
|
107
|
+
if [ -n "$AWS_SMOKE_URL" ]; then
|
|
108
|
+
echo "url=$AWS_SMOKE_URL" >> "$GITHUB_OUTPUT"
|
|
109
|
+
else
|
|
110
|
+
# Fall back to the stack's ConnectUrl CloudFormation output.
|
|
111
|
+
# Stack name is `IrcAwsStack-<environmentName>`; staging →
|
|
112
|
+
# `IrcAwsStack-staging`.
|
|
113
|
+
URL=$(aws cloudformation describe-stacks \
|
|
114
|
+
--stack-name IrcAwsStack-staging \
|
|
115
|
+
--query 'Stacks[0].Outputs[?OutputKey==`ConnectUrl`].OutputValue' \
|
|
116
|
+
--output text 2>/dev/null || true)
|
|
117
|
+
if [ -n "$URL" ]; then
|
|
118
|
+
echo "url=$URL" >> "$GITHUB_OUTPUT"
|
|
119
|
+
else
|
|
120
|
+
echo "::warning::Unable to resolve the staging WebSocket URL (set the AWS_SMOKE_URL repo variable or check the stack ConnectUrl output); smoke step will be skipped."
|
|
121
|
+
echo "url=" >> "$GITHUB_OUTPUT"
|
|
122
|
+
fi
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
- name: Smoke e2e
|
|
126
|
+
if: steps.smoke-url.outputs.url != ''
|
|
127
|
+
env:
|
|
128
|
+
SMOKE_URL: ${{ steps.smoke-url.outputs.url }}
|
|
129
|
+
run: pnpm smoke:aws:staging -- --url "$SMOKE_URL"
|
package/.gitmodules
ADDED
package/AGENTS.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
## Code Style
|
|
4
|
+
|
|
5
|
+
- **Do not reference ticket IDs in source files.** Never put `TICKET-###` or similar ticket-tracker tokens in `.ts` or `.js` files (code or comments). Describe the intent or cross-reference by feature/command name instead. Ticket tracking lives in `progress.md` / `tickets.md`, not in source.
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to ServerlessIRCd are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/) with
|
|
7
|
+
the 0.x convention (any release may change anything).
|
|
8
|
+
|
|
9
|
+
For the release process itself — versioning policy, pre-release checklist,
|
|
10
|
+
cutting a tag, rolling back — see [`docs/release.md`](docs/release.md).
|
|
11
|
+
Cross-reference `progress.md` / `tickets.md` for per-ticket detail.
|
|
12
|
+
|
|
13
|
+
## [0.2.0] - 2026-07-23
|
|
14
|
+
|
|
15
|
+
### Added — Authentication & flood control (`@serverless-ircd/irc-core`)
|
|
16
|
+
|
|
17
|
+
- **SASL `AUTHENTICATE`**: pure reducer for the IRCv3 SASL exchange.
|
|
18
|
+
`PLAIN` is fully implemented (decodes the payload, validates against
|
|
19
|
+
the injected synchronous `AccountStore` port, emits `900 RPL_LOGGEDIN`
|
|
20
|
+
+ `903 RPL_SASLSUCCESS` on success, `904 ERR_SASLFAIL` on failure).
|
|
21
|
+
`EXTERNAL` is recognized but stubbed to `904` until mTLS lands; any
|
|
22
|
+
other mechanism gets `908 ERR_SASLMECHS`. Multi-frame `<=400`-byte
|
|
23
|
+
chunked payloads and `AUTHENTICATE *` abort (`906 ERR_SASLABORT`) are
|
|
24
|
+
handled. `CAP sasl` is now negotiated end-to-end (no longer
|
|
25
|
+
advertised-only).
|
|
26
|
+
- **Token-bucket flood control**: `wrapFloodControl` is a pure
|
|
27
|
+
higher-order reducer wrapper enforcing a per-connection token bucket.
|
|
28
|
+
The bucket is refilled from the injected `Clock` (deterministic —
|
|
29
|
+
never `Date.now()`) and, once it crosses the configured negative
|
|
30
|
+
threshold, short-circuits with `Disconnect("Excess Flood")` without
|
|
31
|
+
invoking the inner reducer — matching hybrid/charybdis/Unreal.
|
|
32
|
+
- **Per-command flood cost**: each command carries an integer cost;
|
|
33
|
+
control-plane commands (`PING`/`PONG`/`QUIT`/`CAP`/`AUTHENTICATE`)
|
|
34
|
+
are exempt so registration and keepalive can never be starved.
|
|
35
|
+
|
|
36
|
+
### Added — IRCv3 chat history (`@serverless-ircd/irc-core`)
|
|
37
|
+
|
|
38
|
+
- **`draft/chathistory`**: pure reducer for `CHATHISTORY <sub> <target>
|
|
39
|
+
[<args>...]`. Reads backlog from the injected `MessageStore` port and
|
|
40
|
+
replays matching `PRIVMSG`/`NOTICE`/`TAGMSG` lines wrapped in a single
|
|
41
|
+
`BATCH chathistory <target>` frame, each carrying its original
|
|
42
|
+
`@time=…` (server-time) and `msgid=…` tags. The cap must be
|
|
43
|
+
negotiated before queries are accepted. Backed by a flood-wrapped
|
|
44
|
+
routed-reducer path so chat-history reads cannot bypass the bucket.
|
|
45
|
+
|
|
46
|
+
### Added — Observability & configuration (`@serverless-ircd/irc-core`)
|
|
47
|
+
|
|
48
|
+
- **Structured logger port**: a `Logger` port with `traceId` /
|
|
49
|
+
`connectionId` propagation, injected through `ctx` so reducers and
|
|
50
|
+
the actor layer emit structured JSON logs without ambient state.
|
|
51
|
+
- **Shared `ServerConfigSchema`**: a single Zod-style schema validating
|
|
52
|
+
`serverName`, `networkName`, `motdLines`, `serverPassword`,
|
|
53
|
+
`cloaking`, `maxConnectionsPerIp`, `maxConnectionsPerUser`, and
|
|
54
|
+
`perIpConnectionRate` with the same defaults across every adapter.
|
|
55
|
+
Each adapter ships a thin loader (`loadServerConfigFromLambdaEnv`,
|
|
56
|
+
CF `vars`, local CLI flags) that reduces to the shared schema.
|
|
57
|
+
|
|
58
|
+
### Added — Security hardening (`@serverless-ircd/irc-core`, `@serverless-ircd/in-memory-runtime`, `@serverless-ircd/local-cli`)
|
|
59
|
+
|
|
60
|
+
- **Server password enforcement**: when `serverPassword` is set in
|
|
61
|
+
`ServerConfig`, connections must supply it via `PASS <password>`
|
|
62
|
+
(or authenticate via SASL PLAIN) before registration completes;
|
|
63
|
+
otherwise the server replies `464 ERR_PASSWDMISMATCH` and closes
|
|
64
|
+
the link.
|
|
65
|
+
- **Hostmask cloaking**: `cloakHost(realHost, config, suffix)` replaces
|
|
66
|
+
the client's visible IP with a deterministic 64-bit FNV-1a hash
|
|
67
|
+
encoded as lowercase base32, using a deployment-wide secret. Enabled
|
|
68
|
+
via `cloaking: { enabled, secret, cloakedSuffix }` in `ServerConfig`.
|
|
69
|
+
- **Connection admission gate**: `AdmissionStats` + `decideAdmission`
|
|
70
|
+
enforce three independent limits at connection-accept time, each with
|
|
71
|
+
a distinct rejection reason:
|
|
72
|
+
- Per-IP simultaneous-connection cap (`maxConnectionsPerIp`, default 10).
|
|
73
|
+
- Per-user simultaneous-connection cap (`maxConnectionsPerUser`,
|
|
74
|
+
default 5; falls back to source IP when no SASL identity is present).
|
|
75
|
+
- Per-IP connection-rate limit (sliding window
|
|
76
|
+
`perIpConnectionRate`, default 5 per 60 s).
|
|
77
|
+
- **512-byte input cap**: the IRC line parser rejects any line whose
|
|
78
|
+
post-CRLF-strip length exceeds `MAX_INPUT_BYTES` (512), matching
|
|
79
|
+
RFC 2812 §2.3 and the existing output-side `enforceLineLimit`.
|
|
80
|
+
|
|
81
|
+
### Added — AWS adapter (`@serverless-ircd/aws-adapter`, `@serverless-ircd/aws-stack`)
|
|
82
|
+
|
|
83
|
+
The second serverless substrate lands, mirroring the Cloudflare adapter
|
|
84
|
+
on the same `irc-core` reducers and `IrcRuntime` port. Cloudflare and
|
|
85
|
+
AWS are now both deployable.
|
|
86
|
+
|
|
87
|
+
- **`AwsRuntime`**: `IrcRuntime` implementation backed by DynamoDB +
|
|
88
|
+
`ApiGatewayManagementApi`. Marshal/unmarshal helpers map irc-core
|
|
89
|
+
state shapes to/from DynamoDB rows.
|
|
90
|
+
- **Lambda handlers**: `$connect` / `$disconnect` / `$default` entry
|
|
91
|
+
point dispatched on `event.requestContext.routeKey`, wired through
|
|
92
|
+
`ConnectionActor` + `dispatch` against `AwsRuntime`.
|
|
93
|
+
- **Gone-connection sweeper** (`sweeperHandler`): scheduled Lambda that
|
|
94
|
+
reaps connections whose WebSocket link is dead, using atomic DynamoDB
|
|
95
|
+
membership transactions so roster/part fanout stays consistent.
|
|
96
|
+
- **Idle / PING checker** (`pingCheckerHandler`): scheduled Lambda that
|
|
97
|
+
drives the PING / no-PONG disconnect sweep, the AWS analogue of the
|
|
98
|
+
Cloudflare DO `alarm()`.
|
|
99
|
+
- **CDK v2 stack** (`apps/aws-stack`): API Gateway v2 WebSocket API +
|
|
100
|
+
auto-deploying `prod` stage, one Node 20 `NodejsFunction` for the
|
|
101
|
+
runtime, one for the sweeper, and one for the PING checker, five
|
|
102
|
+
DynamoDB tables (`Connections`, `ChannelMeta`, `ChannelMembers`,
|
|
103
|
+
`Nicks`, `Accounts`), and least-privilege IAM (per-table data-plane
|
|
104
|
+
grants + `execute-api:ManageConnections` scoped to the stage).
|
|
105
|
+
- **Per-environment isolation**: `environmentName` prop isolates
|
|
106
|
+
stacks (`IrcAwsStack-<env>`); configurable server identity
|
|
107
|
+
(name / network / MOTD).
|
|
108
|
+
- **AWS deploy workflow** (`.github/workflows/deploy-aws.yml`):
|
|
109
|
+
serialized `cdk deploy --all` to staging on every push to `main`,
|
|
110
|
+
followed by the smoke e2e (`scripts/smoke.mjs`) against the deployed
|
|
111
|
+
`ConnectUrl`. Supports static keys or OIDC web-identity role
|
|
112
|
+
assumption.
|
|
113
|
+
|
|
114
|
+
### Added — Shared test harness (`@serverless-ircd/irc-test-support`)
|
|
115
|
+
|
|
116
|
+
- New workspace package owning the parametrized IRC scenario suite
|
|
117
|
+
(`runIrcScenarios`, 31 Phase 2 scenarios) and the
|
|
118
|
+
`IrcHarnessFactory` / `IrcHarness` / `ClientHarness` seam each
|
|
119
|
+
adapter implements. Ships the reference `inMemoryHarnessFactory`.
|
|
120
|
+
cf-adapter and aws-adapter integration tests both consume it, so the
|
|
121
|
+
same flows run against in-memory, Cloudflare, and AWS runtimes.
|
|
122
|
+
|
|
123
|
+
### Added — CI / build
|
|
124
|
+
|
|
125
|
+
- **Coverage gate**: vitest per-package `thresholds` now enforce 100%
|
|
126
|
+
line/function/branch/statement on `irc-core` / `irc-server` /
|
|
127
|
+
`in-memory-runtime` and ≥90% on every other package. The gate is a
|
|
128
|
+
dedicated named CI step; a regression blocks the merge.
|
|
129
|
+
- **Mutation testing**: Stryker spot-checks on `irc-core/protocol` and
|
|
130
|
+
`irc-core/commands` (≥80% mutation score gate), running as a parallel
|
|
131
|
+
CI job. Repo-level `pnpm mutation` / `mutation:protocol` /
|
|
132
|
+
`mutation:commands` scripts drive it locally.
|
|
133
|
+
- **`@serverless-ircd/ci-hardening`** tool: validates the coverage-gate
|
|
134
|
+
and mutation-testing configs exist and meet the documented
|
|
135
|
+
thresholds, catching drift (a lowered threshold or dropped Stryker
|
|
136
|
+
config) before it reaches `main`.
|
|
137
|
+
- **CF observability**: Worker `observability.invocation_logs` enabled
|
|
138
|
+
for runtime visibility in the Cloudflare dashboard.
|
|
139
|
+
- **tcp-ws-forwarder logging**: structured logger with configurable
|
|
140
|
+
log levels.
|
|
141
|
+
|
|
142
|
+
### Changed
|
|
143
|
+
|
|
144
|
+
- `CAP LS` now advertises `draft/chathistory`; `sasl` is negotiated
|
|
145
|
+
end-to-end rather than advertised-only.
|
|
146
|
+
- The local CLI now binds a **second RFC-style TCP listener** by default
|
|
147
|
+
(`--tcp-port`, default `<port> + 1`) alongside the WebSocket listener,
|
|
148
|
+
so stock IRC clients can dial in directly without the forwarder.
|
|
149
|
+
Pass `--no-tcp` for WebSocket-only. `--motd-file` loads the MOTD from
|
|
150
|
+
disk.
|
|
151
|
+
|
|
152
|
+
### Known limitations
|
|
153
|
+
|
|
154
|
+
- **No config loader for oper credentials / max clients.** Server name,
|
|
155
|
+
network, MOTD, cloaking secret, and admission limits are configurable,
|
|
156
|
+
but oper credentials and dynamic max-client limits remain hardcoded
|
|
157
|
+
defaults.
|
|
158
|
+
- **No TLS / raw TCP transport in production.** The local CLI exposes a
|
|
159
|
+
TCP listener for development; deployed stacks (CF + AWS) are
|
|
160
|
+
WebSocket text frames only. `irc+tls` is 0.x work.
|
|
161
|
+
- **SASL `EXTERNAL` is reserved.** It is recognized but returns `904`
|
|
162
|
+
until mTLS lands.
|
|
163
|
+
- **`chathistory` storage is adapter-supplied.** The `MessageStore` port
|
|
164
|
+
is implemented per adapter; clients that query backlog against a
|
|
165
|
+
runtime with no store configured will see an empty result.
|
|
166
|
+
|
|
167
|
+
## [0.1.0] - 2026-07-21
|
|
168
|
+
|
|
169
|
+
First tagged release. Establishes the pure-reducer protocol core, the
|
|
170
|
+
runtime port + reference implementation, a runnable local CLI server,
|
|
171
|
+
and a working Cloudflare Workers adapter deployed to staging.
|
|
172
|
+
|
|
173
|
+
This is a **preview release**. The AWS adapter, SASL authentication,
|
|
174
|
+
flood control, server-password enforcement, and a CI coverage gate
|
|
175
|
+
are not yet implemented — see **Known limitations** below. The
|
|
176
|
+
Cloudflare staging deployment is functional; production deploys are
|
|
177
|
+
manual per `docs/release.md` §8.3.
|
|
178
|
+
|
|
179
|
+
### Added — Protocol core (`@serverless-ircd/irc-core`)
|
|
180
|
+
|
|
181
|
+
- Pure reducer architecture: every command handler is
|
|
182
|
+
`(state, msg, ctx) => { state, effects }`. Side effects are values
|
|
183
|
+
(`Effect[]`), interpreted by a separate `dispatch` step.
|
|
184
|
+
- Discriminated `Effect` taxonomy (`Send`, `Broadcast`, `Disconnect`,
|
|
185
|
+
`ReserveNick`, `ChangeNick`, `ReleaseNick`, `ApplyChannelDelta`,
|
|
186
|
+
`Lookup`, …) covering every side effect referenced in PLAN §2.1.
|
|
187
|
+
- Determinism ports `Clock` and `IdFactory` injected into `ctx` so
|
|
188
|
+
reducers never touch real timers or randomness.
|
|
189
|
+
- RFC 1459 / 2812 command set: registration (`NICK` / `USER` / `PASS`),
|
|
190
|
+
`PING` / `PONG`, `QUIT`, `JOIN`, `PART`, `PRIVMSG`, `NOTICE`,
|
|
191
|
+
`TOPIC`, `NAMES`, `MOTD`, `MODE` (channel + user), `KICK`, `INVITE`,
|
|
192
|
+
`WHO`, `WHOIS`, `LIST`.
|
|
193
|
+
- Channel modes: `o v b i k l t n m s p`. User modes: `i`, `o` (local
|
|
194
|
+
only), `w`, `s`.
|
|
195
|
+
- Welcome numeric sequence `001`–`005` with `isupport` (`005`)
|
|
196
|
+
generator emitting `NETWORK=`, `CHANLIMIT=`, `CASEMAPPING=`,
|
|
197
|
+
`SAFELIST`, and the negotiated IRCv3 caps.
|
|
198
|
+
- IRCv3 `CAP` negotiation: full `LS` / `REQ` / `ACK` / `NAK` / `END` /
|
|
199
|
+
`LIST` / `NEW` / `DEL` lifecycle.
|
|
200
|
+
- IRCv3 extensions: `message-tags`, `server-time`, `echo-message`,
|
|
201
|
+
`multi-prefix`, `extended-join`, `chghost`, `away-notify`,
|
|
202
|
+
`invite-notify`, `batch`, and the `safelist` capability +
|
|
203
|
+
`SAFELIST` isupport token.
|
|
204
|
+
|
|
205
|
+
### Added — Orchestration (`@serverless-ircd/irc-server`)
|
|
206
|
+
|
|
207
|
+
- The `IrcRuntime` port: side-effect interface (transport + state IO)
|
|
208
|
+
that every adapter implements.
|
|
209
|
+
- `dispatch(effects, runtime)` interpreter that walks an `Effect[]`
|
|
210
|
+
against a bound runtime, with ordering and dedup verified.
|
|
211
|
+
- `ConnectionActor`: bytes → framed messages → reducer → dispatch.
|
|
212
|
+
Drives the full registration handshake, PING/PONG cadence, and
|
|
213
|
+
command dispatch.
|
|
214
|
+
|
|
215
|
+
### Added — In-memory runtime (`@serverless-ircd/in-memory-runtime`)
|
|
216
|
+
|
|
217
|
+
- Single-process reference implementation of `IrcRuntime` backed by
|
|
218
|
+
in-memory Maps. Used by integration tests and the local CLI server.
|
|
219
|
+
|
|
220
|
+
### Added — Local CLI server (`@serverless-ircd/local-cli`)
|
|
221
|
+
|
|
222
|
+
- Runnable WebSocket IRC server on `ws://127.0.0.1:6667/` (default),
|
|
223
|
+
built on the in-memory runtime. Speaks WebSocket text frames, one
|
|
224
|
+
IRC message per frame. `SIGINT` / `SIGTERM` perform graceful
|
|
225
|
+
shutdown. Manual-test harness and e2e fixture target.
|
|
226
|
+
- CLI flags: `--port`, `--host`, `-h/--help`.
|
|
227
|
+
|
|
228
|
+
### Added — Cloudflare adapter (`@serverless-ircd/cf-adapter`)
|
|
229
|
+
|
|
230
|
+
- `ConnectionDO`: hibernatable WebSocket handler (one DO per
|
|
231
|
+
connection). Owns `ConnectionState`, drives `ConnectionActor`,
|
|
232
|
+
persists state across hibernation, drives the PING / no-PONG
|
|
233
|
+
disconnect sweep via `alarm()`.
|
|
234
|
+
- `RegistryDO`: sharded nick-uniqueness authority. Shard assignment is
|
|
235
|
+
`fnv1a32(lowercased(nick)) mod N`, default fleet size 32. DO
|
|
236
|
+
single-threadedness makes the uniqueness invariant structural.
|
|
237
|
+
- `ChannelDO`: per-lowercased-channel-name DO holding roster, modes,
|
|
238
|
+
topic, and fanout via `ConnectionDO` stubs.
|
|
239
|
+
- `CfRuntime`: implements the `IrcRuntime` port against the three DO
|
|
240
|
+
classes.
|
|
241
|
+
|
|
242
|
+
### Added — Cloudflare Worker (`@serverless-ircd/cf-worker`)
|
|
243
|
+
|
|
244
|
+
- Worker edge entry point: WebSocket upgrade → allocates
|
|
245
|
+
`connectionId = crypto.randomUUID()` → routes to `ConnectionDO`.
|
|
246
|
+
Non-upgrade requests get a human-readable 200 health string.
|
|
247
|
+
- `wrangler.toml` with default (production) + `[env.staging]`
|
|
248
|
+
environments, DO bindings, `[[migrations]]` block.
|
|
249
|
+
- `scripts/smoke.mjs`: replay CONNECT → NICK/USER → JOIN → PRIVMSG →
|
|
250
|
+
QUIT and assert the server emits `001`, `376`, `353`, `366`, then
|
|
251
|
+
closes. Run by CI against staging, runnable locally against
|
|
252
|
+
`wrangler dev`.
|
|
253
|
+
|
|
254
|
+
### Added — TCP ↔ WebSocket forwarder (`@serverless-ircd/tcp-ws-forwarder`)
|
|
255
|
+
|
|
256
|
+
- Local bridge so stock TCP IRC clients (WeeChat, HexChat, irssi) can
|
|
257
|
+
reach the WebSocket-only server. Listens on a TCP port, opens one
|
|
258
|
+
WebSocket per connection, reassembles the TCP byte stream into one
|
|
259
|
+
message per WS frame outbound, normalizes inbound frames back to
|
|
260
|
+
canonical CRLF. Transport-agnostic — ships no
|
|
261
|
+
`@serverless-ircd/*` dependency.
|
|
262
|
+
|
|
263
|
+
### Added — CI / build
|
|
264
|
+
|
|
265
|
+
- GitHub Actions CI (`.github/workflows/ci.yml`): lint, typecheck,
|
|
266
|
+
test with coverage on every push / pull request to `main`.
|
|
267
|
+
- GitHub Actions CF deploy (`.github/workflows/deploy-cf.yml`):
|
|
268
|
+
serialized staging deploy on every push to `main`, followed by the
|
|
269
|
+
smoke e2e against the deployed URL. Failure blocks the merge.
|
|
270
|
+
- Toolchain: pnpm 9 workspaces, turbo, TypeScript (strict +
|
|
271
|
+
`exactOptionalPropertyTypes`), vitest + `@vitest/coverage-v8`,
|
|
272
|
+
fast-check, Biome.
|
|
273
|
+
|
|
274
|
+
### Added — Documentation
|
|
275
|
+
|
|
276
|
+
- `README.md` — architecture, repository layout, toolchain, local
|
|
277
|
+
server + forwarder usage, testing strategy, roadmap, protocol scope.
|
|
278
|
+
- `docs/architecture-aws.md` — AWS adapter design notes (adapter
|
|
279
|
+
itself lands in a later release).
|
|
280
|
+
- `docs/deployment-cf.md` — end-to-end Cloudflare deployment guide
|
|
281
|
+
(prerequisites, account setup, local dev, staging + production
|
|
282
|
+
deploys, config reference, sharding, cost, CI/CD, troubleshooting).
|
|
283
|
+
- `docs/release.md` — this release process runbook.
|
|
284
|
+
|
|
285
|
+
### Changed
|
|
286
|
+
|
|
287
|
+
- None (this is the first tagged release).
|
|
288
|
+
|
|
289
|
+
### ⚠️ Migration required
|
|
290
|
+
|
|
291
|
+
- None. No prior releases to migrate from. The DO `[[migrations]]`
|
|
292
|
+
block in `wrangler.toml` is `tag = "v1"` and will provision cleanly
|
|
293
|
+
on a fresh account.
|
|
294
|
+
|
|
295
|
+
### Known limitations
|
|
296
|
+
|
|
297
|
+
- **No AWS adapter.** Tickets TICKET-039 through TICKET-044 (CDK
|
|
298
|
+
stack, APIGW WebSocket handlers, DynamoDB transactions, EventBridge
|
|
299
|
+
timers, deploy pipeline, deployment doc) are pending. Cloudflare is
|
|
300
|
+
the only deployable platform in 0.1.0.
|
|
301
|
+
- **No SASL.** `CAP sasl` is advertised in the capability list but
|
|
302
|
+
`AUTHENTICATE` is not wired into the dispatcher. Plain-text password
|
|
303
|
+
authentication via `PASS` is also not enforced (TICKET-046).
|
|
304
|
+
- **No flood control.** A token-bucket wrapper (TICKET-028) is
|
|
305
|
+
pending. Misbehaving clients can send unbounded commands.
|
|
306
|
+
- **No server-password enforcement, rate limits, cloaking, or oper
|
|
307
|
+
credentials** (TICKET-046).
|
|
308
|
+
- **No config loader.** Server name, network name, MOTD, channel
|
|
309
|
+
prefixes, max clients, oper creds are hardcoded defaults
|
|
310
|
+
(TICKET-047). The `MOTD.txt` file at the repo root is informational
|
|
311
|
+
only; the live MOTD is compiled into the Worker from
|
|
312
|
+
`[vars].MOTD_LINES`.
|
|
313
|
+
- **No CI coverage gate.** Coverage is computed and uploaded as an
|
|
314
|
+
artifact, but no threshold is enforced (TICKET-048). Inspect
|
|
315
|
+
`packages/*/coverage/` before deploying.
|
|
316
|
+
- **No TLS / raw TCP transport.** v1 is WebSocket text frames only.
|
|
317
|
+
TLS-hardened and `irc+tls` transports are 0.x work (TICKET-052
|
|
318
|
+
through TICKET-058). Stock TCP IRC clients reach the server through
|
|
319
|
+
the local `tcp-ws-forwarder` bridge.
|
|
320
|
+
- **No `chathistory` playback.** TICKET-063 is pending; clients that
|
|
321
|
+
request backlog on JOIN will see an empty batch or no response.
|
|
322
|
+
|
|
323
|
+
### Security
|
|
324
|
+
|
|
325
|
+
- None. No vulnerabilities have been reported or fixed in this
|
|
326
|
+
release. Report security issues per the contributing guide.
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
<!-- Release template — copy for the next release, fill in, move above this line.
|
|
331
|
+
|
|
332
|
+
## [Unreleased]
|
|
333
|
+
|
|
334
|
+
### Added
|
|
335
|
+
-
|
|
336
|
+
|
|
337
|
+
### Changed
|
|
338
|
+
-
|
|
339
|
+
|
|
340
|
+
### ⚠️ Migration required
|
|
341
|
+
-
|
|
342
|
+
|
|
343
|
+
### Fixed
|
|
344
|
+
-
|
|
345
|
+
|
|
346
|
+
### Known limitations
|
|
347
|
+
-
|
|
348
|
+
|
|
349
|
+
### Security
|
|
350
|
+
-
|
|
351
|
+
|
|
352
|
+
-->
|
package/MOTD.txt
ADDED