diff --git a/.vscode/settings.json b/.vscode/settings.json
index 61015ef..9f1e183 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,11 +1,5 @@
{
"editor.insertSpaces": false,
"editor.detectIndentation": false,
- "editor.tabSize": 3,
- "[jade]": {
- "editor.stickyScroll.enabled": true,
- "editor.stickyScroll.maxLineCount": 6,
- "editor.tabSize": 2,
- "editor.insertSpaces": true
- }
+ "editor.tabSize": 3
}
diff --git a/docs/developer-orientation.md b/docs/developer-orientation.md
index 839b4af..0f5e0c0 100644
--- a/docs/developer-orientation.md
+++ b/docs/developer-orientation.md
@@ -89,14 +89,14 @@ Whether you read those or not, I'm more than happy to help you 1-on-1 with codin
# Dependency justification
-Total transitive production dependencies: 112
+Total transitive production dependencies: 144
### 🦕
+* (35) better-sqlite3: SQLite is the best database, and this is the best library for it.
* (29) sharp: Image resizing and compositing. OOYE needs this for the emoji sprite sheets. It has libvips prebuilts for each platform.
* (26) @cloudrac3r/pug: Language for dynamic web pages. This is my fork. (I released code that hadn't made it to npm, and removed the heavy pug-filters feature.)
* (9) h3: Web server. OOYE needs this for the web UI, appservice listener, authmedia proxy, and more.
-* (1) better-sqlite3: SQLite is the best database, and this is the best library for it.
### 🪱
@@ -120,7 +120,6 @@ Total transitive production dependencies: 112
* (0) entities: Looks fine. No dependencies.
* (0) get-relative-path: Looks fine. No dependencies.
* (1) heatsync: Module hot-reloader that I trust.
-* (0) htmx.org: Declarative partial page reloads that do just enough. I'm not totally happy with this one, but not sure what I'd do instead.
* (0) lru-cache: For holding unused nonce in memory and letting them be overwritten later if never used.
* (1) mime-types: List of mime type mappings. Needed to serve static files.
* (0) prettier-bytes: It does what I want and has no dependencies.
@@ -129,18 +128,3 @@ Total transitive production dependencies: 112
* (0) uqr: QR code SVG generator. Used on the website to scan in an invite link.
* (0) xxhash-wasm: Used where cryptographically secure hashing is not required.
* (0) zod: Input validation for the web server. It's popular and easy to use.
-
-### Outdated versions
-
-* @chriscdn/promise-semaphore
- * Highest usable version is 3.1.3 because the author **dropped CJS** in 4.0.0.
-* @stackoverflow/stacks
- * Highest usable version is 2.9.0 (and 6.9.0 for stacks-icons) because the company **ruined their design** in 3.0.0.
-* cross-env
- * Highest usable version is 7.0.3 because the author **dropped CJS** in 10.0.0.
-* entities
- * Using version 5.0.0. The author messed things up in 6.0.0, started using LLMs in 7.0.0, and **dropped CJS** in 8.0.0.
-* h3
- * Using major version 1. Version 2 has been stuck as **release candidates for months**, and all the code comments are Claude.
-* htmx.org
- * Using major version 2. Version 4 exists, and **I'd be okay updating to it**, but the author changed a lot and the entire site would need to be re-tested.
diff --git a/package-lock.json b/package-lock.json
index d9ff5cb..ee24410 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,7 +22,7 @@
"@stackoverflow/stacks": "^2.5.4",
"@stackoverflow/stacks-icons": "^6.0.2",
"ansi-colors": "^4.1.3",
- "better-sqlite3": "^13.0.3",
+ "better-sqlite3": "^12.2.0",
"chunk-text": "^2.0.1",
"cloudstorm": "^0.19.0",
"denque": "^2.1.0",
@@ -32,10 +32,10 @@
"entities": "^5.0.0",
"get-relative-path": "^1.0.2",
"h3": "^1.15.10",
- "heatsync": "^3.3.0",
+ "heatsync": "^2.7.2",
"htmx.org": "^2.0.4",
"lru-cache": "^11.0.2",
- "mime-types": "^3.0.2",
+ "mime-types": "^2.1.35",
"prettier-bytes": "^1.0.4",
"sharp": "^0.35.3",
"snowtransfer": "^0.19.0",
@@ -47,7 +47,7 @@
"devDependencies": {
"@cloudrac3r/tap-dot": "^2.0.3",
"@types/node": "^22.17.1",
- "c8": "^12.0.0",
+ "c8": "^11.0.0",
"cross-env": "^7.0.3",
"supertape": "^13.2.0"
},
@@ -909,9 +909,9 @@
"license": "MIT"
},
"node_modules/@stackoverflow/stacks": {
- "version": "2.9.0",
- "resolved": "https://registry.npmjs.org/@stackoverflow/stacks/-/stacks-2.9.0.tgz",
- "integrity": "sha512-6VX9GTYFqsBFaelZ0sJ9YGZDa+1eLjr6Dh8r6cIh02SA/BcocWe0lxNZTcLpBQEKtX/9A0jTRsY3Au0BXcFJWQ==",
+ "version": "2.8.6",
+ "resolved": "https://registry.npmjs.org/@stackoverflow/stacks/-/stacks-2.8.6.tgz",
+ "integrity": "sha512-pR0vMDBA5rNV5Cb/McG+2F1nG68fZk3UiNwuOvQrP82WoQy41k9PsBjRjD7wHDVVZyDrWHLb/WnosXX7uK3IdA==",
"dependencies": {
"@hotwired/stimulus": "^3.2.2",
"@popperjs/core": "^2.11.8"
@@ -1039,9 +1039,9 @@
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "22.20.2",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.2.tgz",
- "integrity": "sha512-xlvWf4Vs9n1PEVYwP1n4vvG07M6y8WgvJ2t0vbrWTmijsIHp1cS+uJ2kMIRdY3nHZK0nCYKrPeD171+SzF4/zw==",
+ "version": "22.20.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.1.tgz",
+ "integrity": "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1129,9 +1129,9 @@
}
},
"node_modules/backtracker": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/backtracker/-/backtracker-5.1.1.tgz",
- "integrity": "sha512-+/rMk2Eyzc/k6AqguRxdlUVOzMmyjUqavmICnwI5XGNBpbKLxAu5Bps3G7yRvxCg0b5zc5crZoSgpPTo9i5lbQ==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/backtracker/-/backtracker-5.0.0.tgz",
+ "integrity": "sha512-2rY1s1iMlF1FVb4jpIMxTeGE+KRppuVvPyU61q7gvap1MWVahToUI8WUqy+v3L37iip5a4mJOTRBZxNRbTv4bg==",
"license": "MIT"
},
"node_modules/balanced-match": {
@@ -1144,17 +1144,58 @@
"node": "18 || 20 || >=22"
}
},
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
"node_modules/better-sqlite3": {
- "version": "13.0.3",
- "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-13.0.3.tgz",
- "integrity": "sha512-RbOBxmLBG8uvFUc15X9+9SFemKcQ0WBuISBVkpuiaUB2qblC8UWlHEjdWVoZ8AdhSwmoEgsiXKfopX0CQxaACQ==",
+ "version": "12.10.0",
+ "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.10.0.tgz",
+ "integrity": "sha512-CyzaZRQKyHkB2ZInfTTl2nvT33EbDpjkLEbE8/Zck3Ll6O0qqvuGdrJ45HgtH+HykRg88ITY3AdreBGN70aBSQ==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
- "node-addon-api": "^8.0.0"
+ "bindings": "^1.5.0",
+ "prebuild-install": "^7.1.1"
},
"engines": {
- "node": ">=22"
+ "node": "20.x || 22.x || 23.x || 24.x || 25.x || 26.x"
+ }
+ },
+ "node_modules/bindings": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+ "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+ "license": "MIT",
+ "dependencies": {
+ "file-uri-to-path": "1.0.0"
+ }
+ },
+ "node_modules/bl": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+ "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+ "license": "MIT",
+ "dependencies": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
}
},
"node_modules/brace-expansion": {
@@ -1170,10 +1211,34 @@
"node": "20 || >=22"
}
},
+ "node_modules/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
"node_modules/c8": {
- "version": "12.0.0",
- "resolved": "https://registry.npmjs.org/c8/-/c8-12.0.0.tgz",
- "integrity": "sha512-4zpJvrd1nKWutnnKC2pXkFmb6iM1l+ffN//o1CzlTNwW7GSOs9a1xrLqkC48nU8oEkjmPZLPiwMsIaOvoF4Pqg==",
+ "version": "11.0.0",
+ "resolved": "https://registry.npmjs.org/c8/-/c8-11.0.0.tgz",
+ "integrity": "sha512-e/uRViGHSVIJv7zsaDKM7VRn2390TgHXqUSvYwPHBQaU6L7E9L0n9JbdkwdYPvshDT0KymBmmlwSpms3yBaMNg==",
"dev": true,
"license": "ISC",
"dependencies": {
@@ -1186,14 +1251,14 @@
"istanbul-reports": "^3.1.6",
"test-exclude": "^8.0.0",
"v8-to-istanbul": "^9.0.0",
- "yargs": "^18.0.0",
+ "yargs": "^17.7.2",
"yargs-parser": "^21.1.1"
},
"bin": {
"c8": "bin/c8.js"
},
"engines": {
- "node": "^20.19.0 || ^22.12.0 || >=23"
+ "node": "20 || >=22"
},
"peerDependencies": {
"monocart-coverage-reports": "^2"
@@ -1223,6 +1288,12 @@
"integrity": "sha512-jWburCrDpd+aPopB7esjh/gLyZoHZS4C2xwwJlkTPyhhJdXG+FCG0P4qCOInvOd9yhiuAEJYlZsUMQ0JSK4ykw==",
"license": "MIT"
},
+ "node_modules/chownr": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
+ "license": "ISC"
+ },
"node_modules/chunk-text": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/chunk-text/-/chunk-text-2.0.1.tgz",
@@ -1266,72 +1337,18 @@
}
},
"node_modules/cliui": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz",
- "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
"dev": true,
"license": "ISC",
"dependencies": {
- "string-width": "^7.2.0",
- "strip-ansi": "^7.1.0",
- "wrap-ansi": "^9.0.0"
- },
- "engines": {
- "node": ">=20"
- }
- },
- "node_modules/cliui/node_modules/ansi-regex": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz",
- "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-regex?sponsor=1"
- }
- },
- "node_modules/cliui/node_modules/emoji-regex": {
- "version": "10.6.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
- "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/cliui/node_modules/string-width": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
- "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "emoji-regex": "^10.3.0",
- "get-east-asian-width": "^1.0.0",
- "strip-ansi": "^7.1.0"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/cliui/node_modules/strip-ansi": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
- "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^6.2.2"
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
},
"engines": {
"node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/strip-ansi?sponsor=1"
}
},
"node_modules/cloudstorm": {
@@ -1446,6 +1463,30 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/decompress-response": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+ "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "mimic-response": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/deep-extend": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
"node_modules/defu": {
"version": "6.1.7",
"resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz",
@@ -1477,10 +1518,13 @@
}
},
"node_modules/discord-api-types": {
- "version": "0.38.55",
- "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.38.55.tgz",
- "integrity": "sha512-ytuaRTzdnHUCXJ6KjL9MrItQX0xKncBKEeYI1Bst4+ud47eejH3cG6gaesYakjpPcUhh68XYS2YwGq3mmujFsA==",
- "license": "MIT"
+ "version": "0.38.53",
+ "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.38.53.tgz",
+ "integrity": "sha512-HL1zz/UuZ+bbJjA/X8Kbxx9gk8v9rJAbTeWRNYKmIdjwJ7EovjlHgoJTxcLpATfNJ+AonOtMdy3Y5MVIJAAd/A==",
+ "license": "MIT",
+ "workspaces": [
+ "scripts/actions/documentation"
+ ]
},
"node_modules/doctypes": {
"version": "1.1.0",
@@ -1489,9 +1533,9 @@
"license": "MIT"
},
"node_modules/domino": {
- "version": "2.1.8",
- "resolved": "https://registry.npmjs.org/domino/-/domino-2.1.8.tgz",
- "integrity": "sha512-qLkTcPRkqvifAB0bweVznkWgAu2hwin8An+HbLy0bH1ZtMyJzwXiHKMhynwR1Wq4PgBvEyg2Y749j4JJnlfDKg==",
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/domino/-/domino-2.1.7.tgz",
+ "integrity": "sha512-3rcXhx0ixJV2nj8J0tljzejTF73A35LVVdnTQu79UAqTBFEgYPMgGtykMuu/BDqaOZphATku1ddRUn/RtqUHYQ==",
"license": "BSD-2-Clause"
},
"node_modules/emoji-regex": {
@@ -1501,6 +1545,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/end-of-stream": {
+ "version": "1.4.5",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
+ "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
+ "license": "MIT",
+ "dependencies": {
+ "once": "^1.4.0"
+ }
+ },
"node_modules/enquirer": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz",
@@ -1536,6 +1589,15 @@
"node": ">=6"
}
},
+ "node_modules/expand-template": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
+ "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
+ "license": "(MIT OR WTFPL)",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/fastest-levenshtein": {
"version": "1.0.16",
"resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
@@ -1546,6 +1608,12 @@
"node": ">= 4.9.1"
}
},
+ "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",
+ "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
+ "license": "MIT"
+ },
"node_modules/find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@@ -1587,6 +1655,12 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/fs-constants": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
+ "license": "MIT"
+ },
"node_modules/fullstore": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/fullstore/-/fullstore-4.0.2.tgz",
@@ -1617,19 +1691,6 @@
"node": "6.* || 8.* || >= 10.*"
}
},
- "node_modules/get-east-asian-width": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz",
- "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/get-relative-path": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/get-relative-path/-/get-relative-path-1.0.2.tgz",
@@ -1647,6 +1708,12 @@
"source-map": "^0.6.1"
}
},
+ "node_modules/github-from-package": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
+ "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
+ "license": "MIT"
+ },
"node_modules/glob": {
"version": "13.0.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz",
@@ -1706,15 +1773,15 @@
}
},
"node_modules/heatsync": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/heatsync/-/heatsync-3.3.0.tgz",
- "integrity": "sha512-9qkijny0a9lo0He103na+sGVx8YRcDKizfGNBahkx5OX6LmeR8njNOftRFSCuSRkNqrNWuxRFOOVKIiY0FsEVQ==",
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/heatsync/-/heatsync-2.8.3.tgz",
+ "integrity": "sha512-9pVRC3BZD1NZ0EYnU5akjoO10+s/aJc04QqUxgtBqAYUeberV8st0ctWH7selEnyU8OEAUKZhBCFxmH7MvCQQQ==",
"license": "MIT",
"dependencies": {
- "backtracker": "^5.1.1"
+ "backtracker": "^5.0.0"
},
"engines": {
- "node": ">=20.6.0"
+ "node": ">=14.6.0"
}
},
"node_modules/html-es6cape": {
@@ -1736,6 +1803,38 @@
"integrity": "sha512-kdeJe7ZVwaS6QMz/ebBIVtZdpwen6L0OQ5GOhPV9MKBb196TCZeZu4yA7ZIQsaLKv7EpXz+So7KSXNuHXhj7Cw==",
"license": "0BSD"
},
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "license": "ISC"
+ },
+ "node_modules/ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+ "license": "ISC"
+ },
"node_modules/iron-webcrypto": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz",
@@ -1920,9 +2019,9 @@
}
},
"node_modules/lru-cache": {
- "version": "11.5.2",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz",
- "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==",
+ "version": "11.5.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.0.tgz",
+ "integrity": "sha512-5YgH9UJd7wVb9hIouI2adWpgqrrICkt070Dnj8EUY1+B4B2P9eRLPAkAAo6NICA7CEhOIeBHl46u9zSNpNu7zA==",
"license": "BlueOak-1.0.0",
"engines": {
"node": "20 || >=22"
@@ -1945,28 +2044,36 @@
}
},
"node_modules/mime-db": {
- "version": "1.54.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
- "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
- "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"license": "MIT",
"dependencies": {
- "mime-db": "^1.54.0"
+ "mime-db": "1.52.0"
},
"engines": {
- "node": ">=18"
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mimic-response": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+ "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/minimatch": {
@@ -1985,6 +2092,15 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/minipass": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
@@ -1995,13 +2111,28 @@
"node": ">=16 || 14 >=14.17"
}
},
- "node_modules/node-addon-api": {
- "version": "8.9.2",
- "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.9.2.tgz",
- "integrity": "sha512-VijLXbi3UACN69I0JVXJsX4tjACjNoQDgv2gTF6sx2wWEi8tkSg2eX8p5gSIFi8z2+DL3oHmY6OyKce38SDolg==",
+ "node_modules/mkdirp-classic": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
+ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
+ "license": "MIT"
+ },
+ "node_modules/napi-build-utils": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
+ "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==",
+ "license": "MIT"
+ },
+ "node_modules/node-abi": {
+ "version": "3.89.0",
+ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.89.0.tgz",
+ "integrity": "sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA==",
"license": "MIT",
+ "dependencies": {
+ "semver": "^7.3.5"
+ },
"engines": {
- "node": "^18 || ^20 || >= 21"
+ "node": ">=10"
}
},
"node_modules/node-mock-http": {
@@ -2023,7 +2154,6 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
- "dev": true,
"license": "ISC",
"dependencies": {
"wrappy": "1"
@@ -2105,6 +2235,33 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/prebuild-install": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz",
+ "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
+ "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.",
+ "license": "MIT",
+ "dependencies": {
+ "detect-libc": "^2.0.0",
+ "expand-template": "^2.0.3",
+ "github-from-package": "0.0.0",
+ "minimist": "^1.2.3",
+ "mkdirp-classic": "^0.5.3",
+ "napi-build-utils": "^2.0.0",
+ "node-abi": "^3.3.0",
+ "pump": "^3.0.0",
+ "rc": "^1.2.7",
+ "simple-get": "^4.0.0",
+ "tar-fs": "^2.0.0",
+ "tunnel-agent": "^0.6.0"
+ },
+ "bin": {
+ "prebuild-install": "bin.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/prettier-bytes": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/prettier-bytes/-/prettier-bytes-1.0.4.tgz",
@@ -2201,12 +2358,37 @@
"integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==",
"license": "MIT"
},
+ "node_modules/pump": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz",
+ "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==",
+ "license": "MIT",
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
"node_modules/radix3": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz",
"integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==",
"license": "MIT"
},
+ "node_modules/rc": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+ "license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
+ "dependencies": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ },
+ "bin": {
+ "rc": "cli.js"
+ }
+ },
"node_modules/re-emitter": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/re-emitter/-/re-emitter-1.1.4.tgz",
@@ -2221,6 +2403,30 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "license": "MIT",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/resolve": {
"version": "1.22.11",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
@@ -2251,6 +2457,26 @@
"node": ">=4.0.0"
}
},
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
"node_modules/semver": {
"version": "7.8.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
@@ -2348,6 +2574,51 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/simple-concat": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
+ "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/simple-get": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
+ "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "decompress-response": "^6.0.0",
+ "once": "^1.3.1",
+ "simple-concat": "^1.0.0"
+ }
+ },
"node_modules/simple-markdown": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/simple-markdown/-/simple-markdown-0.7.3.tgz",
@@ -2400,6 +2671,15 @@
"get-source": "^2.0.12"
}
},
+ "node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -2427,10 +2707,19 @@
"node": ">=8"
}
},
+ "node_modules/strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/supertape": {
- "version": "13.6.0",
- "resolved": "https://registry.npmjs.org/supertape/-/supertape-13.6.0.tgz",
- "integrity": "sha512-W/lm1wk370QF0u+LrxS+BMUFNYMfRgjFC9dTKyFB522fa77pKJHwOBDiTl3uhNbsw0Sb1NQPRYk+eFICcqxedA==",
+ "version": "13.2.0",
+ "resolved": "https://registry.npmjs.org/supertape/-/supertape-13.2.0.tgz",
+ "integrity": "sha512-UoxZnyoMOdSJHvbcmD8i28MaGXsA7I0cJ0jr8anT4CkmfaE9M1y5mt9EoXyzfC8UdnQZwXOnJLUwqyKLAeUOug==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2503,6 +2792,34 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/tar-fs": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
+ "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "chownr": "^1.1.1",
+ "mkdirp-classic": "^0.5.2",
+ "pump": "^3.0.0",
+ "tar-stream": "^2.1.4"
+ }
+ },
+ "node_modules/tar-stream": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+ "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+ "license": "MIT",
+ "dependencies": {
+ "bl": "^4.0.3",
+ "end-of-stream": "^1.4.1",
+ "fs-constants": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/test-exclude": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-8.0.0.tgz",
@@ -2557,6 +2874,18 @@
"license": "0BSD",
"optional": true
},
+ "node_modules/tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/ufo": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz",
@@ -2582,6 +2911,12 @@
"integrity": "sha512-0rjE8iEJe4YmT9TOhwsZtqCMRLc5DXZUI2UEYUUg63ikBkqqE5EYWaI0etFe/5KUcmcYwLih2RND1kq+hrUJXA==",
"license": "MIT"
},
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "license": "MIT"
+ },
"node_modules/v8-to-istanbul": {
"version": "9.3.0",
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz",
@@ -2638,95 +2973,43 @@
}
},
"node_modules/wrap-ansi": {
- "version": "9.0.2",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz",
- "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"license": "MIT",
"dependencies": {
- "ansi-styles": "^6.2.1",
- "string-width": "^7.0.0",
- "strip-ansi": "^7.1.0"
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
},
"engines": {
- "node": ">=18"
+ "node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
- "node_modules/wrap-ansi/node_modules/ansi-regex": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz",
- "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-regex?sponsor=1"
- }
- },
"node_modules/wrap-ansi/node_modules/ansi-styles": {
- "version": "6.2.3",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
- "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
"engines": {
- "node": ">=12"
+ "node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
- "node_modules/wrap-ansi/node_modules/emoji-regex": {
- "version": "10.6.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
- "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/wrap-ansi/node_modules/string-width": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
- "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "emoji-regex": "^10.3.0",
- "get-east-asian-width": "^1.0.0",
- "strip-ansi": "^7.1.0"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/wrap-ansi/node_modules/strip-ansi": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
- "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^6.2.2"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/strip-ansi?sponsor=1"
- }
- },
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
- "dev": true,
"license": "ISC"
},
"node_modules/wraptile": {
@@ -2753,21 +3036,22 @@
}
},
"node_modules/yargs": {
- "version": "18.1.0",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.1.0.tgz",
- "integrity": "sha512-2rAgRKu54VsHkqI0/tYkmluGXHD4KW7yZoycuqDQ15QOTnc2VVfy0nN/1eMhnQLO00A+dwtK20xuCnc1YGeUyg==",
+ "version": "17.7.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+ "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
"dev": true,
"license": "MIT",
"dependencies": {
- "cliui": "^9.0.1",
+ "cliui": "^8.0.1",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
- "string-width": "^8.2.1",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
"y18n": "^5.0.5",
- "yargs-parser": "^22.0.0"
+ "yargs-parser": "^21.1.1"
},
"engines": {
- "node": "^20.19.0 || ^22.12.0 || >=23"
+ "node": ">=12"
}
},
"node_modules/yargs-parser": {
@@ -2780,62 +3064,6 @@
"node": ">=12"
}
},
- "node_modules/yargs/node_modules/ansi-regex": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz",
- "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-regex?sponsor=1"
- }
- },
- "node_modules/yargs/node_modules/string-width": {
- "version": "8.2.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.2.tgz",
- "integrity": "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "get-east-asian-width": "^1.5.0",
- "strip-ansi": "^7.1.2"
- },
- "engines": {
- "node": ">=20"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/yargs/node_modules/strip-ansi": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
- "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^6.2.2"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/strip-ansi?sponsor=1"
- }
- },
- "node_modules/yargs/node_modules/yargs-parser": {
- "version": "22.0.0",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz",
- "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==",
- "dev": true,
- "license": "ISC",
- "engines": {
- "node": "^20.19.0 || ^22.12.0 || >=23"
- }
- },
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
@@ -2850,9 +3078,9 @@
}
},
"node_modules/zod": {
- "version": "4.6.5",
- "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.5.tgz",
- "integrity": "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==",
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
+ "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
diff --git a/package.json b/package.json
index 5fbf928..00f11b7 100644
--- a/package.json
+++ b/package.json
@@ -31,7 +31,7 @@
"@stackoverflow/stacks": "^2.5.4",
"@stackoverflow/stacks-icons": "^6.0.2",
"ansi-colors": "^4.1.3",
- "better-sqlite3": "^13.0.3",
+ "better-sqlite3": "^12.2.0",
"chunk-text": "^2.0.1",
"cloudstorm": "^0.19.0",
"denque": "^2.1.0",
@@ -41,10 +41,10 @@
"entities": "^5.0.0",
"get-relative-path": "^1.0.2",
"h3": "^1.15.10",
- "heatsync": "^3.3.0",
+ "heatsync": "^2.7.2",
"htmx.org": "^2.0.4",
"lru-cache": "^11.0.2",
- "mime-types": "^3.0.2",
+ "mime-types": "^2.1.35",
"prettier-bytes": "^1.0.4",
"sharp": "^0.35.3",
"snowtransfer": "^0.19.0",
@@ -59,7 +59,7 @@
"devDependencies": {
"@cloudrac3r/tap-dot": "^2.0.3",
"@types/node": "^22.17.1",
- "c8": "^12.0.0",
+ "c8": "^11.0.0",
"cross-env": "^7.0.3",
"supertape": "^13.2.0"
},
diff --git a/scripts/start-server.js b/scripts/start-server.js
index 883333d..44edbcb 100755
--- a/scripts/start-server.js
+++ b/scripts/start-server.js
@@ -1,6 +1,9 @@
#!/usr/bin/env node
// @ts-check
+const {createServer} = require("http")
+const EventEmitter = require("events")
+const {createApp, createRouter, toNodeListener} = require("h3")
const sqlite = require("better-sqlite3")
const migrate = require("../src/db/migrate")
const HeatSync = require("heatsync")
@@ -13,10 +16,6 @@ const sync = new HeatSync()
Object.assign(passthrough, {sync, db})
-const orm = sync.require("../src/db/orm")
-passthrough.from = orm.from
-passthrough.select = orm.select
-
const DiscordClient = require("../src/d2m/discord-client")
const discord = new DiscordClient(reg.ooye.discord_token, "half")
@@ -25,6 +24,10 @@ passthrough.discord = discord
const {as} = require("../src/matrix/appservice")
passthrough.as = as
+const orm = sync.require("../src/db/orm")
+passthrough.from = orm.from
+passthrough.select = orm.select
+
;(async () => {
await migrate.migrate(db)
await discord.cloud.connect()
diff --git a/src/d2m/actions/register-webhook-user.js b/src/d2m/actions/register-webhook-user.js
index f016843..145eeb8 100644
--- a/src/d2m/actions/register-webhook-user.js
+++ b/src/d2m/actions/register-webhook-user.js
@@ -1,6 +1,6 @@
// @ts-check
-const assert = require("assert").strict
+const assert = require("assert")
const {reg} = require("../../matrix/read-registration")
const Ty = require("../../types")
diff --git a/src/d2m/converters/find-mentions.js b/src/d2m/converters/find-mentions.js
index e9c51c5..5135d17 100644
--- a/src/d2m/converters/find-mentions.js
+++ b/src/d2m/converters/find-mentions.js
@@ -1,6 +1,6 @@
// @ts-check
-const assert = require("assert").strict
+const assert = require("assert")
const {reg} = require("../../matrix/read-registration")
const userRegex = reg.namespaces.users.map(u => new RegExp(u.regex))
diff --git a/src/d2m/converters/lottie.js b/src/d2m/converters/lottie.js
index 6641958..969d345 100644
--- a/src/d2m/converters/lottie.js
+++ b/src/d2m/converters/lottie.js
@@ -1,6 +1,6 @@
// @ts-check
-const assert = require("assert").strict
+const assert = require("assert")
const stream = require("stream")
const {PNG} = require("@cloudrac3r/pngjs")
diff --git a/src/d2m/converters/user-to-mxid.js b/src/d2m/converters/user-to-mxid.js
index fb37aa1..7705aff 100644
--- a/src/d2m/converters/user-to-mxid.js
+++ b/src/d2m/converters/user-to-mxid.js
@@ -1,6 +1,6 @@
// @ts-check
-const assert = require("assert").strict
+const assert = require("assert")
const {reg} = require("../../matrix/read-registration")
const Ty = require("../../types")
@@ -66,7 +66,7 @@ function userToSimName(user) {
// 1. Is sim user already registered?
const existing = select("sim", "user_id", {user_id: user.id}).pluck().get()
- assert.equal(existing, undefined, "Shouldn't try to create a new name for an existing sim")
+ assert.equal(existing, null, "Shouldn't try to create a new name for an existing sim")
// 2. Register based on username (could be new or old format)
// (Unless it's a special user, in which case copy their provided mappings.)
@@ -113,7 +113,7 @@ function webhookAuthorToSimName(author) {
// 1. Is sim user already registered?
const fakeUserID = webhookAuthorToFakeUserID(author)
const existing = select("sim", "user_id", {user_id: fakeUserID}).pluck().get()
- assert.equal(existing, undefined, "Shouldn't try to create a new name for an existing sim")
+ assert.equal(existing, null, "Shouldn't try to create a new name for an existing sim")
// 2. Register based on username (could be new or old format)
const downcased = "webhook_" + downcaseUsername(author)
diff --git a/src/d2m/discord-packets.js b/src/d2m/discord-packets.js
index 9f3b291..992689f 100644
--- a/src/d2m/discord-packets.js
+++ b/src/d2m/discord-packets.js
@@ -74,10 +74,6 @@ async function onPacket(client, message, listen) {
const firstReady = guildReadyStatus.allReady()
const lastGuildReady = guildReadyStatus.makeReady(message.d.id)
- if (lastGuildReady) {
- console.log(`ok, ${client.guilds.size} available.`)
- }
-
const arr = []
client.guildChannelMap.set(message.d.id, arr)
for (const channel of message.d.channels || []) {
@@ -97,7 +93,7 @@ async function onPacket(client, message, listen) {
try {
// Wait for guilds to be connected and homeserver to be online. If this is the last guild, a different code path is used to trigger the homeserver check.
if (lastGuildReady) {
- process.stdout.write(`Connecting to homeserver... `)
+ process.stdout.write(`ok, ${client.guilds.size} available.\nConnecting to homeserver... `)
// await guildReadyStatus.waitForAllReady() - no need, we already checked this is the last guild
await homeserverStatus.homeserverStatus.waitForOnline(true)
console.log("ok.\nReplaying past events. Welcome to Out Of Your Element.")
diff --git a/src/js/errors.js b/src/js/errors.js
deleted file mode 100644
index 7770772..0000000
--- a/src/js/errors.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * This function is adapted from Evan Kaufman's fantastic work.
- * The original function and my adapted function are both MIT licensed.
- * @url https://github.com/EvanK/npm-loggable-error/
- * @param {number} [depth]
- * @returns {string}
-*/
-function stringifyErrorStack(err, depth = 0) {
- let collapsed = " ".repeat(depth);
- if (!(err instanceof Error)) {
- return collapsed + err
- }
-
- // add full stack trace if one exists, otherwise convert to string
- let stackLines = String(err?.stack ?? err).replace(/^/gm, " ".repeat(depth)).trim().split("\n")
- let cloudstormLine = stackLines.findIndex(l => l.includes("/node_modules/cloudstorm/"))
- if (cloudstormLine !== -1) {
- stackLines = stackLines.slice(0, cloudstormLine - 2)
- }
- collapsed += stackLines.join("\n")
-
- const props = Object.getOwnPropertyNames(err).filter(p => !["message", "stack"].includes(p))
-
- // only break into object notation if we have additional props to dump
- if (props.length) {
- const dedent = " ".repeat(depth);
- const indent = " ".repeat(depth + 2);
-
- collapsed += " {\n";
-
- // loop and print each (indented) prop name
- for (let property of props) {
- collapsed += `${indent}[${property}]: `;
-
- // if another error object, stringify it too
- if (err[property] instanceof Error) {
- collapsed += stringifyErrorStack(err[property], depth + 2).trimStart();
- }
- // otherwise stringify as JSON
- else {
- collapsed += JSON.stringify(err[property]);
- }
-
- collapsed += "\n";
- }
-
- collapsed += `${dedent}}\n`;
- }
-
- return collapsed;
-}
-
-module.exports.stringifyErrorStack = stringifyErrorStack
diff --git a/src/js/errors.test.js b/src/js/errors.test.js
deleted file mode 100644
index ddff7d3..0000000
--- a/src/js/errors.test.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// @ts-check
-
-const {test} = require("supertape")
-const {stringifyErrorStack} = require("./errors")
-
-test("stringify error stack: works", t => {
- function a() {
- const e = new Error("message", {cause: new Error("inner")})
- // @ts-ignore
- e.prop = 2.1
- throw e
- }
- try {
- a()
- t.fail("shouldn't get here")
- } catch (e) {
- const str = stringifyErrorStack(e)
- t.match(str, /^Error: message$/m)
- t.match(str, /^ at a \(.*errors\.test\.js/m)
- t.match(str, /^ \[cause\]: Error: inner$/m)
- t.match(str, /^ \[prop\]: 2.1$/m)
- }
-})
diff --git a/src/m2d/converters/event-to-message.js b/src/m2d/converters/event-to-message.js
index 5fe1109..a017e99 100644
--- a/src/m2d/converters/event-to-message.js
+++ b/src/m2d/converters/event-to-message.js
@@ -620,7 +620,7 @@ async function eventToMessage(event, guild, channel, di) {
let filename = event.content.filename || event.content.body
if (!filename) {
const extension = mimeTypes.extension(event.content.info?.mimetype)
- assert(extension, "Filename and mimetype missing. Please report this bug to your client.")
+ if (!extension) throw new Error("Filename and mimetype missing. Please report this bug to your client.")
filename = `file.${extension}`
}
diff --git a/src/m2d/converters/event-to-message.test.js b/src/m2d/converters/event-to-message.test.js
index b262a37..6b22773 100644
--- a/src/m2d/converters/event-to-message.test.js
+++ b/src/m2d/converters/event-to-message.test.js
@@ -4816,39 +4816,6 @@ test("event2message: image attachments can have a formatted caption", async t =>
)
})
-test("event2message: attachments have a generated filename if it was missing", async t => {
- t.deepEqual(
- await eventToMessage({
- type: "m.room.message",
- sender: "@cadence:cadence.moe",
- content: {
- body: "",
- filename: "",
- info: {
- mimetype: "image/png",
- size: 50832
- },
- msgtype: "m.image",
- url: "mxc://agiadn.org/3SvzETkab3XBDM6HCMJxpOryIDxMO31j"
- },
- event_id: "$CXQy3Wmg1A-gL_xAesC1HQcQTEXwICLdSwwUx55FBTI",
- room_id: "!BnKuBPCvyfOkhcUjEu:cadence.moe"
- }),
- {
- ensureJoined: [],
- messagesToDelete: [],
- messagesToEdit: [],
- messagesToSend: [{
- username: "cadence [they]",
- content: "",
- avatar_url: "https://bridge.example.org/download/matrix/cadence.moe/azCAhThKTojXSZJRoWwZmhvU?preset=avatar",
- attachments: [{id: "0", filename: "file.png"}],
- pendingFiles: [{name: "file.png", mxc: "mxc://agiadn.org/3SvzETkab3XBDM6HCMJxpOryIDxMO31j"}]
- }]
- }
- )
-})
-
test("event2message: encrypted image attachments work", async t => {
t.deepEqual(
await eventToMessage({
diff --git a/src/m2d/event-dispatcher.js b/src/m2d/event-dispatcher.js
index f6f414a..0560f46 100644
--- a/src/m2d/event-dispatcher.js
+++ b/src/m2d/event-dispatcher.js
@@ -38,12 +38,62 @@ const retrigger = sync.require("../d2m/actions/retrigger")
const homeserverStatus = sync.require("../matrix/homeserver-status")
/** @type {import("./actions/typing")} */
const typing = sync.require("./actions/typing")
-/** @type {import("../js/errors")} */
-const errors = sync.require("../js/errors")
const {reg} = require("../matrix/read-registration")
let lastReportedEvent = 0
+/**
+ * This function is adapted from Evan Kaufman's fantastic work.
+ * The original function and my adapted function are both MIT licensed.
+ * @url https://github.com/EvanK/npm-loggable-error/
+ * @param {number} [depth]
+ * @returns {string}
+*/
+function stringifyErrorStack(err, depth = 0) {
+ let collapsed = " ".repeat(depth);
+ if (!(err instanceof Error)) {
+ return collapsed + err
+ }
+
+ // add full stack trace if one exists, otherwise convert to string
+ let stackLines = String(err?.stack ?? err).replace(/^/gm, " ".repeat(depth)).trim().split("\n")
+ let cloudstormLine = stackLines.findIndex(l => l.includes("/node_modules/cloudstorm/"))
+ if (cloudstormLine !== -1) {
+ stackLines = stackLines.slice(0, cloudstormLine - 2)
+ }
+ collapsed += stackLines.join("\n")
+
+ const props = Object.getOwnPropertyNames(err).filter(p => !["message", "stack"].includes(p))
+
+ // only break into object notation if we have additional props to dump
+ if (props.length) {
+ const dedent = " ".repeat(depth);
+ const indent = " ".repeat(depth + 2);
+
+ collapsed += " {\n";
+
+ // loop and print each (indented) prop name
+ for (let property of props) {
+ collapsed += `${indent}[${property}]: `;
+
+ // if another error object, stringify it too
+ if (err[property] instanceof Error) {
+ collapsed += stringifyErrorStack(err[property], depth + 2).trimStart();
+ }
+ // otherwise stringify as JSON
+ else {
+ collapsed += JSON.stringify(err[property]);
+ }
+
+ collapsed += "\n";
+ }
+
+ collapsed += `${dedent}}\n`;
+ }
+
+ return collapsed;
+}
+
function printError(type, source, e, payload) {
console.error(`Error while processing a ${type} ${source} event:`)
console.error(e)
@@ -95,7 +145,7 @@ async function sendError(roomID, source, type, e, payload) {
builder.addLine(errorIntroLine)
// Where
- const stack = cleanErrorStack(errors.stringifyErrorStack(e))
+ const stack = cleanErrorStack(stringifyErrorStack(e))
builder.addLine(`Error trace:\n${stack}`, tag`Error trace
${stack} `)
// How
@@ -493,6 +543,7 @@ async event => {
}
}))
+module.exports.stringifyErrorStack = stringifyErrorStack
module.exports.cleanErrorStack = cleanErrorStack
module.exports.sendError = sendError
module.exports.printError = printError
diff --git a/src/m2d/event-dispatcher.test.js b/src/m2d/event-dispatcher.test.js
index 302b33b..2de6381 100644
--- a/src/m2d/event-dispatcher.test.js
+++ b/src/m2d/event-dispatcher.test.js
@@ -1,7 +1,26 @@
// @ts-check
const {test} = require("supertape")
-const {cleanErrorStack} = require("./event-dispatcher")
+const {stringifyErrorStack, cleanErrorStack} = require("./event-dispatcher")
+
+test("stringify error stack: works", t => {
+ function a() {
+ const e = new Error("message", {cause: new Error("inner")})
+ // @ts-ignore
+ e.prop = 2.1
+ throw e
+ }
+ try {
+ a()
+ t.fail("shouldn't get here")
+ } catch (e) {
+ const str = stringifyErrorStack(e)
+ t.match(str, /^Error: message$/m)
+ t.match(str, /^ at a \(.*event-dispatcher\.test\.js/m)
+ t.match(str, /^ \[cause\]: Error: inner$/m)
+ t.match(str, /^ \[prop\]: 2.1$/m)
+ }
+})
test("clean error stack: removes webhook token", t => {
t.notMatch(
diff --git a/src/matrix/homeserver-status.js b/src/matrix/homeserver-status.js
index 6d0ea76..da38ac2 100644
--- a/src/matrix/homeserver-status.js
+++ b/src/matrix/homeserver-status.js
@@ -1,6 +1,6 @@
// @ts-check
-const assert = require("assert").strict
+const assert = require("assert")
const Denque = require("denque")
const StateMachine = require("snowtransfer").StateMachine
diff --git a/src/stdin.js b/src/stdin.js
index 6e35e78..43f9607 100644
--- a/src/stdin.js
+++ b/src/stdin.js
@@ -7,7 +7,6 @@ const {addbot} = require("../addbot")
const passthrough = require("./passthrough")
const {discord, sync, db, select, from, as} = passthrough
-const reg = require("./matrix/read-registration")
const data = sync.require("../test/data")
const createSpace = sync.require("./d2m/actions/create-space")
const createRoom = sync.require("./d2m/actions/create-room")
diff --git a/src/web/pug-sync.js b/src/web/pug-sync.js
index cca90c2..e61c53b 100644
--- a/src/web/pug-sync.js
+++ b/src/web/pug-sync.js
@@ -2,24 +2,20 @@
const assert = require("assert/strict")
const fs = require("fs")
-const util = require("util")
const {join} = require("path")
const getRelativePath = require("get-relative-path")
const h3 = require("h3")
-const {defineEventHandler, defaultContentType, setResponseStatus, getQuery, getRequestURL} = h3
+const {defineEventHandler, defaultContentType, setResponseStatus, getQuery} = h3
const {compileFile} = require("@cloudrac3r/pug")
-const walkAST = require("pug-walk")
const pretty = process.argv.join(" ").includes("test")
const {sync} = require("../passthrough")
/** @type {import("./auth")} */
const auth = sync.require("./auth")
-/** @type {import("../js/errors")} */
-const errors = sync.require("../js/errors")
// Pug
-let globals = sync.remember(() => ({}))
+let globals = {}
/** @type {Map) => Promise>} */
const pugCache = new Map()
@@ -34,60 +30,21 @@ function addGlobals(obj) {
* @param {Record} locals
*/
function render(event, filename, locals) {
- return renderFragments(event, filename, null, locals)
-}
-
-/**
- * @param {import("h3").H3Event} event
- * @param {string} filename
- * @param {string[] | null} fragments
- * @param {Record} locals
- */
-function renderFragments(event, filename, fragments, locals) {
const path = join(__dirname, "pug", filename)
- return renderPath(event, path, fragments, locals)
-}
-
-/**
- * @param {string[] | null} fragments
- * @param {string[]} requiresOut
- */
-function fragmentSelectorPlugins(fragments, requiresOut) {
- if (!fragments) return []
- return [{
- parse: true,
- postParse(ast, options) {
- const found = []
- walkAST(ast, (node, replace) => {
- if (node.type === "NamedBlock") {
- const [name, requires] = node.name.split("requires").map(x => x.trim())
- // console.log(name, "|", requires)
- if (fragments?.includes(name)) {
- if (requires) requiresOut.push(...requires.split(",").map(x => x.trim()))
- found.push(node)
- }
- }
- })
- // console.log(util.inspect(found, false, 9, true))
- return {type: "Block", nodes: found, line: 0, filename: found[0].filename}
- }
- }]
+ return renderPath(event, path, locals)
}
/**
* @param {import("h3").H3Event} event
* @param {string} path
- * @param {string[] | null} fragments
* @param {Record} locals
*/
-function renderPath(event, path, fragments, locals) {
- const cacheKey = path + (fragments ? fragments.map(f => `#${f}`).join("") : "")
-
+function renderPath(event, path, locals) {
function compile() {
try {
- const requiredVars = []
- const template = compileFile(path, {pretty, plugins: fragmentSelectorPlugins(fragments, requiredVars)})
- pugCache.set(cacheKey, async (event, locals) => {
+ const template = compileFile(path, {pretty})
+ pugCache.set(path, async (event, locals) => {
+ defaultContentType(event, "text/html; charset=utf-8")
const session = await auth.useSession(event)
const managed = await auth.getManagedGuilds(event)
const rel = (to, paramsObject) => {
@@ -98,36 +55,16 @@ function renderPath(event, path, fragments, locals) {
}
return result
}
- const templateVars = Object.assign({},
+ return template(Object.assign({},
getQuery(event), // Query parameters can be easily accessed on the top level but don't allow them to overwrite anything
globals, // Globals
locals, // Explicit locals overwrite globals in case we need to DI something
{session, event, rel, managed} // These are assigned last so they overwrite everything else. It would be catastrophically bad if they can't be trusted.
- )
- // Verify all fragment block required variables are present
- for (const key of requiredVars) {
- if (templateVars[key] === undefined) {
- setResponseStatus(event, 500, "Internal Template Variables Error")
- defaultContentType(event, "text/plain")
- return `requested fragments ${JSON.stringify(fragments)}\nrequire variables ${JSON.stringify(requiredVars)}\nbut "${key}" is ${templateVars[key]} (present: ${key in templateVars})`
- }
- }
- try {
- const content = template(templateVars)
- defaultContentType(event, "text/html; charset=utf-8")
- return content
- } catch (e) {
- console.error(e)
- setResponseStatus(event, 500, "Internal Template Rendering Error")
- defaultContentType(event, "text/plain")
- e.url = getRequestURL(event).toString()
- return errors.stringifyErrorStack(e)
- }
+ ))
})
/* c8 ignore start */
} catch (e) {
- pugCache.set(cacheKey, async (event) => {
- console.error(e)
+ pugCache.set(path, async (event) => {
setResponseStatus(event, 500, "Internal Template Error")
defaultContentType(event, "text/plain")
return e.toString()
@@ -136,16 +73,14 @@ function renderPath(event, path, fragments, locals) {
/* c8 ignore stop */
}
- if (!pugCache.has(cacheKey)) {
+ if (!pugCache.has(path)) {
compile()
- const ac = new AbortController()
- const {signal} = ac
- fs.watch(path, {persistent: false, signal}, compile)
- fs.watch(join(__dirname, "pug", "includes"), {persistent: false, signal}, compile)
- sync.events.once(__filename, () => ac.abort())
+ fs.watch(path, {persistent: false}, compile)
+ fs.watch(join(__dirname, "pug", "includes"), {persistent: false}, compile)
+ fs.watch(join(__dirname, "pug", "fragments"), {persistent: false}, compile)
}
- const cb = pugCache.get(cacheKey)
+ const cb = pugCache.get(path)
assert(cb)
return cb(event, locals)
}
@@ -163,6 +98,5 @@ function createRoute(router, url, filename) {
module.exports.addGlobals = addGlobals
module.exports.render = render
-module.exports.renderFragments = renderFragments
module.exports.renderPath = renderPath
module.exports.createRoute = createRoute
diff --git a/src/web/pug/fragments/default-roles-list.pug b/src/web/pug/fragments/default-roles-list.pug
new file mode 100644
index 0000000..3b36549
--- /dev/null
+++ b/src/web/pug/fragments/default-roles-list.pug
@@ -0,0 +1,5 @@
+//- locals: guild, guild_id
+
+include ../includes/default-roles-list.pug
++default-roles-list(guild, guild_id)
++add-roles-menu(guild, guild_id)
diff --git a/src/web/pug/guild.pug b/src/web/pug/guild.pug
index c464954..7411a1e 100644
--- a/src/web/pug/guild.pug
+++ b/src/web/pug/guild.pug
@@ -1,4 +1,5 @@
extends includes/template.pug
+include includes/default-roles-list.pug
mixin badge-readonly
.s-badge.s-badge__xs.s-badge__icon.s-badge__muted
@@ -112,33 +113,15 @@ block body
.d-flex.fw-wrap.g4
.s-tag.s-tag__md.fs-body1.s-tag__required @everyone
- block default-roles-list requires guild, guild_id
- #default-roles-list(style="display: contents")
- each roleID in select("role_default", "role_id", {guild_id}).pluck().all()
- - let r = guild.roles.find(r => r.id === roleID)
- if r
- .s-tag.s-tag__md.fs-body1= r.name
- span(id=`role-loading-${roleID}`)
- button(name="remove_role" value=roleID hx-post="api/default-roles" hx-trigger="click consume" hx-indicator=`#role-loading-${roleID}`).s-tag--dismiss
- != icons.Icons.IconClearSm
+ +default-roles-list(guild, guild_id)
button(type="button" popovertarget="role-add").s-btn__dropdown.s-tag.s-tag__md.fs-body1.p0
.s-tag--dismiss.m1
!= icons.Icons.IconPlusSm
- #role-add.s-popover(popover style="display: revert").ws2.px0.py4.bs-lg.overflow-visible.box-border.lh-sm
+ #role-add.s-popover(popover style="display: revert").ws2.px0.py4.bs-lg.overflow-visible
.s-popover--arrow.s-popover--arrow__tc
-
- block add-roles-menu requires guild, guild_id
- ul.s-menu(role="menu" hx-swap-oob="true").overflow-y-auto.overflow-x-hidden#add-roles-menu
- li.s-menu--title.d-flex(role="separator") Select role
- span#add-role-loading
- each r in guild.roles.sort((a, b) => b.position - a.position)
- if r.id !== guild_id && !r.managed
- - let selected = !!select("role_default", "role_id", {guild_id, role_id: r.id}).get()
- li(role="menuitem")
- button(name="toggle_role" value=r.id class={"is-selected": selected}).s-block-link.s-block-link__left= r.name
-
+ +add-roles-menu(guild, guild_id)
p.fc-light.mb0.mt8 Matrix users will start with these roles. If your main channels are gated by a role, use this to let Matrix users skip the gate.
h3.mt32.fs-category Features
diff --git a/src/web/pug/includes/default-roles-list.pug b/src/web/pug/includes/default-roles-list.pug
new file mode 100644
index 0000000..8c0a4e0
--- /dev/null
+++ b/src/web/pug/includes/default-roles-list.pug
@@ -0,0 +1,19 @@
+mixin default-roles-list(guild, guild_id)
+ #default-roles-list(style="display: contents")
+ each roleID in select("role_default", "role_id", {guild_id}).pluck().all()
+ - let r = guild.roles.find(r => r.id === roleID)
+ if r
+ .s-tag.s-tag__md.fs-body1= r.name
+ span(id=`role-loading-${roleID}`)
+ button(name="remove_role" value=roleID hx-post="api/default-roles" hx-trigger="click consume" hx-indicator=`#role-loading-${roleID}`).s-tag--dismiss
+ != icons.Icons.IconClearSm
+
+mixin add-roles-menu(guild, guild_id)
+ ul.s-menu(role="menu" hx-swap-oob="true").overflow-y-auto.overflow-x-hidden#add-roles-menu
+ li.s-menu--title.d-flex(role="separator") Select role
+ span#add-role-loading
+ each r in guild.roles.sort((a, b) => b.position - a.position)
+ if r.id !== guild_id && !r.managed
+ - let selected = !!select("role_default", "role_id", {guild_id, role_id: r.id}).get()
+ li(role="menuitem")
+ button(name="toggle_role" value=r.id class={"is-selected": selected}).s-block-link.s-block-link__left= r.name
diff --git a/src/web/pug/invite.pug b/src/web/pug/invite.pug
index 0596d58..81a428d 100644
--- a/src/web/pug/invite.pug
+++ b/src/web/pug/invite.pug
@@ -17,10 +17,10 @@ block body
.fl-grow1
h2.fs-headline1 Invite a Matrix user
- form.d-flex.gy16.wmx3.fd-column(method="post" action=rel("/api/invite") hx-post=rel("/api/invite") hx-indicator="#invite-button" hx-select="#ok" hx-target="#form-container")
+ form.d-flex.gy16.fd-column(method="post" action=rel("/api/invite") hx-post=rel("/api/invite") hx-indicator="#invite-button" hx-select="#ok" hx-target="#form-container")
.d-flex.gy4.fd-column
label.s-label(for="mxid") Matrix ID
- input.fl-grow1.s-input#mxid(name="mxid" required placeholder="@user:example.org")
+ input.fl-grow1.s-input.wmx3#mxid(name="mxid" required placeholder="@user:example.org")
.d-flex.gy4.fd-column
label.s-label(for="permissions") Permissions
.s-select
diff --git a/src/web/routes/guild-settings.js b/src/web/routes/guild-settings.js
index 9bfff3d..8119f93 100644
--- a/src/web/routes/guild-settings.js
+++ b/src/web/routes/guild-settings.js
@@ -135,7 +135,7 @@ as.router.post("/api/default-roles", defineEventHandler(async event => {
await createSpace.syncSpaceFully(guildID) // this is inefficient but OK to call infrequently on user request
if (getRequestHeader(event, "HX-Request")) {
- return pugSync.renderFragments(event, "guild.pug", ["default-roles-list", "add-roles-menu"], {guild, guild_id: guildID})
+ return pugSync.render(event, "fragments/default-roles-list.pug", {guild, guild_id: guildID})
} else {
return sendRedirect(event, `/guild?guild_id=${guildID}`, 302)
}
diff --git a/src/web/server.js b/src/web/server.js
index 3c06ede..c8d363d 100644
--- a/src/web/server.js
+++ b/src/web/server.js
@@ -1,6 +1,6 @@
// @ts-check
-const assert = require("assert").strict
+const assert = require("assert")
const fs = require("fs")
const {join} = require("path")
const h3 = require("h3")
@@ -98,7 +98,7 @@ function tryStatic(event, fallthrough) {
getContents: id => {
if (id.match(/\.pug$/)) {
const path = join(publicDir, id)
- return pugSync.renderPath(event, path, null, {})
+ return pugSync.renderPath(event, path, {})
} else {
return fs.createReadStream(join(publicDir, id))
}
diff --git a/test/test.js b/test/test.js
index 5079ed3..4cd9627 100644
--- a/test/test.js
+++ b/test/test.js
@@ -130,7 +130,6 @@ file._actuallyUploadDiscordFileToMxc = function(url, res) { throw new Error(`Not
require("./addbot.test")
require("../src/db/orm.test")
- require("../src/js/errors.test")
require("../src/web/server.test")
require("../src/discord/utils.test")
require("../src/matrix/kstate.test")