serverless-ircd 0.9.0 → 0.11.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.
Files changed (254) hide show
  1. package/.github/workflows/ci.yml +28 -0
  2. package/.github/workflows/deploy-aws.yml +156 -32
  3. package/.github/workflows/deploy-cf-tcp.yml +35 -9
  4. package/.github/workflows/deploy-cf.yml +40 -14
  5. package/CHANGELOG.md +594 -0
  6. package/README.md +286 -60
  7. package/apps/aws-stack/README.md +3 -5
  8. package/apps/aws-stack/bin/aws.ts +118 -9
  9. package/apps/aws-stack/cdk.json +0 -3
  10. package/apps/aws-stack/package.json +3 -4
  11. package/apps/aws-stack/src/aws-stack.ts +398 -67
  12. package/apps/aws-stack/src/static-site.ts +323 -0
  13. package/apps/aws-stack/tests/smoke-helpers.test.ts +1 -1
  14. package/apps/aws-stack/tests/stack.test.ts +714 -105
  15. package/apps/aws-stack/tests/static-site.test.ts +491 -0
  16. package/apps/aws-stack/tests/synth-no-bundle.test.ts +0 -1
  17. package/apps/cf-tcp-container/Dockerfile +37 -5
  18. package/apps/cf-tcp-container/package.json +7 -3
  19. package/apps/cf-tcp-container/src/config-loader.ts +113 -2
  20. package/apps/cf-tcp-container/src/container-server.ts +267 -87
  21. package/apps/cf-tcp-container/src/main.ts +22 -7
  22. package/apps/cf-tcp-container/src/proxy-protocol.ts +112 -0
  23. package/apps/cf-tcp-container/terraform/spectrum.tf +40 -11
  24. package/apps/cf-tcp-container/tests/config-loader.test.ts +170 -0
  25. package/apps/cf-tcp-container/tests/container-server-tls.test.ts +382 -0
  26. package/apps/cf-tcp-container/tests/container-server.test.ts +358 -31
  27. package/apps/cf-tcp-container/tests/dockerfile.test.ts +110 -0
  28. package/apps/cf-tcp-container/tests/proxy-protocol.test.ts +187 -0
  29. package/apps/cf-tcp-container/tests/spectrum-terraform.test.ts +135 -0
  30. package/apps/cf-tcp-container/tests/tls-e2e.test.ts +5 -1
  31. package/apps/cf-tcp-container/wrangler.toml +18 -14
  32. package/apps/cf-worker/package.json +3 -4
  33. package/apps/cf-worker/src/worker.ts +77 -5
  34. package/apps/cf-worker/tests/raw-modules.d.ts +11 -0
  35. package/apps/cf-worker/tests/smoke.test.ts +4 -0
  36. package/apps/cf-worker/tests/wrangler-config.test.ts +47 -0
  37. package/apps/cf-worker/tests/ws-admission.test.ts +112 -0
  38. package/apps/cf-worker/tests/ws-rate-limit.test.ts +133 -0
  39. package/apps/cf-worker/wrangler.test.toml +15 -1
  40. package/apps/cf-worker/wrangler.toml +95 -77
  41. package/apps/local-cli/package.json +1 -1
  42. package/apps/local-cli/src/config-loader.ts +14 -2
  43. package/apps/local-cli/src/line-scanner.ts +26 -0
  44. package/apps/local-cli/src/server.ts +44 -19
  45. package/apps/local-cli/tests/line-scanner.test.ts +64 -0
  46. package/apps/local-cli/tests/tcp.test.ts +29 -0
  47. package/apps/web/landing/favicon.ico +0 -0
  48. package/apps/web/landing/index.html +1 -0
  49. package/apps/web/package.json +2 -2
  50. package/apps/web/scripts/build.mjs +66 -4
  51. package/apps/web/src/build-env.ts +125 -4
  52. package/apps/web/src/config-schema.ts +20 -6
  53. package/apps/web/static/{config.staging.json → config.prod-aws.json} +3 -2
  54. package/apps/web/tests/build-env.test.ts +210 -9
  55. package/apps/web/tests/build-smoke.test.ts +2 -2
  56. package/apps/web/tests/config-schema.test.ts +149 -25
  57. package/docs/AWS-Deployment.md +793 -118
  58. package/docs/AWS-TCP-Deployment.md +57 -47
  59. package/docs/Chat-History.md +55 -0
  60. package/docs/Cloudflare-Deployment-Guide.md +95 -114
  61. package/docs/Cloudflare-TCP-Deployment.md +160 -101
  62. package/docs/Release-Process.md +27 -23
  63. package/docs/SASL-EXTERNAL.md +175 -0
  64. package/docs/Services.md +69 -22
  65. package/docs/WebClientGuide.md +35 -26
  66. package/package.json +7 -10
  67. package/packages/aws-adapter/package.json +1 -1
  68. package/packages/aws-adapter/src/admission.ts +28 -13
  69. package/packages/aws-adapter/src/aws-runtime.ts +30 -3
  70. package/packages/aws-adapter/src/cdk-table-defs.ts +39 -16
  71. package/packages/aws-adapter/src/config-loader.ts +153 -8
  72. package/packages/aws-adapter/src/dynamo-services-store.ts +19 -0
  73. package/packages/aws-adapter/src/handlers/connect.ts +73 -1
  74. package/packages/aws-adapter/src/handlers/default.ts +279 -123
  75. package/packages/aws-adapter/src/handlers/index.ts +98 -25
  76. package/packages/aws-adapter/src/handlers/nlb-stream.ts +135 -14
  77. package/packages/aws-adapter/src/index.ts +5 -7
  78. package/packages/aws-adapter/src/ip-admission.ts +79 -0
  79. package/packages/aws-adapter/src/origin-allowlist.ts +94 -0
  80. package/packages/aws-adapter/src/serialize.ts +23 -0
  81. package/packages/aws-adapter/src/tables.ts +11 -12
  82. package/packages/aws-adapter/tests/admission.test.ts +60 -2
  83. package/packages/aws-adapter/tests/aws-harness.ts +23 -2
  84. package/packages/aws-adapter/tests/aws-runtime.test.ts +64 -0
  85. package/packages/aws-adapter/tests/config-loader.test.ts +217 -0
  86. package/packages/aws-adapter/tests/connect.test.ts +323 -3
  87. package/packages/aws-adapter/tests/default-frame-limit.test.ts +231 -0
  88. package/packages/aws-adapter/tests/default-occ.test.ts +226 -0
  89. package/packages/aws-adapter/tests/dynamo-services-store-unit.test.ts +134 -1
  90. package/packages/aws-adapter/tests/handlers.test.ts +174 -12
  91. package/packages/aws-adapter/tests/migrate-accounts-to-services.test.ts +164 -0
  92. package/packages/aws-adapter/tests/nlb-secure.test.ts +362 -0
  93. package/packages/aws-adapter/tests/nlb-stream.test.ts +628 -9
  94. package/packages/aws-adapter/tests/origin-allowlist.test.ts +110 -0
  95. package/packages/aws-adapter/tests/ping-checker.test.ts +0 -1
  96. package/packages/aws-adapter/tests/stats.test.ts +0 -3
  97. package/packages/aws-adapter/tests/sweeper.test.ts +0 -1
  98. package/packages/aws-adapter/tests/tables.test.ts +1 -8
  99. package/packages/aws-adapter/tests/transactions.test.ts +0 -1
  100. package/packages/cf-adapter/package.json +1 -5
  101. package/packages/cf-adapter/src/cf-runtime.ts +100 -10
  102. package/packages/cf-adapter/src/channel-do.ts +13 -3
  103. package/packages/cf-adapter/src/config-loader.ts +133 -8
  104. package/packages/cf-adapter/src/connection-do.ts +406 -116
  105. package/packages/cf-adapter/src/counter-do.ts +142 -0
  106. package/packages/cf-adapter/src/d1-services-store.ts +105 -26
  107. package/packages/cf-adapter/src/env.ts +99 -10
  108. package/packages/cf-adapter/src/index.ts +17 -7
  109. package/packages/cf-adapter/src/rate-limit-do.ts +87 -0
  110. package/packages/cf-adapter/tests/cf-runtime.test.ts +205 -16
  111. package/packages/cf-adapter/tests/channel-do.test.ts +118 -1
  112. package/packages/cf-adapter/tests/config-loader.test.ts +159 -0
  113. package/packages/cf-adapter/tests/connection-do-counter.test.ts +165 -0
  114. package/packages/cf-adapter/tests/connection-do-coverage.test.ts +460 -0
  115. package/packages/cf-adapter/tests/connection-do-frame-limit.test.ts +177 -0
  116. package/packages/cf-adapter/tests/connection-do-pure.test.ts +164 -54
  117. package/packages/cf-adapter/tests/connection-do-sasl-d1.test.ts +62 -38
  118. package/packages/cf-adapter/tests/connection-do-ws-spec-contract.test.ts +7 -4
  119. package/packages/cf-adapter/tests/counter-do.test.ts +181 -0
  120. package/packages/cf-adapter/tests/d1-services-store.test.ts +245 -3
  121. package/packages/cf-adapter/tests/rate-limit-do.test.ts +160 -0
  122. package/packages/cf-adapter/tests/serialize.test.ts +25 -0
  123. package/packages/cf-adapter/tests/worker/main.ts +4 -0
  124. package/packages/cf-adapter/wrangler.test.toml +18 -1
  125. package/packages/in-memory-runtime/package.json +1 -1
  126. package/packages/in-memory-runtime/src/in-memory-runtime.ts +25 -0
  127. package/packages/in-memory-runtime/tests/in-memory-runtime.test.ts +74 -0
  128. package/packages/irc-core/package.json +1 -1
  129. package/packages/irc-core/src/account-migration.ts +140 -0
  130. package/packages/irc-core/src/caps/capabilities.ts +20 -10
  131. package/packages/irc-core/src/certfp.ts +178 -0
  132. package/packages/irc-core/src/commands/account-auth.ts +16 -19
  133. package/packages/irc-core/src/commands/cap.ts +10 -2
  134. package/packages/irc-core/src/commands/chanserv.ts +117 -14
  135. package/packages/irc-core/src/commands/chathistory.ts +13 -5
  136. package/packages/irc-core/src/commands/hostserv.ts +84 -8
  137. package/packages/irc-core/src/commands/index.ts +2 -1
  138. package/packages/irc-core/src/commands/invite.ts +1 -7
  139. package/packages/irc-core/src/commands/join.ts +1 -16
  140. package/packages/irc-core/src/commands/kick.ts +1 -8
  141. package/packages/irc-core/src/commands/list.ts +1 -8
  142. package/packages/irc-core/src/commands/memoserv.ts +1 -1
  143. package/packages/irc-core/src/commands/mode.ts +1 -8
  144. package/packages/irc-core/src/commands/multiline.ts +4 -10
  145. package/packages/irc-core/src/commands/names.ts +53 -13
  146. package/packages/irc-core/src/commands/nickserv.ts +161 -11
  147. package/packages/irc-core/src/commands/oper.ts +361 -8
  148. package/packages/irc-core/src/commands/part.ts +4 -10
  149. package/packages/irc-core/src/commands/privmsg.ts +8 -4
  150. package/packages/irc-core/src/commands/registration.ts +148 -4
  151. package/packages/irc-core/src/commands/sasl.ts +154 -46
  152. package/packages/irc-core/src/commands/topic.ts +10 -12
  153. package/packages/irc-core/src/commands/who.ts +1 -8
  154. package/packages/irc-core/src/config.ts +424 -25
  155. package/packages/irc-core/src/credential-hashing.ts +11 -54
  156. package/packages/irc-core/src/effects.ts +24 -0
  157. package/packages/irc-core/src/flood-control.ts +10 -10
  158. package/packages/irc-core/src/frame-rate-limit.ts +82 -0
  159. package/packages/irc-core/src/index.ts +9 -0
  160. package/packages/irc-core/src/oper-hashing.ts +43 -0
  161. package/packages/irc-core/src/oper-lockout.ts +87 -0
  162. package/packages/irc-core/src/ports.ts +529 -190
  163. package/packages/irc-core/src/protocol/bytes.ts +65 -0
  164. package/packages/irc-core/src/protocol/channel-name.ts +37 -0
  165. package/packages/irc-core/src/protocol/index.ts +12 -1
  166. package/packages/irc-core/src/protocol/outbound.ts +43 -10
  167. package/packages/irc-core/src/protocol/parser.ts +79 -10
  168. package/packages/irc-core/src/state/connection.ts +13 -0
  169. package/packages/irc-core/src/types.ts +266 -23
  170. package/packages/irc-core/src/ws-framing.ts +5 -4
  171. package/packages/irc-core/tests/account-migration.test.ts +133 -0
  172. package/packages/irc-core/tests/bytes.test.ts +89 -0
  173. package/packages/irc-core/tests/certfp.test.ts +117 -0
  174. package/packages/irc-core/tests/commands/cap.test.ts +76 -2
  175. package/packages/irc-core/tests/commands/chanserv.test.ts +166 -0
  176. package/packages/irc-core/tests/commands/chathistory.test.ts +140 -0
  177. package/packages/irc-core/tests/commands/hostserv.test.ts +316 -0
  178. package/packages/irc-core/tests/commands/join.test.ts +78 -1
  179. package/packages/irc-core/tests/commands/markread.test.ts +54 -0
  180. package/packages/irc-core/tests/commands/memoserv.test.ts +19 -0
  181. package/packages/irc-core/tests/commands/names.test.ts +193 -0
  182. package/packages/irc-core/tests/commands/nickserv.test.ts +419 -3
  183. package/packages/irc-core/tests/commands/oper.test.ts +574 -1
  184. package/packages/irc-core/tests/commands/privmsg.test.ts +16 -0
  185. package/packages/irc-core/tests/commands/registration.test.ts +602 -133
  186. package/packages/irc-core/tests/commands/sasl.test.ts +742 -172
  187. package/packages/irc-core/tests/commands/topic.test.ts +137 -2
  188. package/packages/irc-core/tests/commands/unified-account.test.ts +104 -84
  189. package/packages/irc-core/tests/config.test.ts +534 -2
  190. package/packages/irc-core/tests/credential-hashing.test.ts +0 -78
  191. package/packages/irc-core/tests/effects.test.ts +14 -0
  192. package/packages/irc-core/tests/flood-control.test.ts +29 -1
  193. package/packages/irc-core/tests/frame-rate-limit.test.ts +98 -0
  194. package/packages/irc-core/tests/message-store.test.ts +5 -0
  195. package/packages/irc-core/tests/oper-hashing.test.ts +60 -0
  196. package/packages/irc-core/tests/oper-lockout.test.ts +74 -0
  197. package/packages/irc-core/tests/outbound.test.ts +148 -0
  198. package/packages/irc-core/tests/parser.test.ts +287 -5
  199. package/packages/irc-core/tests/persistent-services-store.test.ts +212 -12
  200. package/packages/irc-core/tests/ports.test.ts +170 -7
  201. package/packages/irc-core/tests/services-store.test.ts +567 -1
  202. package/packages/irc-core/tests/ws-framing.test.ts +45 -0
  203. package/packages/irc-core/vitest.config.ts +6 -1
  204. package/packages/irc-server/package.json +1 -1
  205. package/packages/irc-server/src/actor.ts +123 -22
  206. package/packages/irc-server/src/dispatch.ts +1 -0
  207. package/packages/irc-server/src/index.ts +7 -0
  208. package/packages/irc-server/src/redact.ts +159 -0
  209. package/packages/irc-server/src/runtime.ts +14 -0
  210. package/packages/irc-server/src/transport.ts +28 -1
  211. package/packages/irc-server/tests/actor.test.ts +563 -54
  212. package/packages/irc-server/tests/dispatch.test.ts +31 -0
  213. package/packages/irc-server/tests/redact.test.ts +198 -0
  214. package/packages/irc-server/tests/runtime.test.ts +2 -0
  215. package/packages/irc-server/tests/transport.test.ts +66 -0
  216. package/packages/irc-test-support/package.json +1 -1
  217. package/packages/irc-test-support/src/in-memory-harness.ts +4 -0
  218. package/pnpm-workspace.yaml +1 -0
  219. package/scripts/__tests__/deploy-web-aws.test.ts +491 -0
  220. package/scripts/deploy-web-aws.mjs +290 -0
  221. package/scripts/package.json +23 -0
  222. package/scripts/tsconfig.test.json +12 -0
  223. package/scripts/vitest.config.ts +19 -0
  224. package/tools/ci-hardening/package.json +2 -2
  225. package/tools/ci-hardening/src/cf-deploy-cli.ts +3 -0
  226. package/tools/ci-hardening/src/cf-deploy.ts +118 -0
  227. package/tools/ci-hardening/src/deploy-hostname.ts +118 -0
  228. package/tools/ci-hardening/src/env-var-drift.ts +192 -0
  229. package/tools/ci-hardening/src/hostname-guard.ts +11 -0
  230. package/tools/ci-hardening/src/index.ts +19 -0
  231. package/tools/ci-hardening/src/validate.ts +57 -0
  232. package/tools/ci-hardening/tests/__wrangler_missing__.toml +2 -0
  233. package/tools/ci-hardening/tests/__wrangler_placeholder__.toml +3 -0
  234. package/tools/ci-hardening/tests/__wrangler_real__.toml +3 -0
  235. package/tools/ci-hardening/tests/cf-deploy.test.ts +200 -0
  236. package/tools/ci-hardening/tests/deploy-aws-oidc.test.ts +96 -0
  237. package/tools/ci-hardening/tests/deploy-hostname.test.ts +348 -0
  238. package/tools/ci-hardening/tests/env-var-drift.test.ts +284 -0
  239. package/tools/ci-hardening/tests/validate.test.ts +42 -0
  240. package/tools/ci-hardening/vitest.config.ts +5 -1
  241. package/tools/hash-oper-cred.ts +85 -0
  242. package/tools/load-test/package.json +1 -1
  243. package/tools/migrate-accounts-to-services.ts +270 -0
  244. package/tools/package.json +2 -1
  245. package/tools/seed-aws-accounts.ts +35 -10
  246. package/tools/seed-cf-accounts.ts +42 -9
  247. package/tools/tcp-ws-forwarder/package.json +1 -1
  248. package/packages/aws-adapter/src/account-store.ts +0 -121
  249. package/packages/aws-adapter/src/dynamo-account-store.ts +0 -95
  250. package/packages/aws-adapter/tests/account-store-dynamo.test.ts +0 -223
  251. package/packages/aws-adapter/tests/account-store.test.ts +0 -276
  252. package/packages/cf-adapter/src/d1-account-store.ts +0 -198
  253. package/packages/cf-adapter/tests/d1-account-store.test.ts +0 -274
  254. package/packages/irc-core/tests/account-store.test.ts +0 -131
@@ -12,7 +12,7 @@ CDK stack and a deployment can enable either or both.
12
12
  > This doc covers the *how*.
13
13
 
14
14
  **Acceptance criterion (TICKET-058):** a new contributor can deploy
15
- their own TCP+TLS staging instance following only this doc.
15
+ their own TCP+TLS instance following only this doc.
16
16
 
17
17
  Cross-reference: `apps/aws-stack/src/aws-stack.ts` (CDK), the wss path
18
18
  (`AWS-Deployment.md`), TICKET-054 (mTLS), ADR-006 (SASL scope).
@@ -102,7 +102,6 @@ The `IrcAwsStack` construct accepts an optional prop
102
102
 
103
103
  ```ts
104
104
  export interface IrcStackProps extends StackProps {
105
- readonly environmentName?: string;
106
105
  readonly serverName?: string;
107
106
  readonly networkName?: string;
108
107
  readonly motdLines?: string[];
@@ -130,21 +129,20 @@ deploys — the existing pipeline stays green.
130
129
 
131
130
  ---
132
131
 
133
- ## 4. Deploy staging (TCP+TLS)
132
+ ## 4. Deploy (TCP+TLS)
134
133
 
135
134
  ```bash
136
135
  # From the repo root:
137
- pnpm deploy:aws:staging -- \
138
- -c environmentName=staging \
139
- -c tcpTlsDomainName=irc-staging.example.com
136
+ pnpm deploy:aws -- \
137
+ -c tcpTlsDomainName=irc.example.com
140
138
  ```
141
139
 
142
140
  This is the same `cdk deploy --all` the wss path uses
143
- (`apps/aws-stack/package.json` `deploy:staging`), just with the extra
141
+ (`apps/aws-stack/package.json` `deploy`), just with the extra
144
142
  context var. The deploy will:
145
143
 
146
- 1. Create the ACM certificate for `irc-staging.example.com` (DNS
147
- validation via Route 53; if the hosted zone is not in this account,
144
+ 1. Create the ACM certificate for `irc.example.com` (DNS
145
+ validation via Route 53; if the hosted zone is not in this account,
148
146
  validate out-of-band and import the cert ARN — see §9.2).
149
147
  2. Provision `NlbVpc`, the internet-facing NLB, the `TLS` listener on
150
148
  `:6697`, and the `IrcNlbHandler` Lambda target group.
@@ -165,15 +163,15 @@ unchanged** — enabling TCP does not disable wss.
165
163
  The first deploy can take several minutes while ACM validates the
166
164
  certificate. `cdk deploy` waits on the certificate resource; do not
167
165
  interrupt it. If validation times out, confirm the hosted zone for the
168
- domain is in this account and Route 53 can write the `_acme-challenge`
166
+ domain is in this account and Route 53 can write the `_acme-challenge`
169
167
  CNAME.
170
168
 
171
169
  ### 4.2 Point a DNS record at the NLB (recommended)
172
170
 
173
171
  The NLB prints a long `.elb.amazonaws.com` DNS name. For a stable,
174
- owned hostname, create an **alias A record** (Route 53) or a CNAME
175
- pointing `irc-staging.example.com` → the NLB DNS name. Clients then
176
- connect to `irc-staging.example.com:6697`.
172
+ owned hostname, create an **alias A record** (Route 53) or a CNAME
173
+ pointing `irc.example.com` → the NLB DNS name. Clients then
174
+ connect to `irc.example.com:6697`.
177
175
 
178
176
  (You can connect directly to the raw NLB DNS, but the cert is issued for
179
177
  your domain, so TLS SNI/hostname verification wants the owned name.)
@@ -182,28 +180,12 @@ your domain, so TLS SNI/hostname verification wants the owned name.)
182
180
 
183
181
  ```bash
184
182
  printf 'NICK smoke\r\nUSER smoke 0 * :Smoke\r\nQUIT :smoke\r\n' | \
185
- timeout 10 openssl s_client -connect irc-staging.example.com:6697 -quiet | \
183
+ timeout 10 openssl s_client -connect irc.example.com:6697 -quiet | \
186
184
  grep -q '001' && echo "SMOKE PASS" || echo "SMOKE FAIL"
187
185
  ```
188
186
 
189
187
  ---
190
188
 
191
- ## 5. Deploy production
192
-
193
- ```bash
194
- pnpm deploy:aws:prod -- \
195
- -c environmentName=production \
196
- -c tcpTlsDomainName=irc.example.com
197
- ```
198
-
199
- Production deploys are manual. The staging CI workflow
200
- (`deploy-aws.yml`) deploys only the wss path (`-c environmentName=staging`
201
- without `tcpTlsDomainName`); there is **no auto-deploy for the TCP path
202
- yet** — add a `deploy-aws-tcp.yml` workflow (mirroring `deploy-cf-tcp.yml`)
203
- as a follow-up when the TCP path is ready for continuous staging.
204
-
205
- ---
206
-
207
189
  ## 6. Operational model & limits
208
190
 
209
191
  The NLB + Lambda streaming model has hard platform limits the wss path
@@ -230,6 +212,18 @@ State lifecycle is identical to the wss path: the **sweeper** Lambda
230
212
  no-PONG. Both cover TCP connections because the `connId` lives in the
231
213
  same `Connections` table.
232
214
 
215
+ **Per-IP new-flow rate limit.** The NLB path has no `$connect` event —
216
+ flow establishment IS the first chunk — so the `perIpConnectionRate`
217
+ budget is enforced inside `handleNlbStream`: the source IP (from
218
+ `x-forwarded-for`) is counted against the same `sourceIp-connectedSince`
219
+ GSI the wss `$connect` gate consults, and over-budget flows receive
220
+ `429` with no row written. Only establishment is budgeted: every
221
+ subsequent chunk of an established flow is also an invocation, and
222
+ rate-limiting those would starve an active IRC session. The knobs are
223
+ the shared `PER_IP_CONNECTION_RATE_MAX` / `PER_IP_CONNECTION_RATE_WINDOW_MS`
224
+ env vars (default 5 per 60 s; see `AWS-Deployment.md` §7.8 for the
225
+ three-layer throttling model).
226
+
233
227
  ---
234
228
 
235
229
  ## 7. Configuration reference
@@ -240,17 +234,20 @@ TCP-specific ones:
240
234
  | Knob (context var / prop) | Purpose | Default when omitted |
241
235
  |-------------------------------|--------------------------------------------------|----------------------------|
242
236
  | `tcpTlsDomainName` | Domain for the ACM cert + NLB TLS listener. | *(TCP path not provisioned)* |
243
- | `environmentName` | Env prefix for table names + stack id. | `staging` |
244
237
 
245
238
  The NLB handler Lambda inherits the **same** identity/table knobs as the
246
- wss handler (`serverName`, `networkName`, `motd`, `environmentName`),
247
- injected in `aws-stack.ts`:
239
+ wss handler (`serverName`, `networkName`, `motd`), injected in
240
+ `aws-stack.ts`:
248
241
 
249
242
  - `SERVER_NAME`, `NETWORK_NAME`, `MOTD` (read by the shared
250
243
  `config-loader.ts`).
251
244
  - `MANAGEMENT_URL` — the wss stage's callback URL, so cross-connection
252
- fanout reaches recipients on either transport.
253
- - `<TABLE>_TABLE` for each of the five tables (prefixed by environment).
245
+ fanout reaches recipients on either transport. The NLB handler's
246
+ execution role also carries `execute-api:ManageConnections` on the
247
+ wss stage (`stage.grantManagementApiAccess(nlbHandler)` in
248
+ `aws-stack.ts`, asserted by a synth-time test) — without it every
249
+ cross-transport `postToConnection` fails with 403.
250
+ - `<TABLE>_TABLE` for each of the five tables (bare logical ids).
254
251
 
255
252
  The Lambda handler entry is the same file
256
253
  (`packages/aws-adapter/src/handlers/index.ts`); esbuild tree-shakes to
@@ -259,7 +256,10 @@ excluded from the bundle (ships with the runtime).
259
256
 
260
257
  There are **no TCP-specific DynamoDB tables** — the existing `Connections`
261
258
  table gains a `transportBuffer` string attribute (SET when non-empty,
262
- REMOVE when empty) on rows whose `connectionId` starts with `nlb-`.
259
+ REMOVE when empty) on rows whose `connectionId` starts with `nlb-`, plus
260
+ the `sourceIp` attribute + `sourceIp-connectedSince` GSI shared with the
261
+ wss path's per-IP admission gates (both transports stamp the flow/client
262
+ IP at establishment).
263
263
 
264
264
  ---
265
265
 
@@ -325,6 +325,22 @@ then fanout uses `ApiGatewayManagementApi.postToConnection`, which works
325
325
  for both transports. If `MANAGEMENT_URL` is unset, `managementApi` is
326
326
  `null` and cross-connection sends are silent no-ops.
327
327
 
328
+ The mirror-image symptom — a TCP client's messages never reaching wss
329
+ recipients — is an IAM problem, not a push problem: the NLB handler's
330
+ role must carry `execute-api:ManageConnections` on the wss stage
331
+ (`stage.grantManagementApiAccess(nlbHandler)`; synth-time asserted in
332
+ `apps/aws-stack/tests/stack.test.ts`). Without the grant the NLB
333
+ handler's `postToConnection` calls fail with 403 and the delivery is
334
+ silently dropped. Verify manually after a deploy:
335
+
336
+ ```bash
337
+ # 1. Connect over wss (e.g. the web client) and JOIN #fanout-check.
338
+ # 2. Connect over TLS :6697 (openssl one-liner in §11) and JOIN #fanout-check.
339
+ # 3. PRIVMSG from the TCP side — the wss client must receive it, and vice
340
+ # versa. A silent drop + 403 in the IrcNlbHandler CloudWatch logs
341
+ # means the ManageConnections grant is missing.
342
+ ```
343
+
328
344
  ### 9.4 Lurkers get disconnected after a few minutes
329
345
 
330
346
  The NLB idle timeout. A receiving-only client sends no chunks, so the
@@ -372,25 +388,19 @@ RFC-compliant clients that need it.
372
388
  ## 11. Quick reference
373
389
 
374
390
  ```bash
375
- # Staging (TCP+TLS added alongside wss)
376
- pnpm deploy:aws:staging -- \
377
- -c environmentName=staging \
378
- -c tcpTlsDomainName=irc-staging.example.com
391
+ # Deploy (TCP+TLS added alongside wss)
392
+ pnpm deploy:aws -- \
393
+ -c tcpTlsDomainName=irc.example.com
379
394
 
380
395
  # Read the TCP endpoint from stack outputs
381
396
  aws cloudformation describe-stacks \
382
- --stack-name IrcAwsStack-staging \
397
+ --stack-name IrcAwsStack \
383
398
  --query 'Stacks[0].Outputs[?OutputKey==`TcpConnectUrl`].OutputValue' \
384
399
  --output text
385
400
 
386
401
  # Smoke over TLS
387
402
  printf 'NICK smoke\r\nUSER smoke 0 * :Smoke\r\nQUIT :smoke\r\n' | \
388
- openssl s_client -connect irc-staging.example.com:6697 -quiet | grep '001'
389
-
390
- # Production (manual)
391
- pnpm deploy:aws:prod -- \
392
- -c environmentName=production \
393
- -c tcpTlsDomainName=irc.example.com
403
+ openssl s_client -connect irc.example.com:6697 -quiet | grep '001'
394
404
 
395
405
  # Tests (synth-time assertions for the NLB path)
396
406
  pnpm --filter @serverless-ircd/aws-stack test
@@ -0,0 +1,55 @@
1
+ # Chat History (`draft/chathistory`)
2
+
3
+ The server implements the IRCv3 [`draft/chathistory`](https://ircv3.net/specs/extensions/chathistory)
4
+ extension: a client that negotiates the `draft/chathistory` cap may query
5
+ stored backlog (`LATEST` / `BEFORE` / `AFTER` / `AROUND` / `BETWEEN` /
6
+ `TARGETS`) and receives the matching messages wrapped in a
7
+ `BATCH chathistory <target>` frame, each replay line carrying its original
8
+ `@time=…` and `msgid=…` tags.
9
+
10
+ ## Query limit ceiling
11
+
12
+ Every client-supplied `limit` is **silently capped** at a deployment
13
+ ceiling before it reaches the `MessageStore`:
14
+
15
+ - `CHATHISTORY LATEST #chan * 999999999` returns at most
16
+ `chathistory.maxLimit` messages (default **100**) — the oversized value
17
+ never reaches the store, so a future higher-capacity backend cannot be
18
+ tricked into materializing a huge result set.
19
+ - The cap is silent: the client receives up to the ceiling worth of
20
+ replay lines and no error. Requests below the ceiling pass through
21
+ unchanged; a request for exactly the ceiling is honored in full.
22
+ - When the client omits the limit, the server default (50) applies —
23
+ also bounded by the ceiling, so a deployment that lowers
24
+ `chathistory.maxLimit` below 50 caps the default too.
25
+ - A limit that is not a non-negative integer (e.g. `abc`, `-5`) is
26
+ rejected with `461 ERR_NEEDMOREPARAMS` (Invalid parameters), unchanged
27
+ by the ceiling.
28
+
29
+ ### Configuration
30
+
31
+ | Knob | Default | Notes |
32
+ |-----------------------------|---------|------------------------------------------------|
33
+ | `chathistory.maxLimit` | `100` | Positive integer; per-`CHATHISTORY`-query cap. |
34
+
35
+ The knob lives in the server config (parsed by `ServerConfigSchema`), so
36
+ any adapter's config source can set it:
37
+
38
+ ```json
39
+ {
40
+ "serverName": "irc.example.com",
41
+ "networkName": "ExampleNet",
42
+ "chathistory": { "maxLimit": 250 }
43
+ }
44
+ ```
45
+
46
+ Omitting the `chathistory` section entirely inherits the default of 100.
47
+
48
+ ## Related
49
+
50
+ - JOIN auto-playback (`chatHistoryPlaybackLimit`, default 50) is a
51
+ separate knob covering the backlog replayed on JOIN; see
52
+ `packages/irc-core/src/config.ts`.
53
+ - `draft/read-marker` integration: `CHATHISTORY BEFORE` without an
54
+ explicit pivot falls back to the connection's last-read marker; see
55
+ `docs/PlanExtensions.md`.