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
@@ -2,15 +2,15 @@
2
2
 
3
3
  End-to-end guide for deploying ServerlessIRCd to Cloudflare Workers
4
4
  (Phase 3 of `PLAN.md`). Covers prerequisites, first-time account setup,
5
- local development, staging deploy, production deploy, configuration,
6
- secrets, sharding, CI/CD, cost, and troubleshooting.
5
+ local development, deploy, configuration, secrets, sharding, CI/CD,
6
+ cost, and troubleshooting.
7
7
 
8
8
  Cross-reference: `PLAN.md` §6.1 (CF mapping), `apps/cf-worker/wrangler.toml`,
9
9
  `packages/cf-adapter/`, `.github/workflows/deploy-cf.yml`. For the AWS
10
- equivalent, see `docs/deployment-aws.md` (TICKET-044).
10
+ equivalent, see `docs/AWS-Deployment.md`.
11
11
 
12
12
  **Acceptance criterion (TICKET-038):** a new contributor can deploy their
13
- own staging instance following only this doc.
13
+ own instance following only this doc.
14
14
 
15
15
  ---
16
16
 
@@ -52,8 +52,10 @@ connection's `ConnectionDO`. All IRC protocol logic lives in the shared
52
52
  `irc-core` reducers, run by `ConnectionActor` inside the DO. No state is
53
53
  held in the Worker process itself.
54
54
 
55
- The same artifacts serve both staging and production; the only difference
56
- is the `--env` flag and the `[env.staging]` block in `wrangler.toml`.
55
+ There is a single deploy target the staging/prod split was collapsed.
56
+ The same `wrangler.toml` ships to whichever Cloudflare account the
57
+ deploy credentials target; staging vs production isolation is by
58
+ account, not by a `[env.staging]` block.
57
59
 
58
60
  ---
59
61
 
@@ -63,15 +65,15 @@ is the `--env` flag and the `[env.staging]` block in `wrangler.toml`.
63
65
  |-----------------------|--------------------------------------------------------|
64
66
  | Node.js | ≥ 20 (matches CI; `engines.node` in root `package.json`)|
65
67
  | pnpm | 9.x (`packageManager: pnpm@9.15.9` in root `package.json`)|
66
- | Cloudflare account | Free tier is enough for staging. Workers Paid plan |
67
- | | (USD $5/mo) is recommended for production — see §10. |
68
+ | Cloudflare account | Free tier is enough to bring up the Worker. Workers Paid |
69
+ | | plan (USD $5/mo) is recommended for real traffic — see §10.|
68
70
  | `wrangler` CLI | Comes from `apps/cf-worker/devDependencies`; no global install needed. |
69
- | Git checkout | Clean working tree on `main` for production deploys. |
71
+ | Git checkout | Clean working tree on `main` for deploys. |
70
72
 
71
- A **Workers Paid plan** is not strictly required for staging, but
72
- Durable Objects only run on the Paid plan in any meaningful production
73
- scenario. The free tier caps DO requests and disables hibernation
74
- budget headroom. See §10 (Cost).
73
+ A **Workers Paid plan** is not strictly required to bring the Worker
74
+ up, but Durable Objects only run on the Paid plan in any meaningful
75
+ production scenario. The free tier caps DO requests and disables
76
+ hibernation budget headroom. See §10 (Cost).
75
77
 
76
78
  Confirm the local environment:
77
79
 
@@ -136,9 +138,8 @@ export CLOUDFLARE_ACCOUNT_ID=...
136
138
  ```
137
139
 
138
140
  When `CLOUDFLARE_API_TOKEN` is set in the environment, `wrangler` uses
139
- it directly and skips the OAuth store. The deploy commands in
140
- `apps/cf-worker/package.json` (`deploy:staging`, `deploy:prod`) honor
141
- both.
141
+ it directly and skips the OAuth store. The deploy command in
142
+ `apps/cf-worker/package.json` (`deploy`) honors both.
142
143
 
143
144
  ---
144
145
 
@@ -172,7 +173,7 @@ Expected output (success):
172
173
  The smoke script (`scripts/smoke.mjs`) replays
173
174
  CONNECT → NICK/USER → JOIN #smoke → PRIVMSG → QUIT and asserts the
174
175
  server emits `001`, `376`, `353`, `366`, and closes the socket. It is
175
- the exact same script CI runs against the deployed staging URL.
176
+ the exact same script CI runs against the deployed URL.
176
177
 
177
178
  The unit + integration suites live in `packages/cf-adapter/tests/` and
178
179
  `apps/cf-worker/tests/`; both run under `@cloudflare/vitest-pool-workers`
@@ -185,29 +186,29 @@ pnpm --filter @serverless-ircd/cf-worker test
185
186
 
186
187
  ---
187
188
 
188
- ## 5. Deploy staging
189
+ ## 5. Deploy
189
190
 
190
- Staging is the environment CI deploys on every push to `main`; you can
191
- also deploy it manually from a clean checkout.
191
+ The deploy is `workflow_dispatch`-only (a maintainer triggers it by
192
+ hand); you can also deploy manually from a clean checkout.
192
193
 
193
194
  ### 5.1 Deploy from your machine
194
195
 
195
196
  ```bash
196
197
  # From the repo root:
197
- pnpm deploy:cf:staging
198
+ pnpm deploy:cf
198
199
  # Equivalent to:
199
- # pnpm --filter @serverless-ircd/cf-worker deploy:staging
200
- # → wrangler deploy --env staging
200
+ # pnpm --filter @serverless-ircd/cf-worker run deploy
201
+ # → wrangler deploy
201
202
  ```
202
203
 
203
204
  The first deploy of a given account will:
204
205
 
205
- 1. Create the Worker `serverless-ircd-staging`.
206
- 2. Apply the `[[env.staging.migrations]]` block (`tag = "v1"`,
207
- `new_classes = [ConnectionDO, RegistryDO, ChannelDO]`). This is what
208
- provisions the three DO namespaces.
206
+ 1. Create the Worker `serverless-ircd`.
207
+ 2. Apply the `[[migrations]]` block (`tag = "v1"`,
208
+ `new_sqlite_classes = [ConnectionDO, RegistryDO, ChannelDO,
209
+ ChannelRegistryDO]`). This is what provisions the DO namespaces.
209
210
  3. Print the deployed URL, e.g.
210
- `https://serverless-ircd-staging.example.workers.dev`.
211
+ `https://serverless-ircd.example.workers.dev`.
211
212
 
212
213
  If you see `Migration tag has already been applied`, the namespaces
213
214
  already exist; subsequent deploys just update the Worker code.
@@ -216,7 +217,7 @@ already exist; subsequent deploys just update the Worker code.
216
217
 
217
218
  ```bash
218
219
  node apps/cf-worker/scripts/smoke.mjs \
219
- --url wss://serverless-ircd-staging.example.workers.dev
220
+ --url wss://serverless-ircd.example.workers.dev
220
221
  ```
221
222
 
222
223
  The same JSON `level: "info"` line on stdout means the full
@@ -228,7 +229,7 @@ Point any RFC-compliant WebSocket-aware IRC client at the deployed URL.
228
229
  For WeeChat:
229
230
 
230
231
  ```
231
- /server add ircd serverless-ircd-staging.example.workers.dev/443
232
+ /server add ircd serverless-ircd.example.workers.dev/443
232
233
  /set irc.server.ircd.ssl on
233
234
  /connect ircd
234
235
  /join #test
@@ -241,18 +242,14 @@ section.
241
242
 
242
243
  ---
243
244
 
244
- ## 6. Deploy production
245
+ ## 6. Production hardening
245
246
 
246
- Production is the default `wrangler.toml` environment (no `--env`
247
- flag). It deploys the Worker named `serverless-ircd` (no `-staging`
248
- suffix) with its own DO namespaces.
247
+ There is a single deploy target per platform (`pnpm deploy:cf`). The
248
+ staging/prod split was collapsed there is no `[env.staging]` block
249
+ and no `--env` flag. The Worker is always named `serverless-ircd`.
249
250
 
250
- ```bash
251
- # From the repo root:
252
- pnpm deploy:cf:prod
253
- ```
254
-
255
- Before your first production deploy, edit `apps/cf-worker/wrangler.toml`:
251
+ Before your first deploy against a real account, edit
252
+ `apps/cf-worker/wrangler.toml`:
256
253
 
257
254
  1. Set `[vars].SERVER_NAME` to the public hostname clients should see
258
255
  in numerics (`001`, `005`, etc.) — e.g. `irc.your-domain.com`.
@@ -263,60 +260,46 @@ Before your first production deploy, edit `apps/cf-worker/wrangler.toml`:
263
260
  3. Set `[vars].MOTD_LINES` to your message-of-the-day (newline-delimited).
264
261
  4. (Optional) Add a custom-domain Route under `[[routes]]` — see §8.4.
265
262
 
266
- **First-time production migration:** the default `[[migrations]]` block
267
- applies on the first `deploy:cf:prod` and creates the production DO
268
- classes. This is one-way: once a DO namespace has data, you cannot
269
- rename or delete a class without an explicit migration entry (see
270
- §9.2).
263
+ **First-time migration:** the `[[migrations]]` block applies on the
264
+ first deploy and creates the DO classes. This is one-way: once a DO
265
+ namespace has data, you cannot rename or delete a class without an
266
+ explicit migration entry (see §9.2).
271
267
 
272
- There is **no CI auto-deploy to production** — production deploys are
273
- always manual (`workflow_dispatch` only is intentionally not wired; see
274
- `.github/workflows/deploy-cf.yml`). Staging deploys on every push to
275
- `main`.
268
+ Staging vs production isolation is by **Cloudflare account** point a
269
+ separate account's `CLOUDFLARE_API_TOKEN` at the deploy to ship to a
270
+ different Worker namespace.
276
271
 
277
272
  ---
278
273
 
279
274
  ## 7. Configuration reference
280
275
 
281
276
  All deployment knobs live in `apps/cf-worker/wrangler.toml`. The file
282
- is the single source of truth for both environments.
277
+ is the single source of truth for the Worker.
283
278
 
284
279
  ### 7.1 Top-level / `[vars]`
285
280
 
286
281
  | Var | Purpose | Default |
287
282
  |-----------------|----------------------------------------------------|--------------------------------------|
288
- | `name` | Worker name. Staging overrides to `...-staging`. | `serverless-ircd` |
283
+ | `name` | Worker name. | `serverless-ircd` |
289
284
  | `main` | Worker entry. | `src/worker.ts` |
290
285
  | `compatibility_date` | Pins Workers runtime behavior. | `2024-11-01` |
291
286
  | `compatibility_flags` | `nodejs_compat` enables Node-style APIs. | `["nodejs_compat"]` |
292
287
  | `SERVER_NAME` | Server name sent in `001`/`005` numerics. **Required** — the CF config loader fails fast at boot when unset. | _No default; must be set in `wrangler.toml`._ |
293
288
  | `NETWORK_NAME` | Network label in `005 NETWORK=…`. | `ServerlessIRCd` |
294
289
  | `MOTD_LINES` | Message-of-the-day, `\n`-delimited. | Welcome banner string. |
290
+ | `MAX_CLIENTS` | Global live-connection cap (enforced by `CounterDO` at the edge). | schema default |
291
+ | `MAX_CONNECTIONS_PER_IP` | Per-IP simultaneous-connection cap (in-memory admission in `ConnectionDO`). | schema default (10) |
292
+ | `PER_IP_CONNECTION_RATE_MAX` | Per-IP upgrade rate budget — how many WebSocket upgrades one `CF-Connecting-IP` may open per sliding window. Enforced at the edge by `RateLimitDO` (429 when over budget). | schema default (5) |
293
+ | `PER_IP_CONNECTION_RATE_WINDOW_MS` | Sliding-window length in ms for the upgrade rate budget. Setting only one half of the pair falls back to the schema default (60 000 ms) for the other. | schema default (60 000) |
295
294
 
296
295
  These are read by `ConnectionDO` via `Env` (see
297
296
  `packages/cf-adapter/src/env.ts:20` and the `serverConfig()` method in
298
297
  `connection-do.ts:337`). They are **not** secrets — they ship in the
299
298
  bundle and are visible in the dashboard.
300
299
 
301
- ### 7.2 `[env.staging]`
302
-
303
- The staging block overrides `name` and `[vars]` only. The DO bindings
304
- and migrations must be redeclared per-environment (wrangler requires
305
- explicit per-env blocks — they do not inherit):
300
+ ### 7.2 Durable Object bindings
306
301
 
307
- ```toml
308
- [env.staging]
309
- name = "serverless-ircd-staging"
310
-
311
- [env.staging.vars]
312
- SERVER_NAME = "irc-staging.example.com"
313
- NETWORK_NAME = "ServerlessIRCd (staging)"
314
- MOTD_LINES = "..."
315
- ```
316
-
317
- ### 7.3 Durable Object bindings
318
-
319
- Three DO classes are exported from `src/worker.ts` (re-exported from
302
+ The DO classes are exported from `src/worker.ts` (re-exported from
320
303
  `@serverless-ircd/cf-adapter`) and bound in `wrangler.toml`:
321
304
 
322
305
  | Binding name | Class | Owned state |
@@ -324,16 +307,19 @@ Three DO classes are exported from `src/worker.ts` (re-exported from
324
307
  | `CONNECTION_DO` | `ConnectionDO` | Socket + ConnectionState + PING alarms. |
325
308
  | `REGISTRY_DO` | `RegistryDO` | Nick uniqueness, nick→connId map (sharded).|
326
309
  | `CHANNEL_DO` | `ChannelDO` | Per-channel roster, modes, topic, fanout. |
310
+ | `CHANNEL_REGISTRY_DO` | `ChannelRegistryDO` | The channel-name registry (shard index). |
311
+ | `COUNTER_DO` | `CounterDO` | Global live-connection counter (`maxClients` cap, TICKET-194). |
312
+ | `RATE_LIMIT_DO` | `RateLimitDO` | Per-IP upgrade rate limiter — one sliding-window admission list per `CF-Connecting-IP`; the Worker edge checks the budget before forwarding an upgrade and rejects over-budget IPs with `429` (the per-IP layer of the connect throttling; runs before the `maxClients` counter so a flooding IP cannot consume global slots). |
327
313
 
328
314
  The class names in `wrangler.toml`'s `class_name` field MUST match the
329
315
  re-exports at the top of `apps/cf-worker/src/worker.ts:29`.
330
316
 
331
- ### 7.4 Migrations
317
+ ### 7.3 Migrations
332
318
 
333
319
  ```toml
334
320
  [[migrations]]
335
321
  tag = "v1"
336
- new_classes = ["ConnectionDO", "RegistryDO", "ChannelDO"]
322
+ new_sqlite_classes = ["ConnectionDO", "RegistryDO", "ChannelDO", "ChannelRegistryDO", "CounterDO", "RateLimitDO"]
337
323
  ```
338
324
 
339
325
  `tag` is the migration id (string, monotonically tracked by wrangler).
@@ -342,10 +328,10 @@ new_classes = ["ConnectionDO", "RegistryDO", "ChannelDO"]
342
328
  block with `tag = "v2"` (etc.) and a `renamed_classes` or `deleted_classes`
343
329
  entry. See <https://developers.cloudflare.com/durable-objects/reference/durable-objects-migrations/>.
344
330
 
345
- Both the default and staging environments carry their own migration
346
- list. Keep them in sync unless you intentionally diverge.
331
+ There is a single migration list the `[env.staging]` block was
332
+ removed when staging/prod collapsed into one target.
347
333
 
348
- ### 7.5 Custom domain (optional)
334
+ ### 7.4 Custom domain (optional)
349
335
 
350
336
  To serve the Worker on `irc.example.com` instead of the workers.dev
351
337
  subdomain, add a route and bind a Cloudflare-managed DNS record:
@@ -357,9 +343,9 @@ zone_name = "example.com"
357
343
  custom_domain = false # true if you'd rather use a Worker Custom Domain
358
344
  ```
359
345
 
360
- Custom domains are optional for staging and recommended for production
361
- (many IRC clients expect a stable, owned hostname). DNS records are
362
- managed separately in the dashboard.
346
+ Custom domains are optional for a first deploy and recommended for
347
+ real traffic (many IRC clients expect a stable, owned hostname). DNS
348
+ records are managed separately in the dashboard.
363
349
 
364
350
  ---
365
351
 
@@ -372,7 +358,7 @@ disabled (the default). Configure it as a wrangler secret, never a
372
358
  plaintext `[vars]` entry:
373
359
 
374
360
  ```bash
375
- wrangler secret put SERVER_PASSWORD --env staging
361
+ wrangler secret put SERVER_PASSWORD
376
362
  # → prompts for the value; stores it in the Workers secret store,
377
363
  # NOT in wrangler.toml or the repo.
378
364
  ```
@@ -463,8 +449,7 @@ node --import tsx tools/seed-cf-accounts.ts \
463
449
  --accounts alice:change-me bob:also-change-me
464
450
  ```
465
451
 
466
- For staging, add `--env staging` and use the staging database name. The
467
- seed CLI hashes each password locally and executes the `INSERT OR REPLACE`
452
+ The seed CLI hashes each password locally and executes the `INSERT OR REPLACE`
468
453
  via `wrangler d1 execute`.
469
454
 
470
455
  > The `SASL_ACCOUNTS` env var remains the quick-start path (no D1 needed):
@@ -548,9 +533,9 @@ the public list price as of 2024-11; verify current pricing at
548
533
 
549
534
  Practical numbers:
550
535
 
551
- - **Workers Free plan**: sufficient to bring up staging, exercise the
536
+ - **Workers Free plan**: sufficient to bring up the Worker, exercise the
552
537
  smoke e2e, and validate a handful of concurrent connections. Not
553
- suitable for production traffic (request caps, no reserved DO
538
+ suitable for sustained traffic (request caps, no reserved DO
554
539
  compute).
555
540
  - **Workers Paid plan** (USD $5/mo base + usage): enough headroom for a
556
541
  small production network. The dominant cost driver at scale is
@@ -572,10 +557,10 @@ mitigations (batched fanout, per-channel send-list cache).
572
557
 
573
558
  ## 11. CI/CD
574
559
 
575
- The GitHub Actions workflow at `.github/workflows/deploy-cf.yml`
576
- deploys staging on every push to `main` and replays the smoke e2e. It
577
- is the canonical deploy path manual `pnpm deploy:cf:staging` is for
578
- iteration only.
560
+ The GitHub Actions workflow at `.github/workflows/deploy-cf.yml` is
561
+ `workflow_dispatch`-only (a maintainer triggers it by hand); there is
562
+ no automatic push-to-main deploy. It deploys the single Worker target
563
+ and replays the smoke e2e.
579
564
 
580
565
  Steps performed by the workflow (in order):
581
566
 
@@ -584,13 +569,13 @@ Steps performed by the workflow (in order):
584
569
  3. `pnpm install --frozen-lockfile`.
585
570
  4. `pnpm build` — builds all workspace packages.
586
571
  5. `pnpm typecheck` and `pnpm test` — gate the deploy.
587
- 6. `pnpm deploy:cf:staging` — `wrangler deploy --env staging`.
572
+ 6. `pnpm deploy:cf` — `wrangler deploy`.
588
573
  7. Resolve the smoke URL from the `CF_SMOKE_URL` repo variable. If
589
574
  unset, the smoke step is skipped with a warning.
590
575
  8. Run `node scripts/smoke.mjs --url "$SMOKE_URL"`. Failure fails the
591
576
  build.
592
577
 
593
- Concurrency is serialized via `concurrency.group: cf-staging` so two
578
+ Concurrency is serialized via `concurrency.group: cf-deploy` so two
594
579
  deploys cannot race the same DO namespace.
595
580
 
596
581
  Required repo configuration (under Settings → Secrets and variables →
@@ -599,12 +584,12 @@ Actions):
599
584
  - **Secret `CLOUDFLARE_API_TOKEN`** — required.
600
585
  - **Secret `CLOUDFLARE_ACCOUNT_ID`** — required if the token's account
601
586
  context is ambiguous.
602
- - **Variable `CF_SMOKE_URL`** — set to the staging Worker's `wss://`
587
+ - **Variable `CF_SMOKE_URL`** — set to the Worker's `wss://`
603
588
  URL. Without it, the smoke step silently no-ops.
604
589
 
605
- There is **no auto-deploy to production**. Production deploys are
606
- intentionally manual (`pnpm deploy:cf:prod` from a clean checkout on
607
- `main`).
590
+ There is a single deploy target the staging/prod split was collapsed,
591
+ so the same workflow + account ships to whichever Worker namespace the
592
+ credentials target.
608
593
 
609
594
  ---
610
595
 
@@ -619,10 +604,10 @@ the `[[migrations]]` block, wrangler refuses to proceed.
619
604
  - If you intentionally changed the DO schema, append a new
620
605
  `[[migrations]]` block with `tag = "v2"` (and `renamed_classes` /
621
606
  `deleted_classes` as needed). Never edit an already-applied `tag`.
622
- - If the staging namespace has stale state from an aborted experiment,
607
+ - If the namespace has stale state from an aborted experiment,
623
608
  you can destroy and recreate it from the dashboard (Workers & Pages →
624
- Durable Objects → namespaces). **Production namespaces must never be
625
- deleted** — that data is gone permanently.
609
+ Durable Objects → namespaces). **Namespaces carrying real traffic must
610
+ never be deleted** — that data is gone permanently.
626
611
 
627
612
  ### 12.2 `Cannot find module '@serverless-ircd/cf-adapter'`
628
613
 
@@ -636,10 +621,10 @@ The connection upgrade succeeded but registration didn't complete.
636
621
  Common causes:
637
622
 
638
623
  - The deployed Worker is reachable but the DO threw on the first frame.
639
- Tail the logs: `wrangler tail --env staging` and reproduce.
624
+ Tail the logs: `wrangler tail` and reproduce.
640
625
  - The `MOTD_LINES` or `SERVER_NAME` var was deleted — `ConnectionDO`'s
641
626
  `serverConfig()` falls back to defaults, but a malformed value can
642
- break parsing. Check the `[env.staging.vars]` block.
627
+ break parsing. Check the `[vars]` block.
643
628
  - Client connected over `ws://` to a Worker that requires `wss://`.
644
629
  Use the `wss://` URL the deploy step printed.
645
630
 
@@ -649,8 +634,8 @@ The DO alarm fired but the handler threw. The most likely cause is a
649
634
  stale persisted-state version after a code change; the serializer in
650
635
  `packages/cf-adapter/src/serialize.ts` carries `PERSISTED_STATE_VERSION`
651
636
  and will reject incompatible blobs. If this happens after an upgrade,
652
- ship a `deserialize` migration that upgrades the old version (or, on
653
- staging, clear the DO storage from the dashboard).
637
+ ship a `deserialize` migration that upgrades the old version (or, on a
638
+ throwaway deployment, clear the DO storage from the dashboard).
654
639
 
655
640
  ### 12.5 Nick reservation always fails
656
641
 
@@ -658,9 +643,9 @@ A client's `NICK` command always returns `433 ERR_NICKNAMEINUSE`, even
658
643
  for nicknames that should be free. This happens when two deployments
659
644
  share a `RegistryDO` namespace but were supposed to be separate —
660
645
  e.g., staging and production point at the same DO class name. Verify
661
- that each environment has its own DO namespace (the Worker name
662
- differs: `serverless-ircd` vs `serverless-ircd-staging`, and wrangler
663
- allocates a distinct namespace per Worker).
646
+ that each deployment has its own DO namespace (a distinct Worker name
647
+ per Cloudflare account means wrangler allocates a distinct namespace
648
+ per Worker).
664
649
 
665
650
  ### 12.6 High request cost / DO request spike
666
651
 
@@ -687,9 +672,9 @@ appears lost, either:
687
672
  - The persisted-state version changed without a deserialize migration
688
673
  (see 12.4).
689
674
 
690
- For staging, the fastest recovery is usually to clear DO storage and
691
- re-test. For production, treat any migration tag change as a release
692
- blocker requiring a runbook entry.
675
+ For a throwaway deployment, the fastest recovery is usually to clear DO
676
+ storage and re-test. For real traffic, treat any migration tag change
677
+ as a release blocker requiring a runbook entry.
693
678
 
694
679
  ---
695
680
 
@@ -705,15 +690,11 @@ pnpm build
705
690
  pnpm --filter @serverless-ircd/cf-worker dev # http://localhost:8787
706
691
  node apps/cf-worker/scripts/smoke.mjs # smoke against localhost
707
692
 
708
- # Staging
709
- pnpm deploy:cf:staging
693
+ # Deploy (single target — staging vs prod is which account you point at)
694
+ pnpm deploy:cf
710
695
  node apps/cf-worker/scripts/smoke.mjs \
711
- --url wss://serverless-ircd-staging.<subdomain>.workers.dev
712
- npx wrangler tail --env staging # live logs
713
-
714
- # Production (manual only)
715
- pnpm deploy:cf:prod
716
- npx wrangler tail # default env = production
696
+ --url wss://serverless-ircd.<subdomain>.workers.dev
697
+ npx wrangler tail # live logs
717
698
 
718
699
  # Tests / lint
719
700
  pnpm test # full workspace
@@ -732,4 +713,4 @@ Key files:
732
713
  | `packages/cf-adapter/src/` | `ConnectionDO`, `RegistryDO`, `ChannelDO`, `CfRuntime`, sharding. |
733
714
  | `packages/cf-adapter/src/sharding.ts` | Shard function + `DEFAULT_REGISTRY_SHARDS`. |
734
715
  | `packages/cf-adapter/src/env.ts` | `Env` interface (binding contract). |
735
- | `.github/workflows/deploy-cf.yml` | Staging deploy + smoke e2e CI. |
716
+ | `.github/workflows/deploy-cf.yml` | Deploy + smoke e2e CI (manual dispatch). |