diff --git a/api/article-og.ts b/api/article-og.ts index 6311fe49..2dc01eb6 100644 --- a/api/article-og.ts +++ b/api/article-og.ts @@ -1,4 +1,6 @@ import type { VercelRequest, VercelResponse } from '@vercel/node' +import WebSocket from 'ws' +;(globalThis as any).WebSocket ??= WebSocket as any import { RelayPool } from 'applesauce-relay' import { nip19 } from 'nostr-tools' import { AddressPointer } from 'nostr-tools/nip19' @@ -102,11 +104,11 @@ async function fetchArticleMetadata(naddr: string): Promise

Redirecting to Boris...

+ ` } -function isCrawler(userAgent: string | undefined): boolean { - if (!userAgent) return false - const crawlers = [ - 'bot', 'crawl', 'spider', 'slurp', 'facebook', 'twitter', 'linkedin', - 'whatsapp', 'telegram', 'slack', 'discord', 'preview' - ] - const ua = userAgent.toLowerCase() - return crawlers.some(crawler => ua.includes(crawler)) -} - export default async function handler(req: VercelRequest, res: VercelResponse) { const naddr = (req.query.naddr as string | undefined)?.trim() @@ -212,52 +215,11 @@ export default async function handler(req: VercelRequest, res: VercelResponse) { return res.status(400).json({ error: 'Missing naddr parameter' }) } - const userAgent = req.headers['user-agent'] as string | undefined - const isCrawlerRequest = isCrawler(userAgent) - const debugEnabled = req.query.debug === '1' || req.headers['x-boris-debug'] === '1' if (debugEnabled) { res.setHeader('X-Boris-Debug', '1') } - // If it's a regular browser (not a bot), serve HTML that loads SPA - // Use history.replaceState to set the URL before the SPA boots - if (!isCrawlerRequest) { - const articlePath = `/a/${naddr}` - // Serve a minimal HTML that sets up the URL and loads the SPA - const html = ` - - - - - - Boris - Loading Article... - - ${debugEnabled ? `` : ''} - - - -
- -` - - res.setHeader('Content-Type', 'text/html; charset=utf-8') - res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate') - if (debugEnabled) { - // Debug mode enabled - } - return res.status(200).send(html) - } - // Check cache for bots/crawlers const now = Date.now() const cached = memoryCache.get(naddr) diff --git a/package-lock.json b/package-lock.json index f77a5416..fd0eddf5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "boris", - "version": "0.10.23", + "version": "0.10.33", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "boris", - "version": "0.10.23", + "version": "0.10.33", "dependencies": { "@fortawesome/fontawesome-svg-core": "^7.1.0", "@fortawesome/free-regular-svg-icons": "^7.1.0", @@ -37,7 +37,8 @@ "rehype-raw": "^7.0.0", "remark-gfm": "^4.0.1", "tinyld": "^1.3.4", - "use-pull-to-refresh": "^2.4.1" + "use-pull-to-refresh": "^2.4.1", + "ws": "^8.18.3" }, "devDependencies": { "@tailwindcss/postcss": "^4.1.14", @@ -102,6 +103,7 @@ "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", @@ -2262,6 +2264,7 @@ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-7.1.0.tgz", "integrity": "sha512-fNxRUk1KhjSbnbuBxlWSnBLKLBNun52ZBTcs22H/xEEzM6Ap81ZFTQ4bZBxVQGQgVY0xugKGoRcCbaKjLQ3XZA==", "license": "MIT", + "peer": true, "dependencies": { "@fortawesome/fontawesome-common-types": "7.1.0" }, @@ -3553,6 +3556,7 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.26.tgz", "integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==", "license": "MIT", + "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -3637,6 +3641,7 @@ "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "6.21.0", "@typescript-eslint/types": "6.21.0", @@ -3927,7 +3932,8 @@ "version": "16.18.11", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@vercel/node/node_modules/esbuild": { "version": "0.14.47", @@ -4012,6 +4018,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -4088,6 +4095,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4640,6 +4648,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.9", "caniuse-lite": "^1.0.30001746", @@ -5876,6 +5885,7 @@ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -9711,6 +9721,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -9857,6 +9868,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -9869,6 +9881,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -10434,6 +10447,7 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", "license": "Apache-2.0", + "peer": true, "dependencies": { "tslib": "^2.1.0" } @@ -11189,6 +11203,7 @@ "integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", @@ -11265,6 +11280,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -11517,6 +11533,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -11560,8 +11577,7 @@ "version": "7.14.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz", "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", @@ -11842,6 +11858,7 @@ "integrity": "sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -12227,6 +12244,7 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -12271,6 +12289,7 @@ "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "rollup": "dist/bin/rollup" }, @@ -12519,6 +12538,27 @@ "dev": true, "license": "ISC" }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", diff --git a/package.json b/package.json index 06f0a1a2..003d7fc8 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,9 @@ "description": "A minimal nostr client for bookmark management", "homepage": "https://read.withboris.com/", "type": "module", + "engines": { + "node": "22.x" + }, "scripts": { "dev": "vite", "build": "tsc && vite build", @@ -41,7 +44,8 @@ "rehype-raw": "^7.0.0", "remark-gfm": "^4.0.1", "tinyld": "^1.3.4", - "use-pull-to-refresh": "^2.4.1" + "use-pull-to-refresh": "^2.4.1", + "ws": "^8.18.3" }, "devDependencies": { "@tailwindcss/postcss": "^4.1.14", diff --git a/vercel.json b/vercel.json index 891d4ef1..9d044f6a 100644 --- a/vercel.json +++ b/vercel.json @@ -1,4 +1,10 @@ { + "version": 2, + "functions": { + "api/article-og.ts": { + "maxDuration": 10 + } + }, "rewrites": [ { "source": "/a/:naddr",