serverless-ircd 0.7.0 → 0.8.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 +3 -3
- package/.gitmodules +1 -1
- package/CHANGELOG.md +273 -29
- package/README.md +155 -55
- package/apps/aws-stack/package.json +1 -1
- package/apps/aws-stack/src/aws-stack.ts +186 -18
- package/apps/aws-stack/tests/stack.test.ts +400 -56
- package/apps/cf-tcp-container/package.json +1 -1
- package/apps/cf-worker/package.json +1 -1
- package/apps/cf-worker/src/worker.ts +4 -4
- package/apps/cf-worker/tests/fixtures/web-dist/webclient/index.html +18 -0
- package/apps/cf-worker/tests/smoke.test.ts +5 -5
- package/apps/cf-worker/wrangler.test.toml +6 -6
- package/apps/cf-worker/wrangler.toml +7 -5
- package/apps/local-cli/package.json +1 -1
- package/apps/local-cli/src/config-loader.ts +8 -0
- package/apps/local-cli/src/main.ts +16 -0
- package/apps/local-cli/src/server.ts +1 -0
- package/apps/local-cli/tests/config-loader.test.ts +14 -0
- package/apps/web/landing/index.html +14 -16
- package/apps/web/package.json +2 -2
- package/apps/web/scripts/build.mjs +23 -16
- package/apps/web/src/build-env.ts +1 -1
- package/apps/web/src/config-schema.ts +6 -6
- package/apps/web/tests/build-smoke.test.ts +14 -14
- package/apps/web/tests/config-schema.test.ts +1 -1
- package/docs/AWS-Deployment.md +21 -8
- package/docs/Cloudflare-Deployment-Guide.md +22 -6
- package/docs/PlanExtensions.md +113 -3
- package/docs/Release-Process.md +23 -13
- package/docs/Services.md +546 -0
- package/docs/WebClientGuide.md +32 -31
- package/package.json +2 -2
- package/packages/aws-adapter/package.json +1 -1
- package/packages/aws-adapter/src/aws-runtime.ts +5 -0
- package/packages/aws-adapter/src/cdk-table-defs.ts +6 -0
- package/packages/aws-adapter/src/config-loader.ts +11 -0
- package/packages/aws-adapter/src/connection-counter.ts +89 -0
- package/packages/aws-adapter/src/dynamo-services-store.ts +649 -0
- package/packages/aws-adapter/src/handlers/connect.ts +55 -51
- package/packages/aws-adapter/src/handlers/default.ts +36 -4
- package/packages/aws-adapter/src/handlers/index.ts +15 -0
- package/packages/aws-adapter/src/handlers/nlb-stream.ts +15 -0
- package/packages/aws-adapter/src/handlers/sweeper.ts +5 -1
- package/packages/aws-adapter/src/index.ts +4 -0
- package/packages/aws-adapter/src/stats.ts +6 -1
- package/packages/aws-adapter/src/tables.ts +34 -4
- package/packages/aws-adapter/tests/aws-harness.ts +3 -0
- package/packages/aws-adapter/tests/config-loader.test.ts +8 -0
- package/packages/aws-adapter/tests/connect.test.ts +158 -32
- package/packages/aws-adapter/tests/connection-counter.test.ts +127 -0
- package/packages/aws-adapter/tests/dynamo-services-store-dynamo.test.ts +183 -0
- package/packages/aws-adapter/tests/dynamo-services-store-unit.test.ts +568 -0
- package/packages/aws-adapter/tests/handlers.test.ts +105 -3
- package/packages/aws-adapter/tests/tables.test.ts +6 -1
- package/packages/cf-adapter/package.json +1 -1
- package/packages/cf-adapter/src/config-loader.ts +11 -0
- package/packages/cf-adapter/src/connection-do.ts +112 -2
- package/packages/cf-adapter/src/d1-services-store.ts +703 -0
- package/packages/cf-adapter/src/env.ts +8 -0
- package/packages/cf-adapter/src/index.ts +5 -0
- package/packages/cf-adapter/tests/config-loader.test.ts +19 -0
- package/packages/cf-adapter/tests/connection-do-nickserv-d1.test.ts +128 -0
- package/packages/cf-adapter/tests/connection-do.test.ts +150 -2
- package/packages/cf-adapter/tests/d1-services-store.test.ts +582 -0
- package/packages/cf-adapter/tests/serialize.test.ts +1 -0
- package/packages/in-memory-runtime/package.json +1 -1
- package/packages/irc-core/package.json +1 -1
- package/packages/irc-core/scripts/generate-build-info.mjs +26 -5
- package/packages/irc-core/src/commands/account-auth.ts +172 -0
- package/packages/irc-core/src/commands/chanserv.ts +882 -0
- package/packages/irc-core/src/commands/hostserv.ts +487 -0
- package/packages/irc-core/src/commands/index.ts +12 -0
- package/packages/irc-core/src/commands/join.ts +164 -8
- package/packages/irc-core/src/commands/markread.ts +202 -0
- package/packages/irc-core/src/commands/memoserv.ts +319 -0
- package/packages/irc-core/src/commands/mode.ts +96 -4
- package/packages/irc-core/src/commands/nickserv.ts +390 -0
- package/packages/irc-core/src/commands/oper.ts +18 -1
- package/packages/irc-core/src/commands/operserv.ts +346 -0
- package/packages/irc-core/src/commands/pre-away.ts +3 -1
- package/packages/irc-core/src/commands/privmsg.ts +42 -0
- package/packages/irc-core/src/commands/read-marker.ts +8 -8
- package/packages/irc-core/src/commands/registration.ts +61 -6
- package/packages/irc-core/src/commands/sasl.ts +18 -49
- package/packages/irc-core/src/commands/tagmsg.ts +41 -6
- package/packages/irc-core/src/commands/topic.ts +37 -0
- package/packages/irc-core/src/config.ts +36 -5
- package/packages/irc-core/src/effects.ts +56 -1
- package/packages/irc-core/src/ports.ts +1653 -84
- package/packages/irc-core/src/protocol/numerics.ts +8 -0
- package/packages/irc-core/src/state/channel.ts +21 -1
- package/packages/irc-core/src/state/connection.ts +25 -1
- package/packages/irc-core/src/types.ts +48 -12
- package/packages/irc-core/tests/commands/chanserv.test.ts +1668 -0
- package/packages/irc-core/tests/commands/chathistory.test.ts +6 -0
- package/packages/irc-core/tests/commands/hostserv.test.ts +935 -0
- package/packages/irc-core/tests/commands/join.test.ts +393 -1
- package/packages/irc-core/tests/commands/markread.test.ts +361 -0
- package/packages/irc-core/tests/commands/memoserv.test.ts +654 -0
- package/packages/irc-core/tests/commands/mode.test.ts +381 -2
- package/packages/irc-core/tests/commands/nickserv.test.ts +807 -0
- package/packages/irc-core/tests/commands/oper.test.ts +13 -0
- package/packages/irc-core/tests/commands/operserv.test.ts +656 -0
- package/packages/irc-core/tests/commands/privmsg.test.ts +147 -0
- package/packages/irc-core/tests/commands/read-marker.test.ts +28 -28
- package/packages/irc-core/tests/commands/registration.test.ts +788 -14
- package/packages/irc-core/tests/commands/sasl.test.ts +185 -12
- package/packages/irc-core/tests/commands/server-info.test.ts +9 -5
- package/packages/irc-core/tests/commands/tagmsg.test.ts +73 -33
- package/packages/irc-core/tests/commands/topic.test.ts +94 -2
- package/packages/irc-core/tests/commands/unified-account.test.ts +416 -0
- package/packages/irc-core/tests/config.test.ts +49 -5
- package/packages/irc-core/tests/effects.test.ts +19 -0
- package/packages/irc-core/tests/message-store.test.ts +63 -0
- package/packages/irc-core/tests/persistent-services-store.test.ts +582 -0
- package/packages/irc-core/tests/services-store.test.ts +1289 -0
- package/packages/irc-core/tests/state/channel.test.ts +3 -0
- package/packages/irc-server/package.json +1 -1
- package/packages/irc-server/src/actor.ts +71 -16
- package/packages/irc-server/src/dispatch.ts +94 -7
- package/packages/irc-server/src/routing.ts +19 -0
- package/packages/irc-server/tests/actor.test.ts +623 -12
- package/packages/irc-server/tests/dispatch.test.ts +270 -2
- package/packages/irc-server/tests/routing.test.ts +6 -0
- package/packages/irc-test-support/package.json +1 -1
- package/packages/irc-test-support/src/in-memory-harness.ts +29 -3
- package/packages/irc-test-support/src/index.ts +1 -0
- package/packages/irc-test-support/tests/in-memory-harness.test.ts +32 -0
- package/tools/ci-hardening/package.json +1 -1
- package/tools/load-test/package.json +1 -1
- package/tools/tcp-ws-forwarder/package.json +1 -1
- package/tools/tcp-ws-forwarder/tests/forwarder.test.ts +2 -2
- package/apps/cf-worker/tests/fixtures/web-dist/app/index.html +0 -18
- package/packages/irc-core/tests/read-marker-store.test.ts +0 -108
|
@@ -202,13 +202,26 @@ export const tagmsgChannelReducer: Reducer<ChannelState> = (state, msg, ctx) =>
|
|
|
202
202
|
// this channel. Persist the marker (advances the connection's in-memory
|
|
203
203
|
// marker too); a valueless tag carries no msgid and is dropped here. The
|
|
204
204
|
// TAGMSG still fans out below so the user's other connections learn it.
|
|
205
|
-
|
|
205
|
+
const isReadMarker = isReadMarkerTagmsg(msg.tags);
|
|
206
|
+
if (isReadMarker) {
|
|
206
207
|
const msgid = readMarkerMsgid(msg.tags);
|
|
207
208
|
if (msgid !== undefined) {
|
|
208
209
|
persistReadMarker(ctx, state.nameLower, msgid);
|
|
209
210
|
}
|
|
210
211
|
}
|
|
211
212
|
|
|
213
|
+
// IRCv3 draft/read-marker spec compliance: a read marker is private to
|
|
214
|
+
// the originator's account and MUST NOT be disclosed to other users. The
|
|
215
|
+
// mark TAGMSG fans out ONLY to the originator's own account (account-
|
|
216
|
+
// scoped broadcast); dispatch restricts the recipient set to same-account
|
|
217
|
+
// channel members. An unidentified originator has no account to share the
|
|
218
|
+
// mark with, so the mark stays session-local — no fanout at all (the
|
|
219
|
+
// originator's own client still observes its mark via echo-message below).
|
|
220
|
+
// Every other TAGMSG (typing, generic) keeps the channel-wide fanout.
|
|
221
|
+
const originAccount = ctx.connection.account;
|
|
222
|
+
const suppressFanout = isReadMarker && originAccount === undefined;
|
|
223
|
+
const accountFilter = isReadMarker ? originAccount : undefined;
|
|
224
|
+
|
|
212
225
|
// Broadcast the tag-bearing line to message-tags-enabled members only.
|
|
213
226
|
// When the TAGMSG carries `+draft/typing` or `+draft/read-marker`, the
|
|
214
227
|
// audience widens to also include members that announced the matching
|
|
@@ -217,11 +230,33 @@ export const tagmsgChannelReducer: Reducer<ChannelState> = (state, msg, ctx) =>
|
|
|
217
230
|
// `caps` so dispatch applies OR semantics per recipient.
|
|
218
231
|
const tagPrefix = serializeTags(msg.tags);
|
|
219
232
|
const line: RawLine = { text: `${tagPrefix}:${hostmask} TAGMSG ${state.name}` };
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
233
|
+
if (!suppressFanout) {
|
|
234
|
+
const widenCaps = widenAudienceCaps(msg.tags);
|
|
235
|
+
if (widenCaps !== undefined) {
|
|
236
|
+
effects.push(
|
|
237
|
+
Effect.broadcast(
|
|
238
|
+
state.name,
|
|
239
|
+
[line],
|
|
240
|
+
ctx.connId,
|
|
241
|
+
undefined,
|
|
242
|
+
undefined,
|
|
243
|
+
widenCaps,
|
|
244
|
+
accountFilter,
|
|
245
|
+
),
|
|
246
|
+
);
|
|
247
|
+
} else {
|
|
248
|
+
effects.push(
|
|
249
|
+
Effect.broadcast(
|
|
250
|
+
state.name,
|
|
251
|
+
[line],
|
|
252
|
+
ctx.connId,
|
|
253
|
+
MESSAGE_TAGS_CAP,
|
|
254
|
+
undefined,
|
|
255
|
+
undefined,
|
|
256
|
+
accountFilter,
|
|
257
|
+
),
|
|
258
|
+
);
|
|
259
|
+
}
|
|
225
260
|
}
|
|
226
261
|
|
|
227
262
|
// IRCv3 echo-message: echo the same line back to the sender, after
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
import { Effect } from '../effects.js';
|
|
22
22
|
import type { Effect as EffectType, RawLine } from '../effects.js';
|
|
23
|
+
import type { PersistedTopic } from '../ports.js';
|
|
23
24
|
import { Numerics } from '../protocol/numerics.js';
|
|
24
25
|
import type { ChannelState, ChannelTopic } from '../state/channel.js';
|
|
25
26
|
import { hostmaskOf } from '../state/connection.js';
|
|
@@ -121,6 +122,10 @@ export const topicReducer: Reducer<ChannelState> = (state, msg, ctx) => {
|
|
|
121
122
|
// path that persists the change, so subsequent reads by other
|
|
122
123
|
// connections observe the cleared topic.
|
|
123
124
|
effects.push(Effect.applyChannelDelta(state.name, { topic: null }));
|
|
125
|
+
// ChanServ KEEPTOPIC: clear the persisted snapshot when the channel has
|
|
126
|
+
// KEEPTOPIC enabled, so a subsequent empty-recreate does not restore a
|
|
127
|
+
// stale topic.
|
|
128
|
+
persistKeepTopic(ctx, state.nameLower, undefined);
|
|
124
129
|
} else {
|
|
125
130
|
const topic: ChannelTopic = {
|
|
126
131
|
text: truncated,
|
|
@@ -130,6 +135,9 @@ export const topicReducer: Reducer<ChannelState> = (state, msg, ctx) => {
|
|
|
130
135
|
state.topic = topic;
|
|
131
136
|
// Mirror the topic set to the channel authority (see comment above).
|
|
132
137
|
effects.push(Effect.applyChannelDelta(state.name, { topic }));
|
|
138
|
+
// ChanServ KEEPTOPIC: persist the snapshot when the channel has
|
|
139
|
+
// KEEPTOPIC enabled, so a subsequent empty-recreate restores it.
|
|
140
|
+
persistKeepTopic(ctx, state.nameLower, topic);
|
|
133
141
|
}
|
|
134
142
|
|
|
135
143
|
const hostmask = callerHostmask(ctx.connection);
|
|
@@ -167,3 +175,32 @@ function readTopic(
|
|
|
167
175
|
);
|
|
168
176
|
return { state, effects };
|
|
169
177
|
}
|
|
178
|
+
|
|
179
|
+
// ============================================================================
|
|
180
|
+
// ChanServ KEEPTOPIC persistence
|
|
181
|
+
// ============================================================================
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Persists the topic snapshot for a ChanServ-registered channel with
|
|
185
|
+
* KEEPTOPIC enabled. Called by the topic reducer on every topic change
|
|
186
|
+
* (set or clear) so a subsequent empty-recreate can restore the snapshot.
|
|
187
|
+
*
|
|
188
|
+
* No-op when:
|
|
189
|
+
* - no services store is bound,
|
|
190
|
+
* - the channel is not registered,
|
|
191
|
+
* - KEEPTOPIC is off.
|
|
192
|
+
*
|
|
193
|
+
* `topic === undefined` clears the persisted snapshot; a {@link ChannelTopic}
|
|
194
|
+
* replaces it.
|
|
195
|
+
*/
|
|
196
|
+
function persistKeepTopic(ctx: Ctx, nameLower: string, topic: ChannelTopic | undefined): void {
|
|
197
|
+
const services = ctx.services;
|
|
198
|
+
if (services === undefined) return;
|
|
199
|
+
const rec = services.getChannel(nameLower);
|
|
200
|
+
if (rec === undefined || !rec.keepTopic) return;
|
|
201
|
+
const persisted: PersistedTopic | undefined =
|
|
202
|
+
topic === undefined
|
|
203
|
+
? undefined
|
|
204
|
+
: { text: topic.text, setter: topic.setter, setAt: topic.setAt };
|
|
205
|
+
services.setChannelTopic(nameLower, persisted);
|
|
206
|
+
}
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import { z } from 'zod';
|
|
20
|
-
import { BUILD_DATE } from './build-info.js';
|
|
20
|
+
import { BUILD_DATE, PACKAGE_VERSION } from './build-info.js';
|
|
21
21
|
import { DEFAULT_MULTILINE_MAX_BYTES } from './caps/capabilities.js';
|
|
22
22
|
|
|
23
23
|
/**
|
|
@@ -144,11 +144,14 @@ export const DEFAULT_FLOOD_CONTROL_CONFIG: {
|
|
|
144
144
|
|
|
145
145
|
/**
|
|
146
146
|
* Default server version surfaced in `002`/`004`/`351`/`371` when a deployment
|
|
147
|
-
* does not supply one.
|
|
148
|
-
*
|
|
149
|
-
* knob
|
|
147
|
+
* does not supply one. Sourced from `irc-core/package.json` at build time via
|
|
148
|
+
* `scripts/generate-build-info.mjs`, so a deployment that omits the
|
|
149
|
+
* `serverVersion` knob advertises the version of the package it was shipped
|
|
150
|
+
* with — no manual sync required. Adapters may still inject a deploy-time
|
|
151
|
+
* version via the `serverVersion` config knob (see the per-adapter config
|
|
152
|
+
* loaders).
|
|
150
153
|
*/
|
|
151
|
-
export const DEFAULT_SERVER_VERSION =
|
|
154
|
+
export const DEFAULT_SERVER_VERSION: string = PACKAGE_VERSION;
|
|
152
155
|
|
|
153
156
|
/**
|
|
154
157
|
* Default "created" text for `003 RPL_CREATED` when a deployment does not
|
|
@@ -162,6 +165,14 @@ export const DEFAULT_SERVER_VERSION = '0.3.0';
|
|
|
162
165
|
*/
|
|
163
166
|
export const DEFAULT_CREATED_TEXT: string = BUILD_DATE;
|
|
164
167
|
|
|
168
|
+
/**
|
|
169
|
+
* Default grace period (ms) NickServ applies before force-disconnecting a
|
|
170
|
+
* client using a `ghost`-enforced registered nick without identifying.
|
|
171
|
+
* Matches the Atheme/Anope convention (~30s); overridable per deployment
|
|
172
|
+
* via `ServerConfig.nickEnforceGraceMs`.
|
|
173
|
+
*/
|
|
174
|
+
export const DEFAULT_NICK_ENFORCE_GRACE_MS = 30_000;
|
|
175
|
+
|
|
165
176
|
/**
|
|
166
177
|
* The full server-config schema. Optional fields default to deployment-
|
|
167
178
|
* sensible values so a minimal `{ serverName, networkName }` config is
|
|
@@ -337,6 +348,26 @@ export const ServerConfigSchema = z.object({
|
|
|
337
348
|
* nicks make them meaningless.
|
|
338
349
|
*/
|
|
339
350
|
servicesEnabled: z.boolean().optional(),
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Grace period (ms) NickServ applies before force-disconnecting a client
|
|
354
|
+
* using a `ghost`-enforced registered nick without identifying. See
|
|
355
|
+
* `ServerConfig.nickEnforceGraceMs`. `0` disables the grace (ghost
|
|
356
|
+
* behaves like kill). Omit for the 30s default.
|
|
357
|
+
*/
|
|
358
|
+
nickEnforceGraceMs: z.number().int().nonnegative().optional(),
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* HostServ approval mode for `REQUEST <vhost>`. `true` (the default)
|
|
362
|
+
* preserves the legacy auto-approve behaviour — the requested vhost is
|
|
363
|
+
* recorded against the account immediately (no oper review). `false`
|
|
364
|
+
* switches HostServ into oper-queue mode: `REQUEST` records a pending
|
|
365
|
+
* request that an oper must `APPROVE` (or `REJECT`) via HostServ. The
|
|
366
|
+
* queue + the `APPROVE` / `REJECT` / `LIST` (oper-only) commands are
|
|
367
|
+
* available in either mode, but only `false` routes `REQUEST` through
|
|
368
|
+
* them.
|
|
369
|
+
*/
|
|
370
|
+
hostservAutoApproveVhosts: z.boolean().default(false),
|
|
340
371
|
});
|
|
341
372
|
|
|
342
373
|
/** Input type: what adapters supply (fields with defaults may be omitted). */
|
|
@@ -55,6 +55,17 @@ export interface BroadcastEffect {
|
|
|
55
55
|
* path.
|
|
56
56
|
*/
|
|
57
57
|
caps?: readonly string[];
|
|
58
|
+
/**
|
|
59
|
+
* Account-scoped recipient filter (IRCv3 `draft/read-marker` privacy).
|
|
60
|
+
* When set, dispatch restricts the recipient set to channel members
|
|
61
|
+
* authenticated as this account — a read marker is private to the
|
|
62
|
+
* originator's own account and MUST NOT be disclosed to other users.
|
|
63
|
+
* Comparison is case-insensitive (RFC 1459 fold). Recipients still must
|
|
64
|
+
* satisfy the {@link cap} / {@link caps} filter; the {@link except}
|
|
65
|
+
* originator skip still applies. Used only by the read-marker mark
|
|
66
|
+
* TAGMSG path; every other broadcast leaves this unset (channel-wide).
|
|
67
|
+
*/
|
|
68
|
+
account?: string;
|
|
58
69
|
}
|
|
59
70
|
|
|
60
71
|
export interface DisconnectEffect {
|
|
@@ -121,6 +132,39 @@ export interface BroadcastWallopsEffect {
|
|
|
121
132
|
except?: ConnId;
|
|
122
133
|
}
|
|
123
134
|
|
|
135
|
+
/**
|
|
136
|
+
* NickServ nick-enforcement directive.
|
|
137
|
+
*
|
|
138
|
+
* Emitted by the NICK path when a client takes a registered nick they are
|
|
139
|
+
* not identified as, and the registered account's
|
|
140
|
+
* {@link NickEnforcePolicy} is `ghost` or `kill`. The actor layer (via
|
|
141
|
+
* `dispatch`) interprets the policy:
|
|
142
|
+
*
|
|
143
|
+
* - `none` — never emitted (the reducer sends the warning NOTICE only).
|
|
144
|
+
* - `kill` — `disconnect("Nick enforced by NickServ")` immediately.
|
|
145
|
+
* - `ghost` — schedule the same disconnect after {@link EnforceNickEffect.graceMs};
|
|
146
|
+
* when `graceMs === 0` the disconnect is immediate (matches `kill`).
|
|
147
|
+
*
|
|
148
|
+
* The grace duration is stamped by the reducer from the deployment's
|
|
149
|
+
* `nickEnforceGraceMs` config so `dispatch` stays free of clock access and
|
|
150
|
+
* the in-memory tests stay deterministic (the scheduler is injectable via
|
|
151
|
+
* {@link DispatchOptions.scheduler}).
|
|
152
|
+
*/
|
|
153
|
+
export interface EnforceNickEffect {
|
|
154
|
+
tag: 'EnforceNick';
|
|
155
|
+
/** Connection using the enforced nick. */
|
|
156
|
+
conn: ConnId;
|
|
157
|
+
/** Display spelling of the enforced nick. */
|
|
158
|
+
nick: Nick;
|
|
159
|
+
/** Per-account enforcement policy. */
|
|
160
|
+
policy: import('./ports.js').NickEnforcePolicy;
|
|
161
|
+
/**
|
|
162
|
+
* Grace period in ms before the disconnect fires (`ghost` only).
|
|
163
|
+
* `0` for `kill` and for `ghost` when the deployment disables the grace.
|
|
164
|
+
*/
|
|
165
|
+
graceMs: number;
|
|
166
|
+
}
|
|
167
|
+
|
|
124
168
|
/** Discriminated union of every effect the dispatch interpreter knows. */
|
|
125
169
|
export type Effect =
|
|
126
170
|
| SendEffect
|
|
@@ -131,7 +175,8 @@ export type Effect =
|
|
|
131
175
|
| ReleaseNickEffect
|
|
132
176
|
| ApplyChannelDeltaEffect
|
|
133
177
|
| SendToNickEffect
|
|
134
|
-
| BroadcastWallopsEffect
|
|
178
|
+
| BroadcastWallopsEffect
|
|
179
|
+
| EnforceNickEffect;
|
|
135
180
|
|
|
136
181
|
/** Literal string tag of every {@link Effect} variant. */
|
|
137
182
|
export type EffectTag = Effect['tag'];
|
|
@@ -163,12 +208,14 @@ export const Effect = {
|
|
|
163
208
|
cap?: string,
|
|
164
209
|
capLines?: RawLine[],
|
|
165
210
|
caps?: readonly string[],
|
|
211
|
+
account?: string,
|
|
166
212
|
): Effect {
|
|
167
213
|
const e: BroadcastEffect = { tag: 'Broadcast', chan, lines };
|
|
168
214
|
if (except !== undefined) e.except = except;
|
|
169
215
|
if (cap !== undefined) e.cap = cap;
|
|
170
216
|
if (capLines !== undefined) e.capLines = capLines;
|
|
171
217
|
if (caps !== undefined) e.caps = caps;
|
|
218
|
+
if (account !== undefined) e.account = account;
|
|
172
219
|
return e;
|
|
173
220
|
},
|
|
174
221
|
disconnect(conn: ConnId, reason?: string): Effect {
|
|
@@ -198,4 +245,12 @@ export const Effect = {
|
|
|
198
245
|
if (except !== undefined) e.except = except;
|
|
199
246
|
return e;
|
|
200
247
|
},
|
|
248
|
+
enforceNick(
|
|
249
|
+
conn: ConnId,
|
|
250
|
+
nick: Nick,
|
|
251
|
+
policy: import('./ports.js').NickEnforcePolicy,
|
|
252
|
+
graceMs: number,
|
|
253
|
+
): Effect {
|
|
254
|
+
return { tag: 'EnforceNick', conn, nick, policy, graceMs };
|
|
255
|
+
},
|
|
201
256
|
} as const;
|