6 Commits

Author SHA1 Message Date
6db2c2d683 v3.3.1: configurable sync frequency 2024-02-15 03:47:05 -05:00
a9191e84a0 v3.3.0: IRC notifications 2024-02-14 03:22:09 -05:00
4a4e3d9614 update readme
closes #4
2024-02-13 17:19:35 -05:00
66f45cae07 package names link to Gitea
closes #1
2024-02-13 01:14:59 -05:00
91186f29ff create user cache dir 2024-02-11 18:38:09 -05:00
e148e79195 increase healthcheck timeout 2024-02-11 23:15:01 +00:00
15 changed files with 702 additions and 61 deletions

View File

@@ -18,7 +18,7 @@ FROM artixlinux/artixlinux:devel as deploy
VOLUME /usr/notifier/config
WORKDIR /usr/notifier
HEALTHCHECK --timeout=3s \
HEALTHCHECK --timeout=15m \
CMD curl --fail http://localhost:8080/healthcheck || exit 1
EXPOSE 8080
@@ -29,7 +29,10 @@ RUN pacman -Sy --noconfirm curl artools-pkg artix-checkupdates git nodejs npm op
COPY --from=build-env /usr/notifier /usr/notifier
RUN mkdir -p ./config /home/artix/.config/artix-checkupdates /home/artix/.config/artools && \
RUN mkdir -p ./config /home/artix/.config/artix-checkupdates \
/home/artix/.config/artools /home/artix/.cache/artix-checkupdates && \
ln -sf /usr/notifier/config/artools-pkg.conf /home/artix/.config/artools/artools-pkg.conf && \
ln -sf /usr/notifier/config/artix-checkupdates.conf /home/artix/.config/artix-checkupdates/config && \
chown -R artix:artix /home/artix/ && \
chown -R artix:artix .
@@ -41,4 +44,4 @@ ENV ARTIX_REPOS="system-goblins,world-goblins,galaxy-goblins,lib32-goblins,syste
ENV ARCH_REPOS="core-staging,extra-staging,multilib-staging,core-testing,extra-testing,multilib-testing,core,extra,multilib"
ENV GITEA_TOKEN="CHANGEME"
CMD ./startup.sh
CMD [ "node", "index.js"]

View File

@@ -1,25 +1,58 @@
# artix-packy-notifier
Notify me when one of my packages needs maintaining
Notification system and web frontend for Artix packages with pending operations. Notifications can be sent via
[Apprise](https://github.com/caronc/apprise/wiki#notification-services) or IRC. Web interface shows all packages with pending operations
and publishes prometheus metrics.
mount a folder to `/usr/volume`.
## configuration
Inside the volume, create a `packages.json` with the following schema:
create `config/config.json`:
| Variable | Description |
|-----------------|-----------------------------------------------------------------------------------------------------------------------|
| PREVIOUS | The path to store the generated list of actionable packages. Defaults to `previous.json` in the mounted volume. |
| packages | An array of packages to look for pending operations for. |
| writeAllPending | Boolean. If all pending packages should be included in the PREVIOUS file. Provided as `allPackages` and `allMovable`. |
| apprise.api | The url of the Apprise server to use for sending notifications. For example, "http://192.168.1.123:8000" |
| apprise.urls | An array of Apprise destination URLs to deliver notifications to. For example, "tgram://bot-token/chat-id" |
| apprise | The URL of the Apprise instance for sending notifications |
| maintainers | Array of maintainer names as strings or objects containing the `name` of the maintainer and a list of `channels` to send notifications to |
| cron | The cron schedule for when the application should check for pending operations via [artix-checkupdates](https://gitea.artixlinux.org/artix/artix-checkupdates) |
| syncfreq | How often (in days) should the application sync package ownership from Gitea |
| port | What port to run the webserver on (defaults to 8080) |
| savePath | Location of auxiliary save data (defaults to `config/data.db`) |
| db | Location of the SQLite DB (defaults to `config/packages.db`) |
| irc-framework | The options to feed into [irc-framework](https://github.com/kiwiirc/irc-framework/blob/master/docs/clientapi.md) |
| ircClient | Auxilary config data for the IRC bot. For now, it takes `ircClient.channel` and optionally `ircClient.channel_key` |
The following environment variables should be supplied.
Note that the IRC bot needs to be exempt from excess flooding. The following command permanently voices a bot on Libera.chat:
```
/msg ChanServ FLAGS #example artix-update-bot +V
```
If the channel is intended only for the bot to broadcast, consider setting the channel mode to "moderated":
```
/mode +m #example
```
| Variable | Description |
|--------------|--------------------------------------------|
| CRON | The cron schedule for checking for updates |
| ARTIX_MIRROR | The Artix mirror to use |
| ARCH_MIRROR | The Arch mirror to use |
| ARTIX_REPOS | The Artix repos to check |
| ARCH_REPOS | The Arch repos to check |
## How to run
```
npm install
node index.js
```
## Docker Setup
Image : `registry.gitlab.com/sanin.dev/artix-packy-notifier`
mount a folder to `/usr/notifier/config`.
Include a `config.json` as described above.
Include `artools-pkg.conf`:
```
GIT_TOKEN='YOUR-GITEA-TOKEN-HERE'
```
Include `artix-checkupdates.conf`:
```
ARTIX_MIRROR=https://example.com/%s/os/x86_64
ARCH_MIRROR=https://example.com/%s/os/x86_64
ARTIX_REPOS=system-goblins,world-goblins,galaxy-goblins,lib32-goblins,system-gremlins,world-gremlins,galaxy-gremlins,lib32-gremlins,system,world,galaxy,lib32
ARCH_REPOS=core-staging,extra-staging,multilib-staging,core-testing,extra-testing,multilib-testing,core,extra,multilib
```

View File

@@ -16,7 +16,7 @@
<linearGradient xlink:href="#b" id="d" x1="105.834" x2="80.209" y1="15.354" y2="30.531" gradientTransform="translate(-56.383 115.378)" gradientUnits="userSpaceOnUse"/>
<linearGradient xlink:href="#a" id="c" x1="75.543" x2="81.2" y1="145.986" y2="143.227" gradientTransform="translate(-16.572 -7.109)" gradientUnits="userSpaceOnUse"/>
</defs>
<path fill="#10a0cc" stroke-width=".1" d="m23.362 0-8.034 16.474 22.112 12.39zM12.901 21.45.574 46.726l36.578-15.111zm26.955 12.368L28.32 40.441l17.832 6.284z"/>
<path class="artix-logo-base" fill="#10a0cc" stroke-width=".1" d="m23.362 0-8.034 16.474 22.112 12.39zM12.901 21.45.574 46.726l36.578-15.111zm26.955 12.368L28.32 40.441l17.832 6.284z"/>
<path fill="url(#c)" stroke-width=".265" d="m58.971 138.877 4.138-5.876 6.295 12.908z" transform="translate(-23.253 -99.183)"/>
<path fill="url(#d)" stroke-width=".265" d="m23.826 145.909 25.626-15.177 10.952.065z" transform="translate(-23.253 -99.183)"/>
<path fill="url(#e)" stroke-width=".265" d="m60.693 128.047-22.112-12.39 5.744-2.213z" transform="translate(-23.253 -99.183)"/>

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -6,6 +6,7 @@ const dayjs = require('dayjs');
const json5 = require('json5');
const phin = require('phin');
const DB = require('./db');
const IRCBot = require('./ircbot');
const Web = require('./web');
const fsp = fs.promises;
@@ -23,6 +24,7 @@ let saveData = {
}
let cronjob;
let ircBot;
let savePath = process.env.SAVEPATH || path.join(__dirname, 'config', 'data.json');
@@ -50,7 +52,15 @@ fs.readFile(process.env.CONFIGPATH || path.join(__dirname, 'config', 'config.jso
main(config, db);
});
process.on('SIGTERM', (new Web(db, config, saveData)).close);
const web = new Web(db, config, saveData);
ircBot = new IRCBot(config);
ircBot.connect();
process.on('SIGTERM', () => {
cronjob.stop();
web.close();
ircBot.clouse();
});
}
});
@@ -58,10 +68,12 @@ async function main(config, db) {
console.log('Starting scheduled task');
cronjob.stop();
let now = dayjs();
if (!('last-sync' in saveData) || !saveData['last-sync'] || dayjs(saveData['last-sync']).isBefore(now.subtract(3, 'days'))) {
if (!('last-sync' in saveData) || !saveData['last-sync'] || dayjs(saveData['last-sync']).isBefore(now.subtract(process.env.SYNCFREQ || config.syncfreq || 2, 'days'))) {
ircBot.close();
await updateMaintainers(config, db);
saveData['last-sync'] = now.toJSON();
await writeSaveData();
await ircBot.connect();
}
await checkupdates(config, db);
await writeSaveData();
@@ -90,13 +102,17 @@ async function handleUpdates(config, db, packs, type) {
});
for (let i = 0; i < config.maintainers.length; i++) {
let m = config.maintainers[i];
const m = config.maintainers[i];
const mname = typeof m === 'object' ? m.name : m;
const ircName = typeof m === 'object' ? (m.ircName || mname) : m;
const packages = db.getNewByMaintainer(mname, type);
if (typeof m === 'object') {
notify({
api: config.apprise,
urls: m.channels
}, db.getNewByMaintainer(m.name, type), NICETYPES[type])
}, packages, NICETYPES[type])
}
ircNotify(packages, ircName, NICETYPES[type]);
}
db.decrementFlags(type);
@@ -153,9 +169,10 @@ function getMaintainersPackages(maintainer) {
}
async function notify(apprise, packarr, type) {
if (!(packarr && packarr.length)) {
if (!(packarr && packarr.length && apprise && apprise.api && apprise.urls)) {
return;
}
const packagesStr = packarr.map(p => p.package).join('\n');
for (let i = 0; i < 25; i++) {
try {
return await phin({
@@ -163,7 +180,7 @@ async function notify(apprise, packarr, type) {
method: 'POST',
data: {
title: `${packarr[0].maintainer}: packages ready to ${type}`,
body: packarr.map(p => p.package).join('\n'),
body: packagesStr,
urls: apprise.urls.join(',')
}
});
@@ -176,6 +193,23 @@ async function notify(apprise, packarr, type) {
return null;
}
function ircNotify(packarr, maintainer, type) {
if (!(packarr && packarr.length)) {
return;
}
const packagesStr = packarr.map(p => p.package).join('\n');
for (let i = 0; i < 25; i++) {
try {
return ircBot.sendMessage(`${maintainer}: packages ready to ${type}\n${packagesStr}\n-------- EOF --------`);
}
catch (ex) {
console.error('Failed to send IRC notification, attempt #%d', i + 1);
console.error(ex);
}
}
return null;
}
function parseCheckUpdatesOutput(output) {
let packages = [];
let lines = output.split('\n');

61
ircbot.js Normal file
View File

@@ -0,0 +1,61 @@
const IRC = require('irc-framework');
class IRCBot {
constructor(config) {
const options = config['irc-framework'];
const aux = this._aux = config.ircClient || {};
this._channel = aux.channel;
this._messageQueue = [];
if (options) {
const bot = this._bot = new IRC.Client(options);
bot.on('sasl failed', d => console.error(d));
bot.on('notice', d => console.log(`irc:notice: ${d.message}`));
bot.on('action', d => console.log(`irc:action: ${d.message}`));
setInterval(() => this.processMessageQueue(), 2000);
}
}
connect() {
return new Promise((resolve, reject) => {
const bot = this._bot;
bot.connect();
const callback = () => {
clearTimeout(timeout);
console.log(`IRC bot ${bot.user.nick} connected.`);
bot.join(this._aux.channel, this._aux.channel_key);
bot.removeListener('registered', callback);
resolve();
};
const timeout = setTimeout(() => {
bot.removeListener('registered', callback);
reject('timeout exceeded');
}, 60000);
bot.on('registered', callback);
});
}
sendMessage(str) {
str.split('\n').forEach(line => {
this._messageQueue.push(line);
});
}
processMessageQueue() {
const bot = this._bot
let message = bot.connected && this._messageQueue.shift();
message && bot.say(this._channel, message);
}
close() {
if (this._bot.connected) {
this._bot.quit('Shutting down');
}
}
}
module.exports = IRCBot;

474
package-lock.json generated
View File

@@ -1,18 +1,19 @@
{
"name": "artix-packy-notifier",
"version": "3.0.0",
"version": "3.3.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "artix-packy-notifier",
"version": "3.0.0",
"version": "3.3.1",
"license": "MIT",
"dependencies": {
"better-sqlite3": "9.4.0",
"dayjs": "1.11.10",
"ejs": "3.1.9",
"express": "4.18.2",
"irc-framework": "4.13.1",
"json5": "2.2.3",
"node-cron": "3.0.3",
"phin": "^3.7.0",
@@ -81,6 +82,17 @@
"resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz",
"integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg=="
},
"node_modules/available-typed-arrays": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.6.tgz",
"integrity": "sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg==",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -341,6 +353,16 @@
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
},
"node_modules/core-js": {
"version": "3.35.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.35.1.tgz",
"integrity": "sha512-IgdsbxNyMskrTFxa9lWHyMwAJU5gXOPP+1yO+K59d50VLVAIDAbs7gIv705KzALModfK3ZrSZTPNpC0PQgIZuw==",
"hasInstallScript": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/core-js"
}
},
"node_modules/css-tree": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz",
@@ -498,6 +520,11 @@
"node": ">= 0.6"
}
},
"node_modules/eventemitter3": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
"integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="
},
"node_modules/expand-template": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
@@ -547,6 +574,11 @@
"node": ">= 0.10.0"
}
},
"node_modules/fast-text-encoding": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz",
"integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w=="
},
"node_modules/file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
@@ -608,6 +640,14 @@
"node": ">= 0.8"
}
},
"node_modules/for-each": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
"integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
"dependencies": {
"is-callable": "^1.1.3"
}
},
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@@ -697,6 +737,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/grapheme-splitter": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
"integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ=="
},
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -738,6 +783,20 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-tostringtag": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"dependencies": {
"has-symbols": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/hasown": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz",
@@ -810,6 +869,18 @@
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
},
"node_modules/ip-address": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
"integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
"dependencies": {
"jsbn": "1.1.0",
"sprintf-js": "^1.1.3"
},
"engines": {
"node": ">= 12"
}
},
"node_modules/ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
@@ -818,6 +889,74 @@
"node": ">= 0.10"
}
},
"node_modules/irc-framework": {
"version": "4.13.1",
"resolved": "https://registry.npmjs.org/irc-framework/-/irc-framework-4.13.1.tgz",
"integrity": "sha512-oUdNyc5CLwYjsp5AP479EgdMMTepwYK9kury7sWzMV6IeMyKc6fExk6tnhN/jTWpiDKsYtbPAb01wE7yVtLcsQ==",
"dependencies": {
"buffer": "^6.0.3",
"core-js": "^3.27.2",
"eventemitter3": "^5.0.0",
"grapheme-splitter": "^1.0.4",
"iconv-lite": "^0.6.3",
"isomorphic-textencoder": "^1.0.1",
"lodash": "^4.17.21",
"middleware-handler": "^0.2.0",
"regenerator-runtime": "^0.13.11",
"socks": "^2.7.1",
"stream-browserify": "^3.0.0",
"util": "^0.12.5"
}
},
"node_modules/irc-framework/node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"node_modules/irc-framework/node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-arguments": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
"integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
"dependencies": {
"call-bind": "^1.0.2",
"has-tostringtag": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@@ -830,6 +969,17 @@
"node": ">=8"
}
},
"node_modules/is-callable": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -839,6 +989,20 @@
"node": ">=0.10.0"
}
},
"node_modules/is-generator-function": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
"integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
"dependencies": {
"has-tostringtag": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
@@ -860,6 +1024,28 @@
"node": ">=0.12.0"
}
},
"node_modules/is-typed-array": {
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz",
"integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==",
"dependencies": {
"which-typed-array": "^1.1.14"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/isomorphic-textencoder": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/isomorphic-textencoder/-/isomorphic-textencoder-1.0.1.tgz",
"integrity": "sha512-676hESgHullDdHDsj469hr+7t3i/neBKU9J7q1T4RHaWwLAsaQnywC0D1dIUId0YZ+JtVrShzuBk1soo0+GVcQ==",
"dependencies": {
"fast-text-encoding": "^1.0.0"
}
},
"node_modules/jake": {
"version": "10.8.7",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz",
@@ -877,6 +1063,11 @@
"node": ">=10"
}
},
"node_modules/jsbn": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
"integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A=="
},
"node_modules/json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
@@ -888,6 +1079,11 @@
"node": ">=6"
}
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
@@ -926,6 +1122,11 @@
"node": ">= 0.6"
}
},
"node_modules/middleware-handler": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/middleware-handler/-/middleware-handler-0.2.0.tgz",
"integrity": "sha512-Qz4B0yWndSokapr3Kl7fpMRysS0DaBlOuATrExFuZbr+oXZ3rsAPufdLe8mUJXiG5A4aJGW6GfKS4PDfQwu7Mg=="
},
"node_modules/mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
@@ -1236,6 +1437,11 @@
"node": ">=8.10.0"
}
},
"node_modules/regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -1414,6 +1620,28 @@
"simple-concat": "^1.0.0"
}
},
"node_modules/smart-buffer": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
"engines": {
"node": ">= 6.0.0",
"npm": ">= 3.0.0"
}
},
"node_modules/socks": {
"version": "2.7.3",
"resolved": "https://registry.npmjs.org/socks/-/socks-2.7.3.tgz",
"integrity": "sha512-vfuYK48HXCTFD03G/1/zkIls3Ebr2YNa4qU9gHDZdblHLiqhJrJGkY3+0Nx0JpN9qBhJbVObc1CNciT1bIZJxw==",
"dependencies": {
"ip-address": "^9.0.5",
"smart-buffer": "^4.2.0"
},
"engines": {
"node": ">= 10.0.0",
"npm": ">= 3.0.0"
}
},
"node_modules/source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
@@ -1423,6 +1651,11 @@
"node": ">=0.10.0"
}
},
"node_modules/sprintf-js": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="
},
"node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
@@ -1431,6 +1664,15 @@
"node": ">= 0.8"
}
},
"node_modules/stream-browserify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz",
"integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==",
"dependencies": {
"inherits": "~2.0.4",
"readable-stream": "^3.5.0"
}
},
"node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@@ -1555,6 +1797,18 @@
"node": ">= 0.8"
}
},
"node_modules/util": {
"version": "0.12.5",
"resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz",
"integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==",
"dependencies": {
"inherits": "^2.0.3",
"is-arguments": "^1.0.4",
"is-generator-function": "^1.0.7",
"is-typed-array": "^1.1.3",
"which-typed-array": "^1.1.2"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -1584,6 +1838,24 @@
"node": ">= 0.8"
}
},
"node_modules/which-typed-array": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz",
"integrity": "sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==",
"dependencies": {
"available-typed-arrays": "^1.0.6",
"call-bind": "^1.0.5",
"for-each": "^0.3.3",
"gopd": "^1.0.1",
"has-tostringtag": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
@@ -1638,6 +1910,11 @@
"resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz",
"integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg=="
},
"available-typed-arrays": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.6.tgz",
"integrity": "sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg=="
},
"balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -1824,6 +2101,11 @@
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
},
"core-js": {
"version": "3.35.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.35.1.tgz",
"integrity": "sha512-IgdsbxNyMskrTFxa9lWHyMwAJU5gXOPP+1yO+K59d50VLVAIDAbs7gIv705KzALModfK3ZrSZTPNpC0PQgIZuw=="
},
"css-tree": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz",
@@ -1936,6 +2218,11 @@
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="
},
"eventemitter3": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
"integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="
},
"expand-template": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
@@ -1979,6 +2266,11 @@
"vary": "~1.1.2"
}
},
"fast-text-encoding": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz",
"integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w=="
},
"file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
@@ -2033,6 +2325,14 @@
"unpipe": "~1.0.0"
}
},
"for-each": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
"integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
"requires": {
"is-callable": "^1.1.3"
}
},
"forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@@ -2094,6 +2394,11 @@
"get-intrinsic": "^1.1.3"
}
},
"grapheme-splitter": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
"integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ=="
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -2117,6 +2422,14 @@
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
},
"has-tostringtag": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"requires": {
"has-symbols": "^1.0.3"
}
},
"hasown": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz",
@@ -2166,11 +2479,67 @@
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
},
"ip-address": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
"integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
"requires": {
"jsbn": "1.1.0",
"sprintf-js": "^1.1.3"
}
},
"ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
},
"irc-framework": {
"version": "4.13.1",
"resolved": "https://registry.npmjs.org/irc-framework/-/irc-framework-4.13.1.tgz",
"integrity": "sha512-oUdNyc5CLwYjsp5AP479EgdMMTepwYK9kury7sWzMV6IeMyKc6fExk6tnhN/jTWpiDKsYtbPAb01wE7yVtLcsQ==",
"requires": {
"buffer": "^6.0.3",
"core-js": "^3.27.2",
"eventemitter3": "^5.0.0",
"grapheme-splitter": "^1.0.4",
"iconv-lite": "^0.6.3",
"isomorphic-textencoder": "^1.0.1",
"lodash": "^4.17.21",
"middleware-handler": "^0.2.0",
"regenerator-runtime": "^0.13.11",
"socks": "^2.7.1",
"stream-browserify": "^3.0.0",
"util": "^0.12.5"
},
"dependencies": {
"buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"requires": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"requires": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
}
}
}
},
"is-arguments": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
"integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
"requires": {
"call-bind": "^1.0.2",
"has-tostringtag": "^1.0.0"
}
},
"is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@@ -2180,12 +2549,25 @@
"binary-extensions": "^2.0.0"
}
},
"is-callable": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="
},
"is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"dev": true
},
"is-generator-function": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
"integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
"requires": {
"has-tostringtag": "^1.0.0"
}
},
"is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
@@ -2201,6 +2583,22 @@
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true
},
"is-typed-array": {
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz",
"integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==",
"requires": {
"which-typed-array": "^1.1.14"
}
},
"isomorphic-textencoder": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/isomorphic-textencoder/-/isomorphic-textencoder-1.0.1.tgz",
"integrity": "sha512-676hESgHullDdHDsj469hr+7t3i/neBKU9J7q1T4RHaWwLAsaQnywC0D1dIUId0YZ+JtVrShzuBk1soo0+GVcQ==",
"requires": {
"fast-text-encoding": "^1.0.0"
}
},
"jake": {
"version": "10.8.7",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz",
@@ -2212,11 +2610,21 @@
"minimatch": "^3.1.2"
}
},
"jsbn": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
"integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A=="
},
"json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="
},
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
@@ -2246,6 +2654,11 @@
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
"integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="
},
"middleware-handler": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/middleware-handler/-/middleware-handler-0.2.0.tgz",
"integrity": "sha512-Qz4B0yWndSokapr3Kl7fpMRysS0DaBlOuATrExFuZbr+oXZ3rsAPufdLe8mUJXiG5A4aJGW6GfKS4PDfQwu7Mg=="
},
"mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
@@ -2469,6 +2882,11 @@
"picomatch": "^2.2.1"
}
},
"regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
},
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -2580,17 +2998,45 @@
"simple-concat": "^1.0.0"
}
},
"smart-buffer": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="
},
"socks": {
"version": "2.7.3",
"resolved": "https://registry.npmjs.org/socks/-/socks-2.7.3.tgz",
"integrity": "sha512-vfuYK48HXCTFD03G/1/zkIls3Ebr2YNa4qU9gHDZdblHLiqhJrJGkY3+0Nx0JpN9qBhJbVObc1CNciT1bIZJxw==",
"requires": {
"ip-address": "^9.0.5",
"smart-buffer": "^4.2.0"
}
},
"source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"dev": true
},
"sprintf-js": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="
},
"statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
},
"stream-browserify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz",
"integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==",
"requires": {
"inherits": "~2.0.4",
"readable-stream": "^3.5.0"
}
},
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@@ -2685,6 +3131,18 @@
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="
},
"util": {
"version": "0.12.5",
"resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz",
"integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==",
"requires": {
"inherits": "^2.0.3",
"is-arguments": "^1.0.4",
"is-generator-function": "^1.0.7",
"is-typed-array": "^1.1.3",
"which-typed-array": "^1.1.2"
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -2705,6 +3163,18 @@
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
},
"which-typed-array": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz",
"integrity": "sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==",
"requires": {
"available-typed-arrays": "^1.0.6",
"call-bind": "^1.0.5",
"for-each": "^0.3.3",
"gopd": "^1.0.1",
"has-tostringtag": "^1.0.1"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",

View File

@@ -1,6 +1,6 @@
{
"name": "artix-packy-notifier",
"version": "3.0.0",
"version": "3.3.1",
"description": "Determine packages that need attention",
"main": "index.js",
"scripts": {
@@ -27,6 +27,7 @@
"dayjs": "1.11.10",
"ejs": "3.1.9",
"express": "4.18.2",
"irc-framework": "4.13.1",
"json5": "2.2.3",
"node-cron": "3.0.3",
"phin": "^3.7.0",

View File

@@ -1,4 +0,0 @@
#!/bin/bash
printf "GIT_TOKEN=$GITEA_TOKEN\n" > ~/.config/artools/artools-pkg.conf
printf "ARTIX_MIRROR=$ARTIX_MIRROR\nARCH_MIRROR=$ARCH_MIRROR\nARTIX_REPOS=$ARTIX_REPOS\nARCH_REPOS=$ARCH_REPOS" "%s" "%s" > ~/.config/artix-checkupdates/config && \
node index.js

View File

@@ -97,6 +97,10 @@ header {
a:hover,
a:focus {
text-decoration: none;
&.logo svg .artix-logo-base {
fill: #53bffc;
}
}
a.logo {
@@ -137,6 +141,15 @@ header {
footer {
font-size: 9pt;
ul li {
display: inline-block;
padding: 0 1em 0 0;
}
}
table tr td:last-child {
min-width: 6em;
}
.container {
@@ -167,6 +180,10 @@ footer {
}
@media screen and (max-width:270px) {
footer ul li {
display: block;
}
header nav ul li {
display: block;
@@ -174,4 +191,10 @@ footer {
display: block;
}
}
html,
body {
font-size: 1em;
line-height: 1.1em;
}
}

View File

@@ -1,5 +1,9 @@
<div class="container bg">
<footer>
© <%= (new Date()).getFullYear() %> Artix Linux
<ul>
<li>© <%= (new Date()).getFullYear() %> Artix Linux</li>
<li>Developed by Cory Sanin</li>
<li><a href="https://gitea.artixlinux.org/corysanin/artix-packy-notifier">Source</a></li>
</ul>
</footer>
</div>

View File

@@ -9,6 +9,6 @@
<meta name="apple-mobile-web-app-title" content="Artix Checkupdates">
<meta name="application-name" content="Artix Checkupdates">
<meta name="theme-color" content="#212121">
<link rel="stylesheet" href="/assets/css/styles.css?v=1">
<link rel="stylesheet" href="/assets/css/styles.css?v=2">
<link rel="shortcut icon" href="/assets/svg/artix_logo.svg">
</head>

View File

@@ -9,7 +9,7 @@
<li><a href="https://artixlinux.org/">Artix Linux</a></li>
<li><a href="https://forum.artixlinux.org/">Forum</a></li>
<li><a href="https://wiki.artixlinux.org/">Wiki</a></li>
<li><a href="https://gitea.artixlinux.org/">Sources</a></li>
<li><a href="https://gitea.artixlinux.org/explore/repos">Sources</a></li>
</ul>
</nav>
</header>

View File

@@ -16,16 +16,10 @@
<th>Package</th>
<th>Action</th>
</tr>
<% savedata.move && savedata.move.forEach(p => { %>
<% packages && packages.forEach(p => { %>
<tr>
<td><%= p %></td>
<td>Move</td>
</tr>
<% }); %>
<% savedata.update && savedata.update.forEach(p => { %>
<tr>
<td><%= p %></td>
<td>Update</td>
<td><a href="<%= p.url %>"><%= p.package %></a></td>
<td><%= p.action %></td>
</tr>
<% }); %>
</table>

View File

@@ -12,16 +12,10 @@
<th>Package</th>
<th>Action</th>
</tr>
<% moves && moves.forEach(p => { %>
<% packages && packages.forEach(p => { %>
<tr>
<td><%= p.package %></td>
<td>Move</td>
</tr>
<% }); %>
<% updates && updates.forEach(p => { %>
<tr>
<td><%= p.package %></td>
<td>Update</td>
<td><a href="<%= p.url %>"><%= p.package.package %></a></td>
<td><%= p.action %></td>
</tr>
<% }); %>
</table>

42
web.js
View File

@@ -7,11 +7,32 @@ const PROJECT_ROOT = __dirname;
const VIEWOPTIONS = {
outputFunctionName: 'echo'
};
const NAMECOMPLIANCE = [
p => p.replace(/([a-zA-Z0-9]+)\+([a-zA-Z]+)/g, '$1-$2'),
p => p.replace(/\+/g, "plus"),
p => p.replace(/[^a-zA-Z0-9_\-\.]/g, "-"),
p => p.replace(/[_\-]{2,}/g, "-")
]
function inliner(file) {
return fs.readFileSync(path.join(PROJECT_ROOT, file));
}
function packageUrl(p) {
let packagename = typeof p === 'string' ? p : p.package;
return `https://gitea.artixlinux.org/packages/${NAMECOMPLIANCE.reduce((s, fn) => fn(s), packagename)}`;
}
function prepPackages(arr, action) {
return arr.map(m => {
return {
package: m,
action,
url: packageUrl(m)
}
});
}
class Web {
constructor(db, options, savedata) {
const app = express();
@@ -23,7 +44,8 @@ class Web {
app.set('view engine', 'ejs');
app.set('view options', VIEWOPTIONS);
function sendError(res, status, description) {
function sendError(req, res, status, description) {
console.log(`${status} (${description}): ${req.url} requested by ${req.ip} "${req.headers['user-agent']}"`);
res.render('error',
{
inliner,
@@ -51,6 +73,8 @@ class Web {
});
app.get('/', async (_, res) => {
let packages = prepPackages(savedata.move, 'Move');
packages = packages.concat(prepPackages(savedata.update, 'Update'));
res.render('index',
{
inliner,
@@ -58,7 +82,7 @@ class Web {
prefix: 'Artix Checkupdates',
suffix: 'Web Edition'
},
savedata,
packages,
maintainers: maintainers
},
function (err, html) {
@@ -67,7 +91,7 @@ class Web {
}
else {
console.error(err);
sendError(res, 500, 'Something went wrong. Try again later.');
sendError(req, res, 500, 'Something went wrong. Try again later.');
}
}
);
@@ -76,6 +100,8 @@ class Web {
app.get('/maintainer/:maintainer', async (req, res) => {
const maintainer = req.params.maintainer;
const packagesOwned = db.getMaintainerPackageCount(maintainer);
let packages = prepPackages(db.getPackagesByMaintainer(maintainer, 'move'), 'Move');
packages = packages.concat(prepPackages(db.getPackagesByMaintainer(maintainer, 'udate'), 'Update'));
if (packagesOwned > 0) {
res.render('maintainer',
{
@@ -86,8 +112,7 @@ class Web {
},
maintainer,
packagesOwned,
moves: db.getPackagesByMaintainer(maintainer, 'move'),
updates: db.getPackagesByMaintainer(maintainer, 'udate'),
packages
},
function (err, html) {
if (!err) {
@@ -101,7 +126,7 @@ class Web {
);
}
else {
sendError(res, 404, 'File not found');
sendError(req, res, 404, 'File not found');
}
});
@@ -156,7 +181,8 @@ class Web {
res.end(await register.metrics());
}
catch (ex) {
res.status(500).send(ex);
console.error(err);
res.status(500).send('something went wrong.');
}
});
@@ -164,6 +190,8 @@ class Web {
maxAge: '30d'
}));
app.use((req, res) => sendError(req, res, 404, 'File not found'));
this._webserver = app.listen(port, () => console.log(`artix-packy-notifier-web running on port ${port}`));
}