glassframe-protocol 1.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/CHANGELOG.md ADDED
@@ -0,0 +1,197 @@
1
+ # Changelog
2
+
3
+ All notable changes to GlassFrame Protocol are logged here. This library
4
+ follows semantic versioning (MAJOR.MINOR.PATCH). Runtime version metadata
5
+ lives in `src/core/VersionInfo.js` (`VersionInfo.info()` /
6
+ `VersionInfo.banner()`), so code can read the current version without
7
+ parsing this file.
8
+
9
+ # Changelog
10
+
11
+ All notable changes to GlassFrame Protocol are logged here. This library
12
+ follows semantic versioning (MAJOR.MINOR.PATCH). Runtime version metadata
13
+ lives in `src/core/VersionInfo.js` (`VersionInfo.info()` /
14
+ `VersionInfo.banner()`), so code can read the current version without
15
+ parsing this file.
16
+
17
+ ## [1.2.0] - 2026-07-31
18
+
19
+ Packaging and licensing changes to make this publishable to npm. No
20
+ functional/runtime changes to any layer, engine, or command from 1.1.0.
21
+
22
+ ### Added
23
+
24
+ - `GETTING_STARTED.md` - onboarding guide for adding GlassFrame to a bot you
25
+ already have running (this is the file to hand someone alongside the
26
+ package).
27
+ - `scripts/build.js` + `npm run build` - produces `dist/`, the folder that
28
+ actually gets published (see `docs/PUBLISHING.md`). Uses `terser` for
29
+ real minification if it's installed as a devDependency, otherwise copies
30
+ files through unmodified rather than risking a hand-rolled comment
31
+ stripper - several files contain string literals with `//` in them (the
32
+ Groq endpoint URL, for one), which a naive regex-based stripper would
33
+ corrupt.
34
+ - `docs/PUBLISHING.md` - step-by-step npm publishing (same steps on Termux,
35
+ Windows, and Linux), including what `"files"` in `package.json` does and
36
+ does not upload.
37
+ - `.gitignore` for `node_modules/` and the generated `dist/`.
38
+
39
+ ### Changed
40
+
41
+ - **License**: replaced the MIT license with a custom Limited Use License
42
+ (see `LICENSE`) - grants installing and using the package in your own bot
43
+ (personal or commercial), and withholds copying/modifying/redistributing
44
+ the source or reselling the library itself. This is the real mechanism
45
+ for restricting reuse; a plain `npm install`-able package cannot be made
46
+ technically unreadable once it's on someone's disk, since Node has to
47
+ parse the JS to run it. Not legal advice - see the note at the top of
48
+ `LICENSE`.
49
+ - `package.json`: `main` now points at `dist/index.js`; added `files`
50
+ (whitelists what `npm publish` actually uploads - `src/` and the root
51
+ `config.js`/`index.js` are deliberately excluded), `prepublishOnly` (so
52
+ `dist/` can't go stale at publish time), `publishConfig.access: "public"`,
53
+ and placeholder `author`/`repository`/`homepage`/`bugs` fields to fill in.
54
+
55
+ ## [1.1.0] - 2026-07-31
56
+
57
+ Adds a batch of security extensions, a performance layer, and faster
58
+ processing under load - no breaking changes to the 1.0.0 API.
59
+
60
+ ### Added
61
+
62
+ - `PhishingDatabase` (`src/security/PhishingDatabase.js`) - replaces the
63
+ inline link regex in Basic Security with a dedicated, server-editable
64
+ module: a live blocklist (`!gf phishing add/remove/list`) plus
65
+ general-purpose heuristics (raw-IP links, punycode/homograph domains,
66
+ digit-for-letter brand look-alikes, known shorteners). Ships with an
67
+ empty seed list by design - a hardcoded "known bad domains" list goes
68
+ stale immediately and risks flagging an innocent domain on unverified
69
+ information.
70
+ - AntiNuke now watches three more attack surfaces:
71
+ - **Emoji/sticker bursts** - mass emoji or sticker deletion/creation is
72
+ tracked the same way channel/role bursts already were.
73
+ - **Invite abuse** - an unrestricted invite (no expiry, no use limit)
74
+ created by anyone *other than* recognized trusted staff is flagged;
75
+ the same pattern from real staff is left alone, so this doesn't turn
76
+ into noise on a server that already uses a permanent invite link.
77
+ - **Webhook message flooding** - a webhook created moments ago that then
78
+ sends a burst of messages is deleted immediately and traced back to
79
+ whoever created it. This closes a real gap: webhook messages carry no
80
+ guild member, so they were invisible to every other layer's per-member
81
+ checks.
82
+ - AntiRaid now also runs **creation-time cluster correlation**
83
+ (`AntiRaidLayer._clusterScore`): a bulk-registered account farm that
84
+ trickles in slowly enough to dodge the join-rate counter is still caught
85
+ by noticing that several recent joiners' accounts were all created
86
+ within the same narrow window.
87
+ - `EventQueue` (`src/core/EventQueue.js`) - a bounded-concurrency task
88
+ queue. Every Discord mutation `PunishmentEngine` performs and every
89
+ outbound Groq request now runs through one of two queues
90
+ (`frame.actionQueue`, `frame.aiQueue`) instead of firing unbounded, so a
91
+ burst (raid, nuke, wave of gray-zone messages) can't trip a rate limit by
92
+ hammering it all at once. See `docs/PERFORMANCE.md`.
93
+ - `PerformanceMonitor` (`src/core/PerformanceMonitor.js`) and
94
+ `frame.getMetrics()` / `!gf metrics` - lightweight in-process event
95
+ counts and rolling latency averages, plus every cache's stats, in one
96
+ snapshot. No external dependency, no network call.
97
+ - Command cooldown (`performance.commandCooldownMs`, default 3s) - prefix
98
+ commands are now throttled per user per guild.
99
+ - `docs/PERFORMANCE.md`.
100
+
101
+ ### Changed
102
+
103
+ - `GroqClient.classify()` split into a thin queued/cached front end and an
104
+ internal `_request()` - the per-request timeout clock now starts only
105
+ once a request actually leaves the queue, so a busy moment can no longer
106
+ cause a false "AI didn't respond in time".
107
+ - `PunishmentEngine`: an open case can now **escalate** its action if
108
+ continued signals push the tier past what it was last acted on at (e.g.
109
+ log -> timeout -> kick -> ban within the same incident), instead of
110
+ freezing at whatever action was first decided for the entire debounce
111
+ window. Never downgrades, and a trusted member's ceiling
112
+ (quarantine/alert) is still respected on every re-evaluation.
113
+
114
+ ## [1.0.0] - 2026-07-29
115
+
116
+ Initial release of **GlassFrame Protocol** - a full architectural rebuild of
117
+ the previous `guardian-security-module`, renamed and restructured as a
118
+ standalone library rather than a bundle of bot-side modules.
119
+
120
+ ### Added
121
+
122
+ - Layered architecture (`Layer` base class): AntiRaid, AntiNuke, Basic
123
+ Security, and AI Moderation are now independently toggleable layers that
124
+ share one pipeline instead of four separate modules that each punished on
125
+ their own. `enable()`/`disable()` fully attach/detach a layer's listeners,
126
+ so a disabled layer does zero work.
127
+ - `ThreatEngine` - a shared, decaying per-member risk score that every layer
128
+ reports to, so scattered small flags across layers combine into one
129
+ picture instead of triggering separate, redundant reactions. Tiers
130
+ (none/low/medium/high/critical) drive the punishment ladder.
131
+ - `RoleAnalyzer` - role hierarchy checks (the protocol never attempts an
132
+ action it lacks permission for) and role **name** analysis: flags roles
133
+ whose name implies authority but hold no real permissions (impersonation
134
+ bait), and roles that quietly hold dangerous permissions under an
135
+ innocuous name. Exposed via the new `!gf scan` command and an automatic
136
+ audit the moment AntiNuke is armed.
137
+ - `PunishmentEngine` - the single place that actually bans/kicks/times out/
138
+ quarantines a member. Consults role trust level before acting (a real
139
+ admin is never auto-banned - it's flagged for human review instead), and
140
+ debounces repeat signals against the same member so one incident produces
141
+ one action and one log line, not a stream of them.
142
+ - `AIModerationLayer` + `GroqClient` - optional Groq-powered second opinion
143
+ for messages that land in the gray zone between local NLP's clean/dirty
144
+ thresholds. Supports an API key pool with automatic per-key cooldown on
145
+ rate-limit responses, so one exhausted key doesn't take moderation down.
146
+ Verdicts are cached briefly so repeated/near-identical messages don't each
147
+ cost a fresh call. Disabled by default - supply `aiModeration.apiKeys` to
148
+ turn it on.
149
+ - `SmartLogger` - merges near-duplicate log events inside a short window
150
+ into a single message with a running count instead of one message per
151
+ event, and enforces a minimum interval between sends per guild.
152
+ - 5-button control panel (`!gf panel`) - Activate/Deactivate AntiRaid, AI
153
+ Moderation, AntiNuke, and Basic Security individually, plus a fifth
154
+ "Full Protocol" button that arms or disarms all four together. Every
155
+ layer starts disabled until explicitly armed.
156
+ - Prefix-only command surface (`!gf panel|status|scan|whitelist|help`) - no
157
+ slash commands are registered by this library, by design.
158
+ - Dangerous permission-grant watchdog and identity-change watchdog inside
159
+ AntiNuke - a role quietly gaining Administrator, or the server's name/
160
+ icon/vanity URL changing, is flagged the moment it happens rather than
161
+ waiting for a repeat-offense threshold. A forensic role/channel snapshot
162
+ is captured the moment any AntiNuke threshold trips.
163
+ - Alt-account composite scoring in AntiRaid (account age + username entropy
164
+ + missing avatar) alongside the existing join-velocity lockdown.
165
+ - Link heuristics in Basic Security: raw-IP links, punycode domains, and
166
+ Discord look-alike domains.
167
+ - Pluggable state persistence (`MemoryStateStore` by default,
168
+ `JSONFileStateStore` for restart-safe layer state with zero extra
169
+ dependencies - no native modules, ARM64/Termux-friendly).
170
+ - `docs/CACHE_ARCHITECTURE.md` and `docs/PROTOCOL_LAYERS.md` - internal
171
+ architecture references for anyone extending the library.
172
+
173
+ ### Changed
174
+
175
+ - Renamed from `guardian-security-module` to `glassframe-protocol`.
176
+ Directory layout moved from a flat `modules/` + `utils/` split into
177
+ `src/core`, `src/layers`, `src/moderation`, `src/ai`, `src/logging`,
178
+ `src/ui`, and `src/commands`.
179
+ - All punishment decisions moved out of individual layers and into
180
+ `PunishmentEngine`; layers now report signals instead of calling
181
+ `.ban()` / `.kick()` / `.timeout()` directly.
182
+ - Components V2 output kept (no legacy `EmbedBuilder` anywhere) and
183
+ extended to support the control panel's button row and event-count
184
+ badges on aggregated log messages.
185
+
186
+ ### Fixed
187
+
188
+ - Anti-nuke's self-exemption check previously compared `executor.bot === false`
189
+ against the client's own ID, which could never be true for a bot account;
190
+ it now simply skips audit entries the client itself generated.
191
+
192
+ ## [0.x] - guardian-security-module (superseded)
193
+
194
+ The pre-GlassFrame history shipped as `guardian-security-module` v1.0.0:
195
+ local-NLP-only detection, flat `antiRaid.js` / `antiNuke.js` / `security.js`
196
+ modules, each acting immediately and independently with no shared scoring,
197
+ no role-name analysis, no AI layer, and no control panel.
@@ -0,0 +1,133 @@
1
+ # Getting Started
2
+
3
+ This is a library, not a bot - it has no login token of its own and does
4
+ nothing until you attach it to a discord.js `Client` you already have
5
+ running. This guide is written for that: you already have a working bot
6
+ and want to add GlassFrame Protocol to it.
7
+
8
+ If you're starting completely from scratch instead, `examples/basic-usage.js`
9
+ is a full minimal bot (client creation included) you can copy and run
10
+ directly.
11
+
12
+ ## Prerequisites
13
+
14
+ - An existing discord.js v14.16+ bot, already logging in successfully
15
+ - Node.js 18+ (GlassFrame's optional AI layer uses the global `fetch`)
16
+ - Your bot invited with these permissions: Manage Roles, Kick Members, Ban
17
+ Members, Manage Channels, Manage Webhooks, View Audit Log, Moderate
18
+ Members, Manage Messages
19
+ - These gateway intents enabled: `Guilds`, `GuildMembers`, `GuildMessages`,
20
+ `MessageContent`, `GuildModeration`
21
+
22
+ ## Step 1 - Place the folder
23
+
24
+ Put the `glassframe-protocol` folder anywhere inside your existing project,
25
+ for example:
26
+
27
+ ```
28
+ your-bot/
29
+ ├── index.js
30
+ ├── node_modules/
31
+ ├── package.json
32
+ └── libs/
33
+ └── glassframe-protocol/ <- this folder
34
+ ```
35
+
36
+ You do **not** need to run `npm install` inside it for discord.js
37
+ specifically. Node looks for `node_modules` starting at the file that's
38
+ doing the `require()` and walks upward through parent folders - since
39
+ `glassframe-protocol` is nested inside your project, it will find the
40
+ discord.js your bot already has installed. If your project somehow doesn't
41
+ have discord.js yet, run `npm install discord.js` at your project root as
42
+ normal.
43
+
44
+ ## Step 2 - Attach it to your client
45
+
46
+ In your main bot file, once your client is ready:
47
+
48
+ ```js
49
+ const GlassFrame = require("./libs/glassframe-protocol");
50
+
51
+ client.once("ready", () => {
52
+ const frame = new GlassFrame(client, {
53
+ // Required: tell GlassFrame where to send its logs.
54
+ getLogChannel: async (guild) =>
55
+ guild.channels.cache.find((c) => c.name === "security-logs") ?? null,
56
+
57
+ // Optional: which layers turn on immediately vs. stay off until
58
+ // someone arms them from the panel. Layers not listed here start OFF.
59
+ autoStart: ["basicSecurity", "antiRaid", "antiNuke"]
60
+ });
61
+
62
+ frame.on("warning", (w) => console.warn(`[GlassFrame:${w.layer}]`, w.message));
63
+ });
64
+ ```
65
+
66
+ This is the entire integration. You do not write a spam filter, a raid
67
+ detector, a command handler, or any punishment logic - constructing
68
+ `GlassFrame` attaches everything it needs to your existing `client`
69
+ internally. Nothing else in your bot's code has to change.
70
+
71
+ ## Step 3 - Make a log channel
72
+
73
+ Create a text channel (matching whatever `getLogChannel` looks for - the
74
+ example above uses one named `security-logs`) and make sure your bot can
75
+ see and send messages in it. Every alert, every punishment, every layer
76
+ toggle gets reported there through Components V2 messages.
77
+
78
+ ## Step 4 - Turn features on
79
+
80
+ Two ways, pick either or both:
81
+
82
+ - **Code**: list layer names in `autoStart` (see Step 2), or call
83
+ `frame.enableLayer("antiNuke")` / `frame.disableLayer("antiNuke")`
84
+ anywhere after construction.
85
+ - **In Discord**: an admin (Manage Server permission) sends `!gf panel` and
86
+ gets 5 buttons - Activate/Deactivate AntiRaid, AI Moderation, AntiNuke,
87
+ Basic Security, and Full Protocol (all four at once). This is the only
88
+ interface most server admins will ever need - no code, no slash commands.
89
+
90
+ ## Step 5 (optional) - AI Moderation
91
+
92
+ Off by default. To turn it on:
93
+
94
+ 1. Get one or more free API keys from console.groq.com
95
+ 2. Pass them in config:
96
+ ```js
97
+ const frame = new GlassFrame(client, {
98
+ getLogChannel: /* ... */,
99
+ config: {
100
+ aiModeration: { apiKeys: (process.env.GROQ_API_KEYS || "").split(",") }
101
+ }
102
+ });
103
+ ```
104
+ 3. Arm the layer (panel button, or add `"aiModeration"` to `autoStart`)
105
+
106
+ Multiple keys are rotated automatically, and any key that gets rate-limited
107
+ is benched temporarily rather than breaking moderation. It only calls out
108
+ to Groq for messages local detection scores as ambiguous - most messages
109
+ never leave the process.
110
+
111
+ ## Everyday use, once it's running
112
+
113
+ Nobody needs this guide again after setup. Server admins use:
114
+
115
+ | Command | Does |
116
+ |---|---|
117
+ | `!gf panel` | The 5-button control panel |
118
+ | `!gf status` | Which layers are active |
119
+ | `!gf scan` | Checks current roles for name/permission mismatches |
120
+ | `!gf metrics` | Performance and cache health |
121
+ | `!gf phishing add/remove/list <domain>` | Manage the link blocklist |
122
+ | `!gf whitelist add/remove <userId>` | Exempt a user from punitive action |
123
+ | `!gf help` | Lists all of the above |
124
+
125
+ ## Going deeper
126
+
127
+ - `README.md` - full feature overview
128
+ - `docs/PROTOCOL_LAYERS.md` - how a signal becomes an action
129
+ - `docs/CACHE_ARCHITECTURE.md` - every internal cache and its TTL
130
+ - `docs/PERFORMANCE.md` - the bounded-concurrency queues and `!gf metrics`
131
+ - `docs/COMMANDS.md` - full command/button reference
132
+ - `CHANGELOG.md` - version history
133
+ - `config.js` - every tunable threshold, all in one file
package/LICENSE ADDED
@@ -0,0 +1,56 @@
1
+ GlassFrame Protocol - Limited Use License
2
+ Copyright (c) 2026 GlassFrame Protocol
3
+
4
+ This is a custom, non-open-source license. It is not MIT, Apache, GPL, or
5
+ any OSI-approved license, and it is not legal advice - it is a starting
6
+ template. Have an actual lawyer review it before relying on it for
7
+ anything commercially significant; enforceability varies by jurisdiction,
8
+ and only a licensed attorney can tell you how well specific wording holds
9
+ up where you and your users live.
10
+
11
+ 1. GRANT OF USE
12
+ Permission is granted, free of charge, to any person obtaining a copy of
13
+ this software (the "Software") to install and use it, unmodified, as a
14
+ dependency inside their own Discord bot project - personal or
15
+ commercial - subject to the conditions below.
16
+
17
+ 2. RESTRICTIONS
18
+ Without prior written permission from the copyright holder, you may NOT:
19
+ a. Copy, extract, or redistribute the Software's source code on its own
20
+ (as opposed to using it as an installed dependency of your project).
21
+ b. Modify the Software and distribute or publish the modified version,
22
+ under this name or another.
23
+ c. Republish, mirror, or re-upload the Software (or a renamed/modified
24
+ copy of it) to npm or any other package registry.
25
+ d. Reverse-engineer, decompile, or disassemble the Software beyond what
26
+ your local law makes non-waivable.
27
+ e. Remove or alter this license, the copyright notice, or any
28
+ attribution notices contained in the Software.
29
+ f. Resell the Software itself as a standalone product (using it as a
30
+ component inside a bot you sell or host as a service is permitted;
31
+ selling the library itself, or a copy/fork of it, is not).
32
+
33
+ 3. ATTRIBUTION
34
+ Any bot or product that uses this Software should credit "GlassFrame
35
+ Protocol" somewhere reasonably discoverable (a credits command, a
36
+ footer, a README line) unless you have separate written permission to
37
+ omit it.
38
+
39
+ 4. NO WARRANTY
40
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
41
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
42
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
43
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
44
+ LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY ARISING FROM THE
45
+ SOFTWARE OR ITS USE, INCLUDING ANY ACTION TAKEN BY THE SOFTWARE AGAINST
46
+ A DISCORD SERVER OR ITS MEMBERS (bans, kicks, timeouts, role changes,
47
+ webhook deletions, or any other moderation action).
48
+
49
+ 5. TERMINATION
50
+ This license terminates automatically for anyone who violates Section 2;
51
+ they must stop using the Software and destroy any copies in their
52
+ possession.
53
+
54
+ To ask for permission beyond what's granted here (bulk redistribution,
55
+ white-labeling, a different license for a specific use case), contact the
56
+ copyright holder directly.
package/README.md ADDED
@@ -0,0 +1,145 @@
1
+ # GlassFrame Protocol
2
+
3
+ A layered, self-contained security engine for discord.js v14 bots. Four
4
+ independently-toggleable layers - AntiRaid, AntiNuke, Basic Security, and
5
+ Groq-powered AI Moderation - share one threat-scoring and punishment
6
+ pipeline instead of each reacting on its own, so the same member never gets
7
+ hit by four different modules for one incident, and a single soft flag
8
+ never turns into an auto-ban.
9
+
10
+ No slash commands - prefix commands only. No legacy `EmbedBuilder` - every
11
+ log message renders through Discord's Components V2 system. No emoji
12
+ anywhere in code or output.
13
+
14
+ ## Install
15
+
16
+ Copy the `glassframe-protocol` folder into your bot project, then:
17
+
18
+ ```
19
+ npm install
20
+ ```
21
+
22
+ Requires `discord.js` v14.16+ (Components V2 support and the
23
+ `guildAuditLogEntryCreate` event) and Node.js 18+ (global `fetch`, used only
24
+ by the optional AI layer).
25
+
26
+ ## Required intents
27
+
28
+ ```js
29
+ const { Client, GatewayIntentBits } = require("discord.js");
30
+
31
+ const client = new Client({
32
+ intents: [
33
+ GatewayIntentBits.Guilds,
34
+ GatewayIntentBits.GuildMembers,
35
+ GatewayIntentBits.GuildMessages,
36
+ GatewayIntentBits.MessageContent,
37
+ GatewayIntentBits.GuildModeration
38
+ ]
39
+ });
40
+ ```
41
+
42
+ ## Required bot permissions
43
+
44
+ Manage Roles, Kick Members, Ban Members, Manage Channels, Manage Webhooks,
45
+ View Audit Log, Moderate Members (timeout), Manage Messages. GlassFrame's
46
+ own role must sit above any role/member it needs to act on -
47
+ `RoleAnalyzer` checks this before every action instead of attempting and
48
+ failing.
49
+
50
+ ## Usage
51
+
52
+ ```js
53
+ const GlassFrame = require("glassframe-protocol");
54
+
55
+ client.once("ready", () => {
56
+ const frame = new GlassFrame(client, {
57
+ getLogChannel: async (guild) =>
58
+ guild.channels.cache.find((c) => c.name === "security-logs") ?? null,
59
+ whitelist: ["123456789012345678"],
60
+ autoStart: ["basicSecurity"], // layers not listed here start OFF until armed from the panel
61
+ config: {
62
+ antiRaid: { joinThreshold: 8 },
63
+ aiModeration: { apiKeys: [process.env.GROQ_KEY_1, process.env.GROQ_KEY_2].filter(Boolean) }
64
+ }
65
+ });
66
+
67
+ frame.on("warning", (w) => console.warn(`[GlassFrame:${w.layer}]`, w.message));
68
+ });
69
+
70
+ client.login(process.env.BOT_TOKEN);
71
+ ```
72
+
73
+ Send `!gf panel` in any channel (Manage Server permission required) to get
74
+ the 5-button control panel and arm layers from there instead of in code.
75
+
76
+ ## The four layers
77
+
78
+ - **Basic Security** - spam rate, duplicate flood, mention spam, local NLP
79
+ scam/phishing scoring, and link checks via `PhishingDatabase` (a
80
+ server-editable blocklist plus raw-IP/punycode/brand-look-alike/shortener
81
+ heuristics - `!gf phishing add/remove/list`).
82
+ - **AntiRaid** - join-velocity lockdown with automatic verification-level
83
+ raise/restore, a composite alt-account score (account age, username
84
+ entropy, missing avatar), and creation-time cluster correlation that
85
+ catches a raid trickling in too slowly to trip the rate counter.
86
+ - **AntiNuke** - audit-log burst detection across channels, roles, bans,
87
+ kicks, webhooks, emoji, and stickers per executor; a dangerous
88
+ permission-grant watchdog (catches a role quietly gaining Administrator
89
+ the moment it happens, with optional auto-revert); a server-identity
90
+ watchdog (name/icon/vanity URL changes); an invite-abuse watchdog
91
+ (unrestricted invites from non-staff); and webhook-flood containment
92
+ (deletes an abusive webhook and traces it back to its creator, since
93
+ webhook messages carry no guild member for other layers to see).
94
+ - **AI Moderation** (optional, off by default) - Groq-powered second opinion
95
+ for messages the local NLP scores as "gray zone": not clean, not clearly
96
+ over threshold. Supports a pool of API keys with automatic per-key
97
+ cooldown on rate limits. See `config.aiModeration` and
98
+ `docs/CACHE_ARCHITECTURE.md` for how verdicts get cached and keys rotated.
99
+
100
+ Every layer starts disabled. Nothing runs until you list it in
101
+ `autoStart`, call `frame.enableLayer(name)`, or arm it from the control
102
+ panel.
103
+
104
+ ## Performance under load
105
+
106
+ Every Discord mutation `PunishmentEngine` performs and every outbound Groq
107
+ request go through a bounded-concurrency queue (`frame.actionQueue` /
108
+ `frame.aiQueue`) instead of firing unbounded, so a burst can't trip a rate
109
+ limit by hammering it all at once. `frame.getMetrics()` / `!gf metrics`
110
+ gives you queue depth, cache stats, and average latency in one snapshot.
111
+ Full write-up in `docs/PERFORMANCE.md`.
112
+
113
+ ## How punishment works
114
+
115
+ Layers never ban/kick/timeout directly - they report a signal
116
+ (`{ layer, weight, reason }`) to a shared `ThreatEngine`, which keeps one
117
+ decaying risk score per member. `PunishmentEngine` turns that score into an
118
+ action, but only after `RoleAnalyzer` confirms the bot can actually act on
119
+ the member and checks their real trust level (a genuine admin is flagged
120
+ for human review, never auto-banned), and only if there isn't already an
121
+ open case for that member from a moment ago. Full write-up in
122
+ `docs/PROTOCOL_LAYERS.md`.
123
+
124
+ ## Docs
125
+
126
+ - `GETTING_STARTED.md` - adding GlassFrame to a bot you already have running.
127
+ - `docs/PROTOCOL_LAYERS.md` - full architecture: containment vs. punishment,
128
+ how a signal becomes an action, how to add a fifth layer.
129
+ - `docs/CACHE_ARCHITECTURE.md` - every cache in the library, its key shape,
130
+ its TTL, and how to turn on cache-level debug logging.
131
+ - `docs/PERFORMANCE.md` - the bounded-concurrency queues and internal
132
+ metrics collector, and what `!gf metrics` shows.
133
+ - `docs/COMMANDS.md` - the full prefix command reference and the control
134
+ panel's five buttons.
135
+ - `docs/PUBLISHING.md` - publishing this package to npm, and what actually
136
+ gets uploaded vs. stays local.
137
+ - `CHANGELOG.md` - version history.
138
+
139
+ ## Tuning
140
+
141
+ Every threshold lives in `config.js`. Start with the defaults, watch the
142
+ security log channel for a week, and adjust - a very active server needs
143
+ higher spam/mention thresholds than a quiet one. `frame.threatEngine` and
144
+ `frame.punishmentEngine` are both plain properties on the returned instance
145
+ if you want to inspect scores or open cases at runtime.
package/dist/config.js ADDED
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+
3
+ module.exports = {
4
+ // Prefix for all commands. This library never registers slash commands.
5
+ prefix: "!gf ",
6
+
7
+ // Documentation only - the actual channel resolution always goes through
8
+ // the required options.getLogChannel(guild) function you provide.
9
+ logChannelName: "security-logs",
10
+
11
+ roleAnalysis: {
12
+ // Role-name fragments (lowercased, substring match) that imply real authority.
13
+ protectedNames: [
14
+ "owner", "admin", "administrator", "moderator", "mod",
15
+ "staff", "discord staff", "security"
16
+ ],
17
+ // Permission names (PermissionsBitField.Flags keys) treated as "dangerous"
18
+ // when granted to a role - watched by AntiNuke's grant watchdog.
19
+ dangerousPermissions: [
20
+ "Administrator", "ManageGuild", "ManageRoles", "ManageWebhooks",
21
+ "BanMembers", "ManageChannels"
22
+ ],
23
+ // Permission names that mark a member as genuinely trusted staff.
24
+ trustPermissions: ["Administrator", "ManageGuild", "ManageRoles", "BanMembers", "KickMembers"],
25
+ // A role younger than this that already holds a dangerous permission is extra suspicious.
26
+ newRoleGraceMs: 1000 * 60 * 10
27
+ },
28
+
29
+ threatEngine: {
30
+ // Score halves every this-many ms of inactivity - stale flags fade instead of lingering forever.
31
+ decayHalfLifeMs: 1000 * 60 * 30,
32
+ tiers: { low: 20, medium: 45, high: 70, critical: 90 }
33
+ },
34
+
35
+ punishment: {
36
+ // While a case is open for a member, new signals merge into it instead of re-punishing/re-logging.
37
+ caseCooldownMs: 1000 * 30,
38
+ ladder: { low: "log", medium: "timeout", high: "kick", critical: "ban" },
39
+ timeoutDurationMs: 1000 * 60 * 10,
40
+ // Action used instead of kick/ban when the target holds a real trusted/protected role.
41
+ protectedTrustAction: "quarantine"
42
+ },
43
+
44
+ basicSecurity: {
45
+ spam: { windowMs: 6000, messageThreshold: 6, duplicateThreshold: 4 },
46
+ mentionSpam: { maxMentionsPerMessage: 8 },
47
+ nlp: { scamScoreThreshold: 0.62, phishingScoreThreshold: 0.55 },
48
+ // Seed domains for PhishingDatabase (src/security/PhishingDatabase.js).
49
+ // Empty by default - populate with what you actually see via
50
+ // `!gf phishing add <domain>` rather than shipping unverified blocklists.
51
+ linkGuard: { seedDomains: [] }
52
+ },
53
+
54
+ antiRaid: {
55
+ joinWindowMs: 10000,
56
+ joinThreshold: 6,
57
+ minAccountAgeMs: 1000 * 60 * 60 * 24 * 3,
58
+ usernameEntropyFloor: 2.6,
59
+ usernameEntropyCeiling: 4.6,
60
+ lockdownDurationMs: 1000 * 60 * 10,
61
+ altScoreThreshold: 55,
62
+ // Behavioral correlation: catches a raid that trickles in slowly enough
63
+ // to dodge the join-rate counter above, by noticing that several
64
+ // "unrelated" new joiners were actually all created within the same
65
+ // narrow window - a classic sign of a bulk-registered account farm.
66
+ cluster: {
67
+ windowMs: 1000 * 60 * 5,
68
+ minClusterSize: 4,
69
+ creationToleranceMs: 1000 * 60 * 2
70
+ }
71
+ },
72
+
73
+ antiNuke: {
74
+ windowMs: 15000,
75
+ thresholds: {
76
+ channelDelete: 3, channelCreate: 5, roleDelete: 3, roleCreate: 5,
77
+ memberBanAdd: 4, memberKick: 5, webhookCreate: 3, botAdd: 1, guildUpdate: 3,
78
+ emojiDelete: 5, emojiCreate: 8, stickerDelete: 3, stickerCreate: 5
79
+ },
80
+ watchDangerousGrants: true,
81
+ autoRevertDangerousGrants: false,
82
+ watchVanityChanges: true,
83
+ // A brand-new invite with no expiry and no use limit, created by anyone
84
+ // other than the owner, is worth a look the moment it's created.
85
+ watchInviteAbuse: true,
86
+ // A webhook that starts pushing a burst of messages within minutes of
87
+ // being created is a classic "nuke via webhook" pattern - this catches
88
+ // it even though the messages themselves look like normal messageCreate
89
+ // events. The offending webhook is deleted as immediate containment.
90
+ webhookAbuse: {
91
+ enabled: true,
92
+ messageThreshold: 8,
93
+ windowMs: 8000,
94
+ // How long after creation a webhook is still considered "recent" enough to watch.
95
+ watchPeriodMs: 1000 * 60 * 5
96
+ },
97
+ // Forensic role/channel snapshot retention, taken the moment a threshold trips.
98
+ snapshotTtlMs: 1000 * 60 * 60
99
+ },
100
+
101
+ aiModeration: {
102
+ // Empty by default - the layer stays idle until you supply at least one key.
103
+ apiKeys: [],
104
+ model: "llama-3.3-70b-versatile",
105
+ endpoint: "https://api.groq.com/openai/v1/chat/completions",
106
+ timeoutMs: 6000,
107
+ cacheTtlMs: 1000 * 60 * 5,
108
+ // A conservative self-imposed budget shared across the whole key pool, not Groq's own rate limit.
109
+ maxCallsPerMinute: 20,
110
+ // Messages whose local NLP score falls in this band get a second, AI-backed opinion.
111
+ grayZone: { min: 0.30, max: 0.62 }
112
+ },
113
+
114
+ logging: {
115
+ // Near-duplicate log events inside this window merge into one message with a running count.
116
+ aggregationWindowMs: 15000,
117
+ // Minimum time between sends to the same guild's log channel.
118
+ minSendIntervalMs: 1200
119
+ },
120
+
121
+ // Bounded-concurrency controls (src/core/EventQueue.js) so a burst - a raid,
122
+ // a nuke attempt, a wave of gray-zone messages - queues smoothly instead of
123
+ // firing every Discord/Groq call at once and tripping a rate limit right
124
+ // when speed matters most. See docs/PERFORMANCE.md.
125
+ performance: {
126
+ actionConcurrency: 4, // simultaneous ban/kick/timeout/quarantine calls
127
+ aiConcurrency: 3, // simultaneous outbound Groq requests
128
+ // Per-user, per-guild floor between prefix commands, so a doubled
129
+ // keypress can't spawn two control panels or send a command twice.
130
+ commandCooldownMs: 3000
131
+ },
132
+
133
+ cache: {
134
+ // Default for GlassFrame's debug flag - logs every cache SET/HIT/MISS/EXPIRE to the console.
135
+ // See docs/CACHE_ARCHITECTURE.md. Overridden by the `debug` constructor option if provided.
136
+ debug: false
137
+ }
138
+ };