Add the slopbot scaffold and discord.js dependency, unused
This commit is contained in:
@@ -47,6 +47,9 @@ before you stop.
|
|||||||
- Triggers come from trusted users only: one-to-one DMs and direct mentions.
|
- Triggers come from trusted users only: one-to-one DMs and direct mentions.
|
||||||
- Test with throwaway accounts and private test guilds only.
|
- Test with throwaway accounts and private test guilds only.
|
||||||
- Never commit `media-scrape/db/`, scrape databases, downloaded media, or the slopbot token.
|
- Never commit `media-scrape/db/`, scrape databases, downloaded media, or the slopbot token.
|
||||||
|
- Owner interjections become `TODO.md` items unless marked "add this now". Add the item, then
|
||||||
|
continue the current task.
|
||||||
|
- No sudo. Record apt or system-level installs in `TODO.md`; the owner runs them.
|
||||||
- Live send tests: only DMs to user **zzib** (`177117296140091393`).
|
- Live send tests: only DMs to user **zzib** (`177117296140091393`).
|
||||||
- Run `pnpm testTypes` and `pnpm lint` before you report done. Run `pnpm build` to compile.
|
- Run `pnpm testTypes` and `pnpm lint` before you report done. Run `pnpm build` to compile.
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -19,7 +19,9 @@ mobile draft at 390px.
|
|||||||
bridge for group DMs; one self-contained SQLite + media dir per scrape under `media-scrape/db/`
|
bridge for group DMs; one self-contained SQLite + media dir per scrape under `media-scrape/db/`
|
||||||
(gitignored); links indexed by default, downloads optional, third-party embeds never downloaded;
|
(gitignored); links indexed by default, downloads optional, third-party embeds never downloaded;
|
||||||
30 GiB default limit with a 90% warning and 5% no-delete overrun, usage bar and clean button in
|
30 GiB default limit with a 90% warning and 5% no-delete overrun, usage bar and clean button in
|
||||||
Settings → Bot; Media and Bot top-level tabs; MCP hooks designed for C7.
|
Settings → Bot; Media and Bot top-level tabs; MCP hooks designed for C7. The slopbot scaffold
|
||||||
|
(config loader, invite helper) and its discord.js dependency were added 2026-09-16 and stay
|
||||||
|
unused until C4.
|
||||||
|
|
||||||
Checkpoints, push after each:
|
Checkpoints, push after each:
|
||||||
- [x] C1 design docs, AGENTS/INDEX pointers, `.gitignore`
|
- [x] C1 design docs, AGENTS/INDEX pointers, `.gitignore`
|
||||||
|
|||||||
+6
-3
@@ -29,7 +29,7 @@ libraries stands.
|
|||||||
`attachments`, and `embeds` in both gateway events and REST history responses. Unverified apps
|
`attachments`, and `embeds` in both gateway events and REST history responses. Unverified apps
|
||||||
in under 100 servers can enable it in the portal.
|
in under 100 servers can enable it in the portal.
|
||||||
3. Invite the bot with the `bot` and `applications.commands` scopes and the minimum permissions:
|
3. Invite the bot with the `bot` and `applications.commands` scopes and the minimum permissions:
|
||||||
View Channels, Read Message History, Send Messages (for status replies), Embed Links.
|
View Channels and Read Message History. The bot never sends, so it needs no more.
|
||||||
4. Store the token in the daemon state file `slopbot.json` (mode 600) or `VESKSLOP_SLOPBOT_TOKEN`.
|
4. Store the token in the daemon state file `slopbot.json` (mode 600) or `VESKSLOP_SLOPBOT_TOKEN`.
|
||||||
Never commit it. The action log redacts token-shaped strings as before.
|
Never commit it. The action log redacts token-shaped strings as before.
|
||||||
|
|
||||||
@@ -41,7 +41,8 @@ channels.
|
|||||||
| Setting | Default | Purpose |
|
| Setting | Default | Purpose |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `VESKSLOP_SLOPBOT_ENABLED` | `0` | Kill switch, off by default |
|
| `VESKSLOP_SLOPBOT_ENABLED` | `0` | Kill switch, off by default |
|
||||||
| `VESKSLOP_SLOPBOT_TOKEN` / `slopbot.json` | unset | Bot token |
|
| `VESKSLOP_SLOPBOT_TOKEN` | unset | Bot token (preferred) |
|
||||||
|
| `VESKSLOP_SLOPBOT_STATE` | unset | JSON file with `token` and `clientId` |
|
||||||
| `VESKSLOP_SLOPBOT_CLIENT_ID` | unset | For the invite URL helper |
|
| `VESKSLOP_SLOPBOT_CLIENT_ID` | unset | For the invite URL helper |
|
||||||
|
|
||||||
## Code
|
## Code
|
||||||
@@ -68,4 +69,6 @@ Slopbot runs with the faster bot budget; the puppet backend uses the slower user
|
|||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
Design approved 2026-09-16. Implementation at checkpoint C4 in [CURRENT.md](../CURRENT.md).
|
Design approved 2026-09-16. Scaffold added 2026-09-16: `media-scrape/slopbot/` (config loader and
|
||||||
|
invite helper) and the discord.js dependency in `media-scrape/package.json`. Unused until
|
||||||
|
checkpoint C4 in [CURRENT.md](../CURRENT.md).
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ media-scrape/
|
|||||||
configurable with `VESKSLOP_MEDIA_DB_DIR` and never committed. See
|
configurable with `VESKSLOP_MEDIA_DB_DIR` and never committed. See
|
||||||
[../docs/media.md](../docs/media.md).
|
[../docs/media.md](../docs/media.md).
|
||||||
|
|
||||||
The daemon imports this folder. discord.js is declared in `poc/package.json`, like the MCP SDK.
|
The daemon imports this folder. `media-scrape/` is its own pnpm workspace root (like `poc/`), so
|
||||||
|
`discord.js` is declared in `media-scrape/package.json` and resolves from `media-scrape/node_modules`.
|
||||||
|
|
||||||
## Docs
|
## Docs
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "veskslop-media-scrape",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"description": "Media archive module for Veskslop: scraper engine, store, Web UI routes, and slopbot.",
|
||||||
|
"dependencies": {
|
||||||
|
"discord.js": "^14.27.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+218
@@ -0,0 +1,218 @@
|
|||||||
|
lockfileVersion: '9.0'
|
||||||
|
|
||||||
|
settings:
|
||||||
|
autoInstallPeers: true
|
||||||
|
excludeLinksFromLockfile: false
|
||||||
|
|
||||||
|
importers:
|
||||||
|
|
||||||
|
.:
|
||||||
|
dependencies:
|
||||||
|
discord.js:
|
||||||
|
specifier: ^14.27.0
|
||||||
|
version: 14.27.0
|
||||||
|
|
||||||
|
packages:
|
||||||
|
|
||||||
|
'@discordjs/builders@1.14.1':
|
||||||
|
resolution: {integrity: sha512-gSKkhXLqs96TCzk66VZuHHl8z2bQMJFGwrXC0f33ngK+FLNau4hU1PYny3DNJfNdSH+gVMzE85/d5FQ2BpcNwQ==}
|
||||||
|
engines: {node: '>=16.11.0'}
|
||||||
|
|
||||||
|
'@discordjs/collection@1.5.3':
|
||||||
|
resolution: {integrity: sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==}
|
||||||
|
engines: {node: '>=16.11.0'}
|
||||||
|
|
||||||
|
'@discordjs/collection@2.1.1':
|
||||||
|
resolution: {integrity: sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
'@discordjs/formatters@0.6.2':
|
||||||
|
resolution: {integrity: sha512-y4UPwWhH6vChKRkGdMB4odasUbHOUwy7KL+OVwF86PvT6QVOwElx+TiI1/6kcmcEe+g5YRXJFiXSXUdabqZOvQ==}
|
||||||
|
engines: {node: '>=16.11.0'}
|
||||||
|
|
||||||
|
'@discordjs/rest@2.6.3':
|
||||||
|
resolution: {integrity: sha512-wvOylxNYJkwKjctS/Mn5GP1w9r3/rzyH+ThD1JlAca6zEdlHs8QWBBUQJpU5Q+W6DoIj/Ljh1IPlZs7hTU+UAg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
'@discordjs/util@1.2.0':
|
||||||
|
resolution: {integrity: sha512-3LKP7F2+atl9vJFhaBjn4nOaSWahZ/yWjOvA4e5pnXkt2qyXRCHLxoBQy81GFtLGCq7K9lPm9R517M1U+/90Qg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
'@discordjs/ws@1.2.3':
|
||||||
|
resolution: {integrity: sha512-wPlQDxEmlDg5IxhJPuxXr3Vy9AjYq5xCvFWGJyD7w7Np8ZGu+Mc+97LCoEc/+AYCo2IDpKioiH0/c/mj5ZR9Uw==}
|
||||||
|
engines: {node: '>=16.11.0'}
|
||||||
|
|
||||||
|
'@sapphire/async-queue@1.5.5':
|
||||||
|
resolution: {integrity: sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg==}
|
||||||
|
engines: {node: '>=v14.0.0', npm: '>=7.0.0'}
|
||||||
|
|
||||||
|
'@sapphire/shapeshift@4.0.0':
|
||||||
|
resolution: {integrity: sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg==}
|
||||||
|
engines: {node: '>=v16'}
|
||||||
|
|
||||||
|
'@sapphire/snowflake@3.5.5':
|
||||||
|
resolution: {integrity: sha512-xzvBr1Q1c4lCe7i6sRnrofxeO1QTP/LKQ6A6qy0iB4x5yfiSfARMEQEghojzTNALDTcv8En04qYNIco9/K9eZQ==}
|
||||||
|
engines: {node: '>=v14.0.0', npm: '>=7.0.0'}
|
||||||
|
|
||||||
|
'@types/node@26.5.1':
|
||||||
|
resolution: {integrity: sha512-CzNm2FezW4VR/LjG6yUdiEgLE/rAQ9Slj5gCu/C2VrdcW7I0ahNZ8DRbHT7zOZ6r3ONgd/bsQIeSaoDGrd1C6g==}
|
||||||
|
|
||||||
|
'@types/ws@8.18.1':
|
||||||
|
resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
|
||||||
|
|
||||||
|
'@vladfrangu/async_event_emitter@2.4.7':
|
||||||
|
resolution: {integrity: sha512-Xfe6rpCTxSxfbswi/W/Pz7zp1WWSNn4A0eW4mLkQUewCrXXtMj31lCg+iQyTkh/CkusZSq9eDflu7tjEDXUY6g==}
|
||||||
|
engines: {node: '>=v14.0.0', npm: '>=7.0.0'}
|
||||||
|
|
||||||
|
discord-api-types@0.38.55:
|
||||||
|
resolution: {integrity: sha512-ytuaRTzdnHUCXJ6KjL9MrItQX0xKncBKEeYI1Bst4+ud47eejH3cG6gaesYakjpPcUhh68XYS2YwGq3mmujFsA==}
|
||||||
|
|
||||||
|
discord.js@14.27.0:
|
||||||
|
resolution: {integrity: sha512-qHbFlFG2N7y3LjPySYsL6A1+BnX6bkTVgo842EX0CqVPk/KTMwZkojPHEXKsQUpWZNyz5BISNHK1cPpQw0+m4A==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
fast-deep-equal@3.1.3:
|
||||||
|
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||||
|
|
||||||
|
lodash.snakecase@4.1.1:
|
||||||
|
resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==}
|
||||||
|
|
||||||
|
lodash@4.18.1:
|
||||||
|
resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==}
|
||||||
|
|
||||||
|
magic-bytes.js@1.13.1:
|
||||||
|
resolution: {integrity: sha512-x5sn4UX2k5gCWlcfmoFwG4TPie8+dctESyqOBdhB5p6MsgWXdBKGmt9nXPObj/JI50TTL928lc5Yt1WntMn1bw==}
|
||||||
|
|
||||||
|
ts-mixer@6.0.4:
|
||||||
|
resolution: {integrity: sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==}
|
||||||
|
|
||||||
|
tslib@2.8.1:
|
||||||
|
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
||||||
|
|
||||||
|
undici-types@8.9.0:
|
||||||
|
resolution: {integrity: sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==}
|
||||||
|
|
||||||
|
undici@6.28.1:
|
||||||
|
resolution: {integrity: sha512-zWpdTVD54H48CIybL0rWQ3ukpb9d23wM7eH5RtfdmeP70cWHNjtfo7P4vZX+5CoDcO53J4Pu5uXp7lNfjc6DRA==}
|
||||||
|
engines: {node: '>=18.17'}
|
||||||
|
|
||||||
|
ws@8.21.3:
|
||||||
|
resolution: {integrity: sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
bufferutil: ^4.0.1
|
||||||
|
utf-8-validate: '>=5.0.2'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
bufferutil:
|
||||||
|
optional: true
|
||||||
|
utf-8-validate:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
snapshots:
|
||||||
|
|
||||||
|
'@discordjs/builders@1.14.1':
|
||||||
|
dependencies:
|
||||||
|
'@discordjs/formatters': 0.6.2
|
||||||
|
'@discordjs/util': 1.2.0
|
||||||
|
'@sapphire/shapeshift': 4.0.0
|
||||||
|
discord-api-types: 0.38.55
|
||||||
|
fast-deep-equal: 3.1.3
|
||||||
|
ts-mixer: 6.0.4
|
||||||
|
tslib: 2.8.1
|
||||||
|
|
||||||
|
'@discordjs/collection@1.5.3': {}
|
||||||
|
|
||||||
|
'@discordjs/collection@2.1.1': {}
|
||||||
|
|
||||||
|
'@discordjs/formatters@0.6.2':
|
||||||
|
dependencies:
|
||||||
|
discord-api-types: 0.38.55
|
||||||
|
|
||||||
|
'@discordjs/rest@2.6.3':
|
||||||
|
dependencies:
|
||||||
|
'@discordjs/collection': 2.1.1
|
||||||
|
'@discordjs/util': 1.2.0
|
||||||
|
'@sapphire/async-queue': 1.5.5
|
||||||
|
'@sapphire/snowflake': 3.5.5
|
||||||
|
'@vladfrangu/async_event_emitter': 2.4.7
|
||||||
|
discord-api-types: 0.38.55
|
||||||
|
magic-bytes.js: 1.13.1
|
||||||
|
tslib: 2.8.1
|
||||||
|
undici: 6.28.1
|
||||||
|
|
||||||
|
'@discordjs/util@1.2.0':
|
||||||
|
dependencies:
|
||||||
|
discord-api-types: 0.38.55
|
||||||
|
|
||||||
|
'@discordjs/ws@1.2.3':
|
||||||
|
dependencies:
|
||||||
|
'@discordjs/collection': 2.1.1
|
||||||
|
'@discordjs/rest': 2.6.3
|
||||||
|
'@discordjs/util': 1.2.0
|
||||||
|
'@sapphire/async-queue': 1.5.5
|
||||||
|
'@types/ws': 8.18.1
|
||||||
|
'@vladfrangu/async_event_emitter': 2.4.7
|
||||||
|
discord-api-types: 0.38.55
|
||||||
|
tslib: 2.8.1
|
||||||
|
ws: 8.21.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- bufferutil
|
||||||
|
- utf-8-validate
|
||||||
|
|
||||||
|
'@sapphire/async-queue@1.5.5': {}
|
||||||
|
|
||||||
|
'@sapphire/shapeshift@4.0.0':
|
||||||
|
dependencies:
|
||||||
|
fast-deep-equal: 3.1.3
|
||||||
|
lodash: 4.18.1
|
||||||
|
|
||||||
|
'@sapphire/snowflake@3.5.5': {}
|
||||||
|
|
||||||
|
'@types/node@26.5.1':
|
||||||
|
dependencies:
|
||||||
|
undici-types: 8.9.0
|
||||||
|
|
||||||
|
'@types/ws@8.18.1':
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 26.5.1
|
||||||
|
|
||||||
|
'@vladfrangu/async_event_emitter@2.4.7': {}
|
||||||
|
|
||||||
|
discord-api-types@0.38.55: {}
|
||||||
|
|
||||||
|
discord.js@14.27.0:
|
||||||
|
dependencies:
|
||||||
|
'@discordjs/builders': 1.14.1
|
||||||
|
'@discordjs/collection': 1.5.3
|
||||||
|
'@discordjs/formatters': 0.6.2
|
||||||
|
'@discordjs/rest': 2.6.3
|
||||||
|
'@discordjs/util': 1.2.0
|
||||||
|
'@discordjs/ws': 1.2.3
|
||||||
|
'@sapphire/snowflake': 3.5.5
|
||||||
|
discord-api-types: 0.38.55
|
||||||
|
fast-deep-equal: 3.1.3
|
||||||
|
lodash.snakecase: 4.1.1
|
||||||
|
magic-bytes.js: 1.13.1
|
||||||
|
tslib: 2.8.1
|
||||||
|
undici: 6.28.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- bufferutil
|
||||||
|
- utf-8-validate
|
||||||
|
|
||||||
|
fast-deep-equal@3.1.3: {}
|
||||||
|
|
||||||
|
lodash.snakecase@4.1.1: {}
|
||||||
|
|
||||||
|
lodash@4.18.1: {}
|
||||||
|
|
||||||
|
magic-bytes.js@1.13.1: {}
|
||||||
|
|
||||||
|
ts-mixer@6.0.4: {}
|
||||||
|
|
||||||
|
tslib@2.8.1: {}
|
||||||
|
|
||||||
|
undici-types@8.9.0: {}
|
||||||
|
|
||||||
|
undici@6.28.1: {}
|
||||||
|
|
||||||
|
ws@8.21.3: {}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# Keep media-scrape its own workspace root, separate from the Vesktop app.
|
||||||
|
packages: []
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Slopbot — the dedicated bot core for media scraping.
|
||||||
|
*
|
||||||
|
* Scaffold only: nothing imports this yet. The scrape backend lands at
|
||||||
|
* checkpoint C4 (see ../CURRENT.md). Setup, limits, and security: docs/slopbot.md.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { readFileSync } from "node:fs";
|
||||||
|
|
||||||
|
export interface SlopbotConfig {
|
||||||
|
/** Kill switch. Off unless VESKSLOP_SLOPBOT_ENABLED=1 and a token exists. */
|
||||||
|
enabled: boolean;
|
||||||
|
/** Bot token. Never logged, never committed. */
|
||||||
|
token: string | null;
|
||||||
|
/** Application ID, used to render the invite URL. */
|
||||||
|
clientId: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SlopbotStateFile {
|
||||||
|
token?: string;
|
||||||
|
clientId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readStateFile(path: string): SlopbotStateFile {
|
||||||
|
try {
|
||||||
|
return JSON.parse(readFileSync(path, "utf8")) as SlopbotStateFile;
|
||||||
|
} catch {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Read the slopbot settings from the environment, then from the state file. */
|
||||||
|
export function loadSlopbotConfig(
|
||||||
|
env: NodeJS.ProcessEnv = process.env,
|
||||||
|
stateFilePath = env.VESKSLOP_SLOPBOT_STATE
|
||||||
|
): SlopbotConfig {
|
||||||
|
const state = stateFilePath ? readStateFile(stateFilePath) : {};
|
||||||
|
const token = env.VESKSLOP_SLOPBOT_TOKEN ?? state.token ?? null;
|
||||||
|
const clientId = env.VESKSLOP_SLOPBOT_CLIENT_ID ?? state.clientId ?? null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
enabled: env.VESKSLOP_SLOPBOT_ENABLED === "1" && token !== null,
|
||||||
|
token,
|
||||||
|
clientId
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Slopbot entry point.
|
||||||
|
*
|
||||||
|
* Scaffold only: the daemon does not import this yet. Checkpoint C4 adds the
|
||||||
|
* scrape backend; docs/slopbot.md is the module contract.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { Client } from "discord.js";
|
||||||
|
import { loadSlopbotConfig, type SlopbotConfig } from "./config.js";
|
||||||
|
|
||||||
|
/** Kept as a type so the discord.js dependency is type-checked before C4 uses it. */
|
||||||
|
export type SlopbotClient = Client;
|
||||||
|
|
||||||
|
export { loadSlopbotConfig, type SlopbotConfig };
|
||||||
|
|
||||||
|
/** View Channels + Read Message History. The bot reads only; it never sends. */
|
||||||
|
const PERMISSIONS = String((1 << 10) | (1 << 16));
|
||||||
|
|
||||||
|
/** The invite URL the Bot tab renders once a client ID is configured. */
|
||||||
|
export function slopbotInviteUrl(clientId: string): string {
|
||||||
|
return `https://discord.com/oauth2/authorize?client_id=${encodeURIComponent(
|
||||||
|
clientId
|
||||||
|
)}&scope=bot%20applications.commands&permissions=${PERMISSIONS}`;
|
||||||
|
}
|
||||||
+1
-1
@@ -12,5 +12,5 @@
|
|||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"resolveJsonModule": true
|
"resolveJsonModule": true
|
||||||
},
|
},
|
||||||
"include": ["src"]
|
"include": ["src", "../media-scrape/slopbot"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user