🎵 All the way, to Nucleus production (town) (#101)

Co-authored-by: PineappleFan <pineapplefanyt@gmail.com>
Co-authored-by: Skyler <skyler3665@gmail.com>
dependabot/npm_and_yarn/word-wrap-1.2.4
Samuel Shuert 3 years ago committed by GitHub
commit 34a5eaacae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,4 +1,3 @@
if ! has nix_direnv_version || ! nix_direnv_version 2.2.1; then
source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.2.1/direnvrc" "sha256-zelF0vLbEl5uaqrfIzbgNzJWGmLzCmYAkInj/LNxvKs="
fi
use flake
nix_direnv_watch_file flake.nix
use flake --impure
dotenv .env

@ -21,10 +21,10 @@ jobs:
- uses: cachix/install-nix-action@v19
with:
github_access_token: ${{ secrets.GITHUB_TOKEN }}
- run: nix develop --command yarn install --immutable --immutable-cache --check-cache
- run: nix develop .#pure --command pnpm install --frozen-lockfile
- name: Show versions
run: nix develop --command yarn run versions
run: nix develop .#pure --command pnpm run versions
- name: Compile
run: nix develop --command yarn build
run: nix develop .#pure --command pnpm run build build
- name: Run prettier and eslint
run: nix develop --command yarn lint-ci
run: nix develop .#pure --command pnpm run lint-ci

138
.gitignore vendored

@ -1,14 +1,8 @@
dist/
.history/
node_modules/
src/config/*
!src/config/*.d.ts
!src/config/format.ts
!src/config/default.ts
!src/config/emojis.ts
src/utils/migration/data
src/config/main.ts
.vscode/
.vim/
yarn-error.log
@ -21,3 +15,135 @@ ClicksMigratingProblems/oldData/
ClicksMigratingProblems/oldData copy/
.direnv/
.devenv/
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
.cache
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

2
.gitmodules vendored

@ -1,4 +1,4 @@
[submodule "src/reflex/nsfwjs"]
path = src/reflex/nsfwjs
url = https://github.com/infinitered/nsfwjs
url = https://github.com/clicksminuteper/nsfwjs
shallow = true

@ -21,4 +21,5 @@ ClicksMigratingProblems/oldData/
ClicksMigratingProblems/oldData copy/
.direnv/
.devenv/
src/reflex/nsfwjs/**/*

@ -2,9 +2,9 @@
## Contents:
- [In short](in-short)
- [How to](how-to)
- [The legal bit](the-legal-bit)
- [In short](#in-short)
- [How to](#how-to)
- [The legal bit](#the-legal-bit)
## In Short:
@ -29,7 +29,6 @@ Alternatively, you can run `Installer.js` to generate it for you.
```json
{
"token": "your-token-here",
"developmentToken": "dev-token-here",
"managementGuildID": "your-management-guild-id-here",
"developmentGuildID": "your-development-guild-id-here",
"enableDevelopment": true,

@ -0,0 +1 @@
allowUnfree: true

@ -3,7 +3,7 @@ module.exports = {
{
name: "Nucleus",
script: "/run/current-system/sw/bin/nix",
args: "develop --command yarn start --update-commands"
args: "develop --command pnpm start --update-commands"
}
]
};

@ -1,15 +1,126 @@
{
"nodes": {
"clicks-server": {
"inputs": {
"deploy-rs": "deploy-rs",
"flake-utils": "flake-utils",
"home-manager": "home-manager",
"nixpkgs": "nixpkgs_2",
"scalpel": "scalpel",
"sops-nix": "sops-nix"
},
"locked": {
"lastModified": 1686252801,
"narHash": "sha256-ASguQr5onfE7HzawjAvhck2y7NDZ3bdhqFC8O3/XrXU=",
"ref": "refs/heads/production",
"rev": "7f3559f9a56d28b8f5352040f18305082a6dacc0",
"revCount": 53,
"type": "git",
"url": "ssh://git@github.com/clicksminuteper/nixfiles"
},
"original": {
"type": "git",
"url": "ssh://git@github.com/clicksminuteper/nixfiles"
}
},
"deploy-rs": {
"inputs": {
"flake-compat": "flake-compat",
"nixpkgs": "nixpkgs",
"utils": "utils"
},
"locked": {
"lastModified": 1685948350,
"narHash": "sha256-1FldJ059so0X/rScdbIiOlQbjjSNCCTdj2cUr5pHU4A=",
"owner": "serokell",
"repo": "deploy-rs",
"rev": "65211db63ba1199f09b4c9f27e5eba5ec50d76ac",
"type": "github"
},
"original": {
"owner": "serokell",
"repo": "deploy-rs",
"type": "github"
}
},
"devenv": {
"inputs": {
"flake-compat": "flake-compat_2",
"nix": "nix",
"nixpkgs": "nixpkgs_3",
"pre-commit-hooks": "pre-commit-hooks"
},
"locked": {
"lastModified": 1686642933,
"narHash": "sha256-5Z4uitx27QtZIrG9sOSJlZRNcVQn/TI36nj7o70n5Dw=",
"owner": "cachix",
"repo": "devenv",
"rev": "f5278b5d56e39f86a299a2e1889906933a26f762",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "devenv",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1668681692,
"narHash": "sha256-Ht91NGdewz8IQLtWZ9LCeNXMSXHUss+9COoqu6JLmXU=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "009399224d5e398d03b22badca40a37ac85412a1",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-compat_2": {
"flake": false,
"locked": {
"lastModified": 1673956053,
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1681202837,
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
"lastModified": 1685518550,
"narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"locked": {
"lastModified": 1667395993,
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github"
},
"original": {
@ -18,13 +129,181 @@
"type": "github"
}
},
"flake-utils_3": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1685518550,
"narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_4": {
"inputs": {
"systems": "systems_3"
},
"locked": {
"lastModified": 1685518550,
"narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"devenv",
"pre-commit-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1660459072,
"narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "a20de23b925fd8264fd7fad6454652e142fd7f73",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"home-manager": {
"inputs": {
"nixpkgs": [
"clicks-server",
"nixpkgs"
]
},
"locked": {
"lastModified": 1685599623,
"narHash": "sha256-Tob4CMOVHue0D3RzguDBCtUmX5ji2PsdbQDbIOIKvsc=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "93db05480c0c0f30382d3e80779e8386dcb4f9dd",
"type": "github"
},
"original": {
"owner": "nix-community",
"ref": "release-23.05",
"repo": "home-manager",
"type": "github"
}
},
"lowdown-src": {
"flake": false,
"locked": {
"lastModified": 1633514407,
"narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=",
"owner": "kristapsdz",
"repo": "lowdown",
"rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8",
"type": "github"
},
"original": {
"owner": "kristapsdz",
"repo": "lowdown",
"type": "github"
}
},
"nix": {
"inputs": {
"lowdown-src": "lowdown-src",
"nixpkgs": [
"devenv",
"nixpkgs"
],
"nixpkgs-regression": "nixpkgs-regression"
},
"locked": {
"lastModified": 1676545802,
"narHash": "sha256-EK4rZ+Hd5hsvXnzSzk2ikhStJnD63odF7SzsQ8CuSPU=",
"owner": "domenkozar",
"repo": "nix",
"rev": "7c91803598ffbcfe4a55c44ac6d49b2cf07a527f",
"type": "github"
},
"original": {
"owner": "domenkozar",
"ref": "relaxed-flakes",
"repo": "nix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1682134069,
"narHash": "sha256-TnI/ZXSmRxQDt2sjRYK/8j8iha4B4zP2cnQCZZ3vp7k=",
"lastModified": 1671417167,
"narHash": "sha256-JkHam6WQOwZN1t2C2sbp1TqMv3TVRjzrdoejqfefwrM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "bb31220cca6d044baa6dc2715b07497a2a7c4bc7",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-regression": {
"locked": {
"lastModified": 1643052045,
"narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
"type": "github"
}
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1685758009,
"narHash": "sha256-IT4Z5WGhafrq+xbDTyuKrRPRQ1f+kVOtE+4JU1CHFeo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "eaf03591711b46d21abc7082a8ebee4681f9dbeb",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "release-22.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-stable_2": {
"locked": {
"lastModified": 1678872516,
"narHash": "sha256-/E1YwtMtFAu2KUQKV/1+KFuReYPANM2Rzehk84VxVoc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "fd901ef4bf93499374c5af385b2943f5801c0833",
"rev": "9b8e5abb18324c7fe9f07cb100c3cd4a29cda8b8",
"type": "github"
},
"original": {
@ -34,10 +313,144 @@
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1686059680,
"narHash": "sha256-sp0WlCIeVczzB0G8f8iyRg3IYW7KG31mI66z7HIZwrI=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "a558f7ac29f50c4b937fb5c102f587678ae1c9fb",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-23.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1678875422,
"narHash": "sha256-T3o6NcQPwXjxJMn2shz86Chch4ljXgZn746c2caGxd8=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "126f49a01de5b7e35a43fd43f891ecf6d3a51459",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"pnpm2nix": {
"inputs": {
"flake-utils": "flake-utils_4",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1686323589,
"narHash": "sha256-XADn6eWl3670Oj38p0GiN1PaPKvTmDQRQErGLXYjZQU=",
"ref": "refs/heads/master",
"rev": "aa1dc4ff5759f04cc383a5b38a163b3a7b6ac601",
"revCount": 102,
"type": "git",
"url": "ssh://git@github.com/clicksminuteper/pnpm2nix"
},
"original": {
"type": "git",
"url": "ssh://git@github.com/clicksminuteper/pnpm2nix"
}
},
"pre-commit-hooks": {
"inputs": {
"flake-compat": [
"devenv",
"flake-compat"
],
"flake-utils": "flake-utils_2",
"gitignore": "gitignore",
"nixpkgs": [
"devenv",
"nixpkgs"
],
"nixpkgs-stable": "nixpkgs-stable_2"
},
"locked": {
"lastModified": 1686050334,
"narHash": "sha256-R0mczWjDzBpIvM3XXhO908X5e2CQqjyh/gFbwZk/7/Q=",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "6881eb2ae5d8a3516e34714e7a90d9d95914c4dc",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
"clicks-server": "clicks-server",
"devenv": "devenv",
"flake-utils": "flake-utils_3",
"nixpkgs": [
"clicks-server",
"nixpkgs"
],
"pnpm2nix": "pnpm2nix"
}
},
"scalpel": {
"inputs": {
"nixpkgs": [
"clicks-server",
"nixpkgs"
],
"sops-nix": [
"clicks-server",
"sops-nix"
]
},
"locked": {
"lastModified": 1655566736,
"narHash": "sha256-Vyolf8j7QcAHyVTQMqS8EGYZ/P6leJtiVNhYyIxoMRw=",
"owner": "polygon",
"repo": "scalpel",
"rev": "16c2103d613bb1c7adc6dbf2a17c2980ce08567f",
"type": "github"
},
"original": {
"owner": "polygon",
"repo": "scalpel",
"type": "github"
}
},
"sops-nix": {
"inputs": {
"nixpkgs": [
"clicks-server",
"nixpkgs"
],
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1685848844,
"narHash": "sha256-Iury+/SVbAwLES76QJSiKFiQDzmf/8Hsq8j54WF2qyw=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "a522e12ee35e50fa7d902a164a9796e420e6e75b",
"type": "github"
},
"original": {
"owner": "Mic92",
"repo": "sops-nix",
"type": "github"
}
},
"systems": {
@ -54,8 +467,53 @@
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_3": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"utils": {
"locked": {
"lastModified": 1667395993,
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
}
},
"root": "root",
"version": 7
}
}

@ -1,17 +1,170 @@
{
description = "A basic flake with a shell";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-22.11";
inputs.nixpkgs.follows = "clicks-server/nixpkgs";
inputs.flake-utils.url = "github:numtide/flake-utils";
inputs.clicks-server.url = "git+ssh://git@github.com/clicksminuteper/nixfiles";
inputs.pnpm2nix.url = "git+ssh://git@github.com/clicksminuteper/pnpm2nix";
inputs.devenv.url = "github:cachix/devenv";
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system: let
pkgs = nixpkgs.legacyPackages.${system};
in {
devShells.default = pkgs.mkShell {
packages = [ pkgs.nodejs-19_x pkgs.nodePackages_latest.yarn ];
shellHook = ''
unset name
'';
};
});
}
inputs.pnpm2nix.inputs.nixpkgs.follows = "nixpkgs";
outputs = { self, devenv, nixpkgs, flake-utils, clicks-server, pnpm2nix, ... }@inputs:
flake-utils.lib.eachDefaultSystem
(system:
let
pkgs = nixpkgs.legacyPackages.${system};
nodejs = pkgs.nodejs_20;
nodePackages = pkgs.nodePackages_latest;
lib = pkgs.lib;
shellPackages = [ nodejs nodePackages.pnpm pkgs.pkg-config pkgs.fontconfig.dev pkgs.clamav ];
enterShellHook = ''
unset name
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${lib.makeSearchPath "/lib/pkgconfig" [
pkgs.pixman
pkgs.cairo.dev
pkgs.libpng.dev
pkgs.gnome2.pango.dev
pkgs.glib.dev
pkgs.harfbuzz.dev
pkgs.freetype.dev
]}
'';
in
rec {
devShells.pure = pkgs.mkShell {
packages = shellPackages;
shellHook = enterShellHook;
};
devShells.default = devenv.lib.mkShell {
inherit inputs pkgs;
modules = [
({ pkgs, config, ... }: {
# This is your devenv configuration
packages = shellPackages;
enterShell = enterShellHook;
services.mongodb = {
enable = true;
package = pkgs.mongodb-6_0;
additionalArgs = [
"--port"
"27017"
"--noauth"
];
};
processes.clamav.exec =
let
clamd_config = pkgs.writeText "clamd.conf" ''
TCPSocket 3310
PidFile /tmp/clamav-nucleus.pid
DatabaseDirectory ${config.env.DEVENV_STATE}/clamav/db
TemporaryDirectory /tmp
Foreground true
'';
freshclam_config = pkgs.writeText "freshclam.conf" ''
DatabaseDirectory ${config.env.DEVENV_STATE}/clamav/db
DatabaseMirror database.clamav.net
'';
in
"mkdir -p $DEVENV_STATE/clamav/db && ${pkgs.clamav}/bin/freshclam --config ${freshclam_config} || true; ${pkgs.clamav}/bin/clamd -c ${clamd_config}";
})
];
};
}) // {
packages.x86_64-linux =
let
pkgs = nixpkgs.legacyPackages.x86_64-linux;
nodejs = pkgs.nodejs_20;
nodePackages = pkgs.nodePackages_latest;
lib = pkgs.lib;
in
rec {
nucleus =
let
packageJSON = (builtins.fromJSON (builtins.readFile ./package.json));
node_modules = lib.pipe
{
src = ./.;
linkDevDependencies = true;
overrides = pnpm2nix.defaultPnpmOverrides.x86_64-linux // {
canvas = (drv: drv.overrideAttrs (oldAttrs: {
nativeBuildInputs = oldAttrs.nativeBuildInputs ++ [ pkgs.pkg-config ];
buildInputs = oldAttrs.buildInputs ++ [
pkgs.pixman
pkgs.cairo.dev
pkgs.libpng.dev
pkgs.gnome2.pango.dev
pkgs.glib.dev
pkgs.harfbuzz.dev
pkgs.freetype.dev
];
}));
"@tensorflow/tfjs-node" = (drv: drv.overrideAttrs (oldAttrs: {
buildInputs = oldAttrs.buildInputs ++ [
pkgs.libtensorflow
];
preBuild = ''
mkdir -p node_modules/@tensorflow/tfjs-node/deps/lib
ln -s ${pkgs.libtensorflow}/lib/libtensorflow.so.2 node_modules/@tensorflow/tfjs-node/deps/lib/libtensorflow.so.2.9.1
'';
}));
};
} [
(pnpm2nix.mkPnpmPackage.x86_64-linux)
(drv: builtins.readFile "${drv}/nix-support/propagated-build-inputs")
(path: "${path}/node_modules")
];
in
pkgs.stdenv.mkDerivation {
pname = "nucleus";
version = packageJSON.version;
src = ./.;
buildInputs = [ nodejs nodePackages.pnpm ];
nativeBuildInputs = [ nodePackages.pnpm nodePackages.typescript pkgs.python3 ];
buildPhase = ''
${pkgs.python3}/bin/python3 ${./scripts/fix-pnpm-bin.py} ${node_modules} ./bin
export PATH=$PATH:./bin
ln -s ${node_modules} node_modules
pnpm run build
'';
installPhase = ''
mkdir -p $out
cp dist $out -r
cp node_modules $out -r
cp bin $out/.bin -r
cp package.json $out
cp LICENSE $out
mkdir -p $out/bin
echo "#!/usr/bin/env bash" > $out/bin/nucleus
echo "cd $out" >> $out/bin/nucleus
echo "export PATH=$PATH:$out/node_modules/.bin" >> $out/bin/nucleus
echo "${packageJSON.scripts.start}" >> $out/bin/nucleus
chmod +x $out/bin/nucleus
'';
};
dockerImage = pkgs.dockerTools.streamLayeredImage {
name = "nucleus";
tag = "latest";
contents = [ nucleus ];
config.Cmd = [ "${nucleus}/bin/nucleus" ];
};
default = nucleus;
};
};
}

@ -0,0 +1,3 @@
builds:
exclude:
- devShells.x86_64-linux.default

@ -1,56 +1,58 @@
{
"dependencies": {
"@hokify/agenda": "^6.2.12",
"@octokit/graphql": "^5.0.5",
"@tensorflow/tfjs": "^3.18.0",
"@tensorflow/tfjs-node": "^3.18.0",
"@total-typescript/ts-reset": "^0.3.7",
"@ungap/structured-clone": "^1.0.1",
"agenda": "^4.3.0",
"body-parser": "^1.20.0",
"canvas": "^2.11.0",
"@clicks/nsfwjs": "^3.0.3",
"@hokify/agenda": "^6.3.0",
"@octokit/graphql": "^5.0.6",
"@tensorflow/tfjs": "^4.7.0",
"@tensorflow/tfjs-node": "^4.7.0",
"@total-typescript/ts-reset": "^0.4.2",
"@ungap/structured-clone": "^1.2.0",
"agenda": "^5.0.0",
"body-parser": "^1.20.2",
"canvas": "^2.11.2",
"clamscan": "^2.1.2",
"diff": "^5.1.0",
"discord.js": "^14.8.0",
"eslint": "^8.21.0",
"express": "^4.18.1",
"discord.js": "^14.11.0",
"dotenv": "^16.1.4",
"eslint": "^8.42.0",
"express": "^4.18.2",
"fuse.js": "^6.6.2",
"gifencoder": "^2.0.1",
"gm": "^1.25.0",
"humanize-duration": "^3.27.1",
"immutable": "^4.1.0",
"humanize-duration": "^3.28.0",
"immutable": "^4.3.0",
"lodash": "^4.17.21",
"mongodb": "^4.7.0",
"node-fetch": "^3.3.0",
"mongodb": "^5.6.0",
"node-fetch": "^3.3.1",
"node-tesseract-ocr": "^2.2.1",
"nsfwjs": "^2.4.2",
"octokit": "^2.0.14",
"octokit": "^2.0.19",
"seedrandom": "^3.0.5",
"structured-clone": "^0.2.2",
"systeminformation": "^5.17.3"
"systeminformation": "^5.18.2"
},
"resolutions": {
"discord-api-types": "0.37.23"
"pnpm": {
"overrides": {
"@hokify/agenda>mongodb": "$mongodb"
}
},
"name": "nucleus",
"version": "1.1.0",
"description": "Nucleus: The core of your server",
"main": "dist/index.js",
"scripts": {
"build": "tsc && yarn copy-files",
"build": "tsc && pnpm copy-files",
"copy-files": "copyfiles -u 1 src/reflex/nsfwjs/example/nsfw_demo/public/model/**/* dist/",
"start": "node --experimental-json-modules --enable-source-maps dist/index.js",
"dev": "rm -rf dist && eslint src --fix && yarn build && node --experimental-json-modules --enable-source-maps dist/index.js",
"force-dev": "clear; rm -rf dist; tsc-suppress && yarn copy-files && node --experimental-json-modules --enable-source-maps dist/index.js",
"lint": "echo 'Style checking...'; prettier --check .; echo 'Linting...'; eslint src; echo 'To auto-fix everything possible, please run `yarn lint-fix`'; true",
"lint-no-stylecheck": "echo 'Linting...'; eslint src; echo 'A full lint and style check is required for PRs to be accepted. Please run `yarn lint` before committing'; true",
"start": "node --experimental-json-modules --enable-source-maps -r dotenv/config dist/index.js",
"dev": "rm -rf dist && eslint src --fix && pnpm build && node --experimental-json-modules --enable-source-maps dist/index.js",
"force-dev": "clear; rm -rf dist; tsc-suppress && pnpm copy-files && node --experimental-json-modules --enable-source-maps dist/index.js",
"lint": "echo 'Style checking...'; prettier --check .; echo 'Linting...'; eslint src; echo 'To auto-fix everything possible, please run `pnpm lint-fix`'; true",
"lint-no-stylecheck": "echo 'Linting...'; eslint src; echo 'A full lint and style check is required for PRs to be accepted. Please run `pnpm lint` before committing'; true",
"lint-fix": "echo 'Fixing eslint issues...'; eslint src --fix; echo 'Reformatting...'; prettier --write --loglevel warn --cache .; true",
"lint-list": "echo 'Style checking...'; prettier --check .; echo 'Linting...'; eslint src; echo 'To view errors in more detail, please run `yarn lint`'; true",
"lint-list": "echo 'Style checking...'; prettier --check .; echo 'Linting...'; eslint src; echo 'To view errors in more detail, please run `pnpm lint`'; true",
"lint-ci": "echo 'Style checking...' && prettier --check . && echo 'Linting...' && eslint src",
"setup": "node Installer.js",
"win-force-build": "clear | rm -r dist | tsc-suppress | yarn copy-files",
"audit-fix": "yarn-audit-fix",
"versions": "yarn versions && yarn list && node --version",
"setup": "npm i -g pnpm | pnpm | pnpm build | node Installer.js",
"win-force-build": "clear | rm -r dist | tsc-suppress | pnpm copy-files",
"audit-fix": "pnpm audit --fix",
"versions": "pnpm --version && pnpm list && node --version",
"win-lint-fix": "echo 'Fixing eslint issues...' | eslint src --fix | echo 'Reformatting...' | prettier --write --loglevel warn --cache . | true"
},
"repository": {
@ -60,10 +62,10 @@
"author": "Clicks",
"contributors": [
"Minion3665",
"PineappleFan",
"PineaFan",
"TheCodedProf"
],
"license": "SEE LICENSE IN LICENSE",
"license": "AGPL-3.0",
"bugs": {
"url": "https://github.com/ClicksMinutePer/Nucleus/issues"
},
@ -72,19 +74,17 @@
"type": "module",
"devDependencies": {
"@types/clamscan": "^2.0.4",
"@types/gifencoder": "^2.0.1",
"@types/lodash": "^4.14.191",
"@typescript-eslint/eslint-plugin": "^5.32.0",
"@typescript-eslint/parser": "^5.32.0",
"@types/diff": "^5.0.3",
"@types/gm": "^1.25.1",
"@types/lodash": "^4.14.195",
"@types/node": "^20.2.5",
"@typescript-eslint/eslint-plugin": "^5.59.9",
"@typescript-eslint/parser": "^5.59.9",
"copyfiles": "^2.4.1",
"eslint-config-prettier": "^8.5.0",
"prettier": "^2.7.1",
"eslint-config-prettier": "^8.8.0",
"prettier": "^2.8.8",
"prettier-eslint": "^15.0.1",
"tsc-suppress": "^1.0.7",
"typescript": "^5.0.0",
"yarn-audit-fix": "^9.3.9",
"@types/diff": "^5.0.3",
"@types/gm": "^1.25.0",
"@types/node": "^18.14.6"
"typescript": "^5.1.3"
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1 @@
/nix/store/fmvzckvxnqrfbgv0mvzghgi87602pgcm-nucleus-1.1.0

@ -0,0 +1,50 @@
import sys
import os
import json
node_modules = sys.argv[1]
bin_dir = sys.argv[2]
def collect_packages_in(_node_modules, packages: set[str] | None = None):
_packages: set[str] = packages or set()
for path in os.listdir(_node_modules):
if not os.path.isdir(os.path.join(_node_modules, path)) or os.path.join(_node_modules, path) in _packages:
continue
_packages.add(os.path.join(_node_modules, path))
if os.path.exists(os.path.join(_node_modules, path, "node_modules")):
collect_packages_in(os.path.join(_node_modules, path, "node_modules"), _packages)
return _packages
def get_binaries_in(package):
package_json = os.path.join(package, "package.json")
if not os.path.exists(package_json):
return []
with open(package_json) as f:
package_json_contents = json.load(f)
if "bin" not in package_json_contents:
return []
if type(package_json_contents["bin"]) == str:
return [[os.path.basename(package_json_contents["name"]), os.path.join(package, package_json_contents["bin"])]]
return [[name, os.path.join(package, bin)] for name, bin in package_json_contents["bin"].items()]
def main():
packages = collect_packages_in(node_modules)
binaries = []
for package in packages:
binaries += get_binaries_in(package)
os.makedirs(bin_dir, exist_ok=True)
for binary in binaries:
if os.path.exists(os.path.join(bin_dir, binary[0])):
os.remove(os.path.join(bin_dir, binary[0]))
os.symlink(os.path.realpath(binary[1]), os.path.join(bin_dir, binary[0]))
if __name__ == "__main__":
main()

@ -0,0 +1,5 @@
import { type ButtonInteraction } from "discord.js";
export async function callback(interaction: ButtonInteraction) {
console.log(interaction);
}

@ -3,6 +3,6 @@ import { command } from "../../utils/commandRegistration/slashCommandBuilder.js"
const name = "mod";
const description = "Perform moderator actions";
const subcommand = await command(name, description, `mod`);
const subcommand: Awaited<ReturnType<typeof command>> = await command(name, description, `mod`);
export { name, description, subcommand as command };

@ -3,6 +3,15 @@ import { command } from "../../utils/commandRegistration/slashCommandBuilder.js"
const name = "nucleus";
const description = "Commands relating to Nucleus itself";
const subcommand = await command(name, description, `nucleus`, undefined, undefined, undefined, undefined, true);
const subcommand: Awaited<ReturnType<typeof command>> = await command(
name,
description,
`nucleus`,
undefined,
undefined,
undefined,
undefined,
true
);
export { name, description, subcommand as command };

@ -3,6 +3,6 @@ import { command } from "../../utils/commandRegistration/slashCommandBuilder.js"
const name = "server";
const description = "Commands for the server";
const subcommand = await command(name, description, `server`);
const subcommand: Awaited<ReturnType<typeof command>> = await command(name, description, `server`);
export { name, description, subcommand as command };

@ -3,6 +3,14 @@ import { command } from "../../utils/commandRegistration/slashCommandBuilder.js"
const name = "settings";
const description = "Change bot settings";
const subcommand = await command(name, description, "settings", undefined, undefined, undefined, ["ManageGuild"]);
const subcommand: Awaited<ReturnType<typeof command>> = await command(
name,
description,
"settings",
undefined,
undefined,
undefined,
["ManageGuild"]
);
export { name, description, subcommand as command };

@ -3,6 +3,6 @@ import { group } from "../../../utils/commandRegistration/slashCommandBuilder.js
const name = "logs";
const description = "Settings for logging";
const subcommand = await group(name, description, `settings/logs`);
const subcommand: Awaited<ReturnType<typeof group>> = await group(name, description, `settings/logs`);
export { name, description, subcommand as command };

@ -3,6 +3,6 @@ import { command } from "../../utils/commandRegistration/slashCommandBuilder.js"
const name = "tags";
const description = "manage server tags";
const subcommand = await command(name, description, `tags`);
const subcommand: Awaited<ReturnType<typeof command>> = await command(name, description, `tags`);
export { name, description, subcommand as command };

@ -3,6 +3,6 @@ import { command } from "../../utils/commandRegistration/slashCommandBuilder.js"
const name = "ticket";
const description = "Manage modmail tickets";
const subcommand = await command(name, description, `ticket`);
const subcommand: Awaited<ReturnType<typeof command>> = await command(name, description, `ticket`);
export { name, description, subcommand as command };

@ -3,6 +3,6 @@ import { command } from "../../utils/commandRegistration/slashCommandBuilder.js"
const name = "user";
const description = "Commands for user info";
const subcommand = await command(name, description, `user`);
const subcommand: Awaited<ReturnType<typeof command>> = await command(name, description, `user`);
export { name, description, subcommand as command };

@ -2,7 +2,6 @@ import fs from "fs";
import * as readLine from "node:readline/promises";
const defaultDict: Record<string, string | string[] | boolean | Record<string, string | number | undefined>> = {
developmentToken: "Your development bot token (Used for testing in one server, rather than production)",
developmentGuildID: "Your development guild ID",
enableDevelopment: true,
token: "Your bot token",
@ -78,7 +77,7 @@ export default async function (walkthrough = false) {
}
if (Object.keys(json).length) {
if (json["token"] === defaultDict["token"] || json["developmentToken"] === defaultDict["developmentToken"]) {
if (json["token"] === defaultDict["token"]) {
console.log("\x1b[31m⚠ No main.ts found, creating one.");
console.log(
" \x1b[2mYou can edit src/config/main.ts directly using template written to the file.\x1b[0m\n"

@ -1,30 +0,0 @@
declare const config: {
developmentToken: string;
developmentGuildID: string;
enableDevelopment: boolean;
token: string;
managementGuildID: string;
owners: string[];
commandsFolder: string;
eventsFolder: string;
messageContextFolder: string;
userContextFolder: string;
verifySecret: string;
mongoOptions: {
username: string;
password: string;
database: string;
host: string;
authSource: string;
};
baseUrl: string;
clamav: {
socket?: string;
host?: string;
port?: number;
};
githubPAT: string;
suggestionChannel: string;
};
export default config;

@ -0,0 +1,56 @@
interface config {
developmentGuildID: string;
enableDevelopment: boolean;
token: string;
managementGuildID: string;
owners: string[];
commandsFolder: string;
eventsFolder: string;
messageContextFolder: string;
userContextFolder: string;
verifySecret: string;
mongoOptions: {
username: string;
password: string;
database: string;
host: string;
authSource: string;
};
baseUrl: string;
clamav: {
socket?: string;
host?: string;
port?: number;
};
githubPAT: string;
suggestionChannel: string;
};
export default {
"token": process.env["TOKEN"]!,
"managementGuildID": process.env["MANAGEMENT_GUILD_ID"]!,
"developmentGuildID": process.env["DEV_GUILD_ID"]!,
"enableDevelopment": process.env["ENABLE_DEV"] === "true",
"owners": process.env["OWNERS"]?.split(","),
"commandsFolder": process.env["COMMANDS_FOLDER"] ?? "dist/commands",
"eventsFolder": process.env["EVENTS_FOLDER"] ?? "dist/events",
"messageContextFolder": process.env["MESSAGE_CONTEXT_FOLDER"] ?? "dist/context/messages",
"userContextFolder": process.env["USER_CONTEXT_FOLDER"] ?? "dist/context/users",
"verifySecret": process.env["VERIFY_SECRET"]!,
"mongoOptions": {
"username": process.env["MONGO_USERNAME"]!,
"password": process.env["MONGO_PASSWORD"]!,
"host": process.env["MONGO_HOST"]!,
"database": process.env["MONGO_DATABASE"]!,
"authSource": process.env["MONGO_AUTH_SOURCE"]!,
},
"baseUrl": process.env["BASE_URL"]!,
"clamav": {
"host": process.env["CLAMAV_HOST"]!,
"port": parseInt(process.env["CLAMAV_PORT"] ?? "3310")
},
"githubPAT": process.env["GITHUB_PAT"]!,
"suggestionChannel": process.env["SUGGESTION_CHANNEL"]!,
} as config;

@ -4,10 +4,10 @@ import type { GuildAuditLogsEntry } from "discord.js";
import humanizeDuration from "humanize-duration";
import type { NucleusClient } from "../utils/client.js";
import getEmojiByName from "../utils/getEmojiByName.js";
import c from "../utils/client.js";
import client from "../utils/client.js";
import { capitalize } from "../utils/generateKeyValueList.js";
let entry = c.logger.entry;
let entry = client.logger.entry;
const channelTypeEmoji: Record<number, string> = {
0: "Text", // Text channel
@ -18,7 +18,10 @@ const channelTypeEmoji: Record<number, string> = {
99: "Rules" // Rules channel
};
interface channelChanges {
// this eslint rule is invalid here, as the type definition is actually incorrect
// if you make it an interface due to the [key: string]: unknown line. Try it if you like :)
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
type channelChanges = {
channelId: ReturnType<typeof entry>;
channel: ReturnType<typeof entry>;
edited: ReturnType<typeof entry>;
@ -37,11 +40,12 @@ interface channelChanges {
region?: ReturnType<typeof entry>;
maxUsers?: ReturnType<typeof entry>;
autoArchiveDuration?: ReturnType<typeof entry>;
}
[key: string]: unknown;
};
export const event = "channelUpdate";
export async function callback(client: NucleusClient, oldChannel: GuildChannel, newChannel: GuildChannel) {
export async function callback(_client: NucleusClient, oldChannel: GuildChannel, newChannel: GuildChannel) {
const { getAuditLog, log, isLogging, NucleusColors, renderDelta, renderUser, renderChannel } = client.logger;
if (!(await isLogging(newChannel.guild.id, "channelUpdate"))) return;
const config = await client.memory.readGuildInfo(newChannel.guild.id);

@ -24,6 +24,7 @@ import { callback as kickCallback, check as kickCheck } from "../commands/mod/ki
import { callback as muteCallback, check as muteCheck } from "../commands/mod/mute.js";
import { callback as nicknameCallback, check as nicknameCheck } from "../commands/mod/nick.js";
import { callback as warnCallback, check as warnCheck } from "../commands/mod/warn.js";
import { callback as logDetailsCallback } from "../actions/logs/showDetails.js";
import client from "../utils/client.js";
export const event = "interactionCreate";
@ -61,6 +62,9 @@ async function interactionCreate(interaction: Interaction) {
case "createtranscript": {
return await createTranscript(interaction);
}
case "log:showDetails": {
return await logDetailsCallback(interaction);
}
}
// Mod actions
if (interaction.customId.startsWith("mod:")) {

@ -1,5 +1,5 @@
import type { NucleusClient } from "../utils/client.js";
import type { Message, MessageReference } from "discord.js";
import { AttachmentBuilder, Message, MessageReference } from "discord.js";
import type Discord from "discord.js";
import * as diff from "diff";
@ -63,68 +63,88 @@ export async function callback(client: NucleusClient, oldMessage: Message, newMe
return;
}
const differences = diff.diffChars(oldContent, newContent);
console.log(differences);
let contentEdit = "";
if (differences.map((d) => (d.added || d.removed ? 1 : 0)).filter((f) => f === 1).length > 0) {
const green = "\x1B[36m";
const red = "\x1B[41m";
const skipped = "\x1B[40;33m";
const reset = "\x1B[0m";
const bold = "\x1B[1m";
const cutoff = 20;
differences.forEach((part) => {
if (!part.added && !part.removed && part.value.length > cutoff) {
contentEdit +=
reset +
part.value.slice(0, cutoff / 2) +
skipped +
`(${part.value.length - cutoff} more)` +
reset +
part.value.slice(-(cutoff / 2));
} else {
if (part.added || part.removed) {
part.value = part.value.replaceAll(" ", "▁");
}
contentEdit += (part.added ? green : part.removed ? red : reset) + part.value;
}
});
contentEdit = contentEdit.slice(0, 2000);
contentEdit += `\n\n${bold}Key:${reset} ${green}Added${reset} | ${red}Removed${reset} | ${skipped}Skipped${reset}`;
const data = {
meta: {
type: "messageUpdate",
displayName: "Message Edited",
calculateType: "messageUpdate",
color: NucleusColors.yellow,
emoji: "MESSAGE.EDIT",
timestamp: newMessage.editedTimestamp
},
separate: {
start: `\`\`\`ansi\n${contentEdit}\`\`\``,
end: `[[Jump to message]](${newMessage.url})`
},
list: {
messageId: entry(newMessage.id, `\`${newMessage.id}\``),
sentBy: entry(newMessage.author.id, renderUser(newMessage.author)),
sentIn: entry(newMessage.channel.id, renderChannel(newMessage.channel as Discord.GuildBasedChannel)),
sent: entry(newMessage.createdTimestamp, renderDelta(newMessage.createdTimestamp)),
edited: entry(newMessage.editedTimestamp, renderDelta(newMessage.editedTimestamp)),
mentions: renderNumberDelta(oldMessage.mentions.users.size, newMessage.mentions.users.size),
attachments: entry(
renderNumberDelta(oldMessage.attachments.size, newMessage.attachments.size),
renderNumberDelta(oldMessage.attachments.size, newMessage.attachments.size) + attachmentJump
),
repliedTo: entry(
replyTo ? replyTo.messageId! : null,
replyTo
? `[[Jump to message]](https://discord.com/channels/${newMessage.guild.id}/${newMessage.channel.id}/${replyTo.messageId})`
: "None"
)
},
hidden: {
guild: newMessage.guild.id
}
};
await log(data);
}
const green = "\x1B[36m";
const red = "\x1B[41m";
const skipped = "\x1B[40;33m";
const reset = "\x1B[0m";
const bold = "\x1B[1m";
// console.log(differences);
// let contentAdd = "";
// let contentRemove = "";
// if (differences.map((d) => (d.added || d.removed ? 1 : 0)).filter((f) => f === 1).length > 0) {
// const cutoff = 20;
// differences.forEach((part) => {
// if (!part.added && !part.removed && part.value.length > cutoff) {
// contentAdd +=
// reset +
// part.value.slice(0, cutoff / 2) +
// skipped +
// `(${part.value.length - cutoff} more)` +
// reset +
// part.value.slice(-(cutoff / 2));
// contentRemove +=
// reset +
// part.value.slice(0, cutoff / 2) +
// skipped +
// `(${part.value.length - cutoff} more)` +
// reset +
// part.value.slice(-(cutoff / 2));
// } else {
// if (part.added || part.removed) {
// part.value = part.value.replaceAll(" ", "▁");
// }
// if (part.added) {
// contentAdd += green + part.value + reset;
// } else if (part.removed) {
// contentRemove += red + part.value + reset;
// } else {
// contentAdd += part.value;
// contentRemove += part.value;
// }
// }
// });
const key = `\n\n${bold}Key:${reset} ${green}Added${reset} | ${red}Removed${reset} | ${skipped}Skipped${reset}`;
const data = {
meta: {
type: "messageUpdate",
displayName: "Message Edited",
calculateType: "messageUpdate",
color: NucleusColors.yellow,
emoji: "MESSAGE.EDIT",
timestamp: newMessage.editedTimestamp,
files: [
new AttachmentBuilder(Buffer.from(JSON.stringify(differences), "base64"), {
name: "diff.json",
description: "A JSON file containing the differences between the two messages."
})
],
showDetails: true
},
separate: {
start: `To read the full log press the button below.\n\`\`\`ansi\n${key}\`\`\``,
end: `[[Jump to message]](${newMessage.url})`
},
list: {
messageId: entry(newMessage.id, `\`${newMessage.id}\``),
sentBy: entry(newMessage.author.id, renderUser(newMessage.author)),
sentIn: entry(newMessage.channel.id, renderChannel(newMessage.channel as Discord.GuildBasedChannel)),
sent: entry(newMessage.createdTimestamp, renderDelta(newMessage.createdTimestamp)),
edited: entry(newMessage.editedTimestamp, renderDelta(newMessage.editedTimestamp)),
mentions: renderNumberDelta(oldMessage.mentions.users.size, newMessage.mentions.users.size),
attachments: entry(
renderNumberDelta(oldMessage.attachments.size, newMessage.attachments.size),
renderNumberDelta(oldMessage.attachments.size, newMessage.attachments.size) + attachmentJump
),
repliedTo: entry(
replyTo ? replyTo.messageId! : null,
replyTo
? `[[Jump to message]](https://discord.com/channels/${newMessage.guild.id}/${newMessage.channel.id}/${replyTo.messageId})`
: "None"
)
},
hidden: {
guild: newMessage.guild.id
}
};
await log(data);
}

@ -26,6 +26,6 @@ process.on("uncaughtException", (err) => {
console.error(err);
});
await client.login(config.enableDevelopment ? config.developmentToken : config.token);
await client.login(config.token);
await recordPerformance();

@ -1 +1 @@
Subproject commit f48264888bc1b2a805e4b20a5e5c82e11cb4754a
Subproject commit 9b0e45c13996b1b6bc96a3af3d3c4b67ad4e971f

@ -5,7 +5,7 @@ import Tesseract from "node-tesseract-ocr";
import type Discord from "discord.js";
import client from "../utils/client.js";
import { createHash } from "crypto";
import * as nsfwjs from "nsfwjs";
import * as nsfwjs from "@clicks/nsfwjs";
import ClamScan from "clamscan";
import * as tf from "@tensorflow/tfjs-node";
import EmojiEmbed from "../utils/generateEmojiEmbed.js";

@ -25,7 +25,7 @@ class NucleusClient extends Client {
scanCache: ScanCache;
transcripts: Transcript;
};
GitHub = new Octokit({ auth: config.githubPAT });
GitHub: Octokit = new Octokit({ auth: config.githubPAT });
preloadPage: Record<string, { command: string; argument: string }> = {}; // e.g. { channelID: { command: privacy, page: 3}}
commands: Record<
string,

@ -471,6 +471,7 @@ export class Transcript {
obj.style = child.style;
obj.label = child.label ?? "";
} else if (child.type > 2) {
// FIXME: Can we write this more clearly to make it obvious what we mean by 2 here?
obj.placeholder = child.placeholder ?? "";
}
return obj;

@ -1,10 +1,11 @@
import * as Discord from "discord.js";
import getEmojiByName from "./getEmojiByName.js";
import { toHexArray } from "./calculate.js";
import { promisify } from "util";
import generateKeyValueList from "./generateKeyValueList.js";
import client from "./client.js";
import { DiscordAPIError } from "discord.js";
import { Stream } from "node:stream";
import EmojiEmbed from "./generateEmojiEmbed.js";
const wait = promisify(setTimeout);
@ -16,9 +17,17 @@ export interface LoggerOptions {
color: number;
emoji: string;
timestamp: number;
files?: (
| Discord.BufferResolvable
| Stream
| Discord.JSONEncodable<Discord.APIAttachment>
| Discord.Attachment
| Discord.AttachmentBuilder
| Discord.AttachmentPayload
)[];
showDetails?: boolean;
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
list: any;
list: Record<string | symbol | number, unknown>;
hidden: {
guild: string;
};
@ -116,16 +125,31 @@ export const Logger = {
});
if (channel) {
log.separate = log.separate ?? {};
const embed = new Discord.EmbedBuilder()
.setTitle(`${getEmojiByName(log.meta.emoji)} ${log.meta.displayName}`)
.setDescription(
(log.separate.start ? log.separate.start + "\n" : "") +
generateKeyValueList(description) +
(log.separate.end ? "\n" + log.separate.end : "")
)
.setTimestamp(log.meta.timestamp)
.setColor(log.meta.color);
await channel.send({ embeds: [embed] });
const messageOptions: Parameters<Discord.TextChannel["send"]>[0] = {};
const components: Discord.ActionRowBuilder<Discord.ButtonBuilder> = new Discord.ActionRowBuilder();
messageOptions.embeds = [
new EmojiEmbed()
.setEmoji(log.meta.emoji)
.setTitle(log.meta.displayName)
.setDescription(
(log.separate.start ? log.separate.start + "\n" : "") +
generateKeyValueList(description) +
(log.separate.end ? "\n" + log.separate.end : "")
)
.setTimestamp(log.meta.timestamp)
.setColor(log.meta.color)
];
if (log.meta.files) messageOptions.files = log.meta.files;
if (log.meta.showDetails) {
components.addComponents(
new Discord.ButtonBuilder()
.setCustomId("log:showDetails")
.setLabel("Show Details")
.setStyle(Discord.ButtonStyle.Primary)
);
messageOptions.components = [components];
}
await channel.send(messageOptions);
}
}
},

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save