mirror of
https://github.com/jakejarvis/jarv.is.git
synced 2025-04-26 05:45:22 -04:00
more error handling
This commit is contained in:
parent
50c184fb21
commit
ec7c9fae54
@ -7,10 +7,35 @@ import * as Sentry from "@sentry/nextjs";
|
||||
import * as config from "../../lib/config";
|
||||
|
||||
const ContactSchema = v.object({
|
||||
name: v.pipe(v.string(), v.nonEmpty("Your name is required.")),
|
||||
email: v.pipe(v.string(), v.nonEmpty("Your email address is required."), v.email("Invalid email address.")),
|
||||
message: v.pipe(v.string(), v.nonEmpty("A message is required.")),
|
||||
"cf-turnstile-response": v.pipe(v.string(), v.nonEmpty("Just do the stinkin CAPTCHA! 🤖")),
|
||||
// TODO: replace duplicate error messages with v.message() when released. see:
|
||||
// https://valibot.dev/api/message/
|
||||
// https://github.com/fabian-hiller/valibot/blob/main/library/src/methods/message/message.ts
|
||||
name: v.pipe(v.string("Your name is required."), v.trim(), v.nonEmpty("Your name is required.")),
|
||||
email: v.pipe(
|
||||
v.string("Your email address is required."),
|
||||
v.trim(),
|
||||
v.nonEmpty("Your email address is required."),
|
||||
v.email("Invalid email address.")
|
||||
),
|
||||
message: v.pipe(
|
||||
v.string("A message is required."),
|
||||
v.trim(),
|
||||
v.nonEmpty("A message is required."),
|
||||
v.minLength(10, "Your message must be at least 10 characters.")
|
||||
),
|
||||
"cf-turnstile-response": v.pipe(
|
||||
// token wasn't submitted at _all_, most likely a direct POST request by a spam bot
|
||||
v.string("Shoo, bot."),
|
||||
// form submitted properly but token was missing, might be a forgetful human
|
||||
v.nonEmpty("Just do the stinkin CAPTCHA, human! 🤖"),
|
||||
// very rudimentary length check based on Cloudflare's docs
|
||||
// https://developers.cloudflare.com/turnstile/troubleshooting/testing/
|
||||
v.minLength("XXXX.DUMMY.TOKEN.XXXX".length),
|
||||
// "A Turnstile token can have up to 2048 characters."
|
||||
// https://developers.cloudflare.com/turnstile/get-started/server-side-validation/
|
||||
v.maxLength(2048),
|
||||
v.readonly()
|
||||
),
|
||||
});
|
||||
|
||||
export type ContactInput = v.InferInput<typeof ContactSchema>;
|
||||
|
@ -28,7 +28,7 @@ const Page = () => {
|
||||
</p>
|
||||
<p>
|
||||
🔐 You can grab my public key here:{" "}
|
||||
<Link href="/pubkey.asc" title="My Public PGP Key" rel="pgpkey authn" openInNewTab>
|
||||
<Link href="https://jrvs.io/pgp" title="My Public Key">
|
||||
<code style={{ fontSize: "0.925em", letterSpacing: "0.075em", wordSpacing: "-0.3em" }}>
|
||||
6BF3 79D3 6F67 1480 2B0C 9CF2 51E6 9A39
|
||||
</code>
|
||||
|
@ -23,6 +23,8 @@ const HitCounter = async ({ slug }: { slug: string }) => {
|
||||
);
|
||||
} catch (error) {
|
||||
Sentry.captureException(error);
|
||||
|
||||
return <span title="Error getting views! :(">?</span>;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -258,13 +258,12 @@ const Page = () => {
|
||||
</Link>{" "}
|
||||
<sup>
|
||||
<Link
|
||||
href="/pubkey.asc"
|
||||
rel="pgpkey authn"
|
||||
href="https://jrvs.io/pgp"
|
||||
rel="pgpkey"
|
||||
title="My Public Key"
|
||||
lightColor="#757575"
|
||||
darkColor="#959595"
|
||||
plain
|
||||
openInNewTab
|
||||
>
|
||||
<LockIcon size="1.25em" style={{ verticalAlign: "-0.25em" }} />{" "}
|
||||
<span
|
||||
|
@ -10,8 +10,6 @@ import type { User, Repository } from "@octokit/graphql-schema";
|
||||
|
||||
import styles from "./page.module.css";
|
||||
|
||||
export const revalidate = 600; // 10 minutes
|
||||
|
||||
export const metadata = addMetadata({
|
||||
title: "Projects",
|
||||
description: `Most-starred repositories by @${config.authorSocial?.github} on GitHub`,
|
||||
@ -80,6 +78,20 @@ const getRepos = async (): Promise<Project[] | null> => {
|
||||
accept: "application/vnd.github.v3+json",
|
||||
authorization: `token ${process.env.GITHUB_TOKEN}`,
|
||||
},
|
||||
request: {
|
||||
// override fetch() to use next's extension to cache the response
|
||||
// https://nextjs.org/docs/app/api-reference/functions/fetch#fetchurl-options
|
||||
fetch: (url: string | URL | Request, options?: RequestInit) => {
|
||||
return fetch(url, {
|
||||
...options,
|
||||
cache: "force-cache",
|
||||
next: {
|
||||
// 10 minutes
|
||||
revalidate: 600,
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -7,7 +7,7 @@ const robots = (): MetadataRoute.Robots => ({
|
||||
rules: [
|
||||
{
|
||||
userAgent: "*",
|
||||
disallow: ["/_stream/", "/api/", "/pubkey.asc", "/404", "/500"],
|
||||
disallow: ["/_stream/", "/api/", "/404", "/500"],
|
||||
},
|
||||
],
|
||||
sitemap: `${BASE_URL}/sitemap.xml`,
|
||||
|
@ -9,7 +9,13 @@ const Gist = async ({ id, file }: GistProps) => {
|
||||
const iframeId = `gist-${id}${file ? `-${file}` : ""}`;
|
||||
|
||||
const scriptUrl = `https://gist.github.com/${id}.js${file ? `?file=${file}` : ""}`;
|
||||
const scriptResponse = await fetch(scriptUrl);
|
||||
const scriptResponse = await fetch(scriptUrl, {
|
||||
cache: "force-cache",
|
||||
next: {
|
||||
// cache indefinitely in data store
|
||||
revalidate: 0,
|
||||
},
|
||||
});
|
||||
|
||||
if (!scriptResponse.ok) {
|
||||
console.warn(`[gist] failed to fetch js:`, scriptResponse.statusText);
|
||||
|
@ -1,4 +0,0 @@
|
||||
/* stylelint-disable-next-line selector-type-no-unknown */
|
||||
.wrapper lite-youtube {
|
||||
margin: 0 auto;
|
||||
}
|
@ -1,17 +1,14 @@
|
||||
import { YouTubeEmbed } from "@next/third-parties/google";
|
||||
"use client";
|
||||
|
||||
import styles from "./YouTube.module.css";
|
||||
import YouTubeEmbed from "react-lite-youtube-embed";
|
||||
import type { ComponentPropsWithoutRef } from "react";
|
||||
|
||||
export type YouTubeProps = {
|
||||
id: string;
|
||||
};
|
||||
import "react-lite-youtube-embed/dist/LiteYouTubeEmbed.css";
|
||||
|
||||
const YouTube = ({ id }: YouTubeProps) => {
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
<YouTubeEmbed videoid={id} />
|
||||
</div>
|
||||
);
|
||||
export type YouTubeProps = Omit<ComponentPropsWithoutRef<typeof YouTubeEmbed>, "title">;
|
||||
|
||||
const YouTube = ({ ...rest }: YouTubeProps) => {
|
||||
return <YouTubeEmbed cookie={false} containerElement="div" title="" {...rest} />;
|
||||
};
|
||||
|
||||
export default YouTube;
|
||||
|
@ -2,7 +2,6 @@ import * as Sentry from "@sentry/nextjs";
|
||||
|
||||
Sentry.init({
|
||||
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
|
||||
environment: process.env.NEXT_PUBLIC_VERCEL_ENV,
|
||||
integrations: [Sentry.browserTracingIntegration(), Sentry.httpClientIntegration()],
|
||||
tracesSampleRate: 1.0,
|
||||
});
|
||||
|
@ -5,7 +5,6 @@ export const onRequestError = Sentry.captureRequestError;
|
||||
export const register = () => {
|
||||
Sentry.init({
|
||||
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN || process.env.SENTRY_DSN,
|
||||
environment: process.env.NEXT_PUBLIC_VERCEL_ENV,
|
||||
integrations: [Sentry.captureConsoleIntegration()],
|
||||
tracesSampleRate: 1.0,
|
||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/options/#normalizeDepth
|
||||
|
@ -58,7 +58,23 @@ const nextConfig: NextConfig = {
|
||||
},
|
||||
headers: async () => [
|
||||
{
|
||||
// matches any path without a file extension (aka period) or an underscore (e.g. /_next/image)
|
||||
// matches any path
|
||||
source: "/(.*)",
|
||||
headers: [
|
||||
{
|
||||
key: "strict-transport-security",
|
||||
value: "max-age=63072000; includeSubDomains; preload",
|
||||
},
|
||||
{
|
||||
key: "x-got-milk",
|
||||
value: "2%",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
// https://community.torproject.org/onion-services/advanced/onion-location/
|
||||
// only needed on actual pages, not static assets, so make a best effort by matching any path **without** a file
|
||||
// extension (aka a period) and/or an underscore (e.g. /_next/image).
|
||||
source: "/:path([^._]*)",
|
||||
headers: [
|
||||
{
|
||||
@ -67,15 +83,6 @@ const nextConfig: NextConfig = {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
source: "/pubkey.asc",
|
||||
headers: [
|
||||
{
|
||||
key: "Content-Type",
|
||||
value: "text/plain; charset=utf-8",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
rewrites: async () => [
|
||||
{
|
||||
@ -88,6 +95,11 @@ const nextConfig: NextConfig = {
|
||||
source: "/tweets/:path*",
|
||||
destination: "https://tweets-khaki.vercel.app/:path*",
|
||||
},
|
||||
{
|
||||
source: "/pubkey.asc",
|
||||
destination:
|
||||
"https://keys.openpgp.org/pks/lookup?op=get&options=mr&search=0x3bc6e5776bf379d36f6714802b0c9cf251e69a39",
|
||||
},
|
||||
],
|
||||
redirects: async () => [
|
||||
{ source: "/y2k", destination: "https://y2k.pages.dev", permanent: false },
|
||||
@ -231,10 +243,4 @@ const nextPlugins: Array<
|
||||
|
||||
// eslint-disable-next-line import/no-anonymous-default-export
|
||||
export default (): NextConfig =>
|
||||
nextPlugins.reduce((acc, next) => {
|
||||
if (Array.isArray(next)) {
|
||||
return next[0](acc, next[1]);
|
||||
}
|
||||
|
||||
return next(acc);
|
||||
}, nextConfig);
|
||||
nextPlugins.reduce((acc, plugin) => (Array.isArray(plugin) ? plugin[0](acc, plugin[1]) : plugin(acc)), nextConfig);
|
||||
|
@ -25,7 +25,6 @@
|
||||
"@mdx-js/react": "^3.1.0",
|
||||
"@next/bundle-analyzer": "15.3.0-canary.25",
|
||||
"@next/mdx": "15.3.0-canary.25",
|
||||
"@next/third-parties": "15.3.0-canary.25",
|
||||
"@octokit/graphql": "^8.2.1",
|
||||
"@octokit/graphql-schema": "^15.26.0",
|
||||
"@sentry/nextjs": "^9.10.1",
|
||||
@ -37,7 +36,7 @@
|
||||
"fast-glob": "^3.3.3",
|
||||
"feed": "^4.2.2",
|
||||
"geist": "^1.3.1",
|
||||
"html-entities": "^2.5.5",
|
||||
"html-entities": "^2.6.0",
|
||||
"lucide-react": "0.485.0",
|
||||
"modern-normalize": "^3.0.1",
|
||||
"next": "15.3.0-canary.25",
|
||||
@ -49,8 +48,9 @@
|
||||
"react-dom": "19.1.0",
|
||||
"react-innertext": "^1.1.5",
|
||||
"react-is": "19.1.0",
|
||||
"react-lite-youtube-embed": "^2.4.0",
|
||||
"react-schemaorg": "^2.0.0",
|
||||
"react-textarea-autosize": "^8.5.8",
|
||||
"react-textarea-autosize": "^8.5.9",
|
||||
"react-timeago": "^8.0.0",
|
||||
"react-turnstile": "^1.1.4",
|
||||
"react-tweet": "^3.2.2",
|
||||
|
54
pnpm-lock.yaml
generated
54
pnpm-lock.yaml
generated
@ -32,9 +32,6 @@ importers:
|
||||
'@next/mdx':
|
||||
specifier: 15.3.0-canary.25
|
||||
version: 15.3.0-canary.25(@mdx-js/loader@3.1.0(acorn@8.14.1)(webpack@5.98.0))(@mdx-js/react@3.1.0(@types/react@19.0.12)(react@19.1.0))
|
||||
'@next/third-parties':
|
||||
specifier: 15.3.0-canary.25
|
||||
version: 15.3.0-canary.25(next@15.3.0-canary.25(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-aeaed83-20250323)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)
|
||||
'@octokit/graphql':
|
||||
specifier: ^8.2.1
|
||||
version: 8.2.1
|
||||
@ -69,8 +66,8 @@ importers:
|
||||
specifier: ^1.3.1
|
||||
version: 1.3.1(next@15.3.0-canary.25(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-aeaed83-20250323)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))
|
||||
html-entities:
|
||||
specifier: ^2.5.5
|
||||
version: 2.5.5
|
||||
specifier: ^2.6.0
|
||||
version: 2.6.0
|
||||
lucide-react:
|
||||
specifier: 0.485.0
|
||||
version: 0.485.0(react@19.1.0)
|
||||
@ -104,12 +101,15 @@ importers:
|
||||
react-is:
|
||||
specifier: 19.1.0
|
||||
version: 19.1.0
|
||||
react-lite-youtube-embed:
|
||||
specifier: ^2.4.0
|
||||
version: 2.4.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
react-schemaorg:
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0(react@19.1.0)(schema-dts@1.1.5)(typescript@5.8.2)
|
||||
react-textarea-autosize:
|
||||
specifier: ^8.5.8
|
||||
version: 8.5.8(@types/react@19.0.12)(react@19.1.0)
|
||||
specifier: ^8.5.9
|
||||
version: 8.5.9(@types/react@19.0.12)(react@19.1.0)
|
||||
react-timeago:
|
||||
specifier: ^8.0.0
|
||||
version: 8.0.0(react@19.1.0)
|
||||
@ -728,12 +728,6 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@next/third-parties@15.3.0-canary.25':
|
||||
resolution: {integrity: sha512-UiwiSeKKyBW31YZ6v4QEb9+Sx22ubWcf/74Jv1dIQnXrKLMd3OTNj9r0Z3Bj5sIpuBx0NIf8LCr90H2sJRRYDw==}
|
||||
peerDependencies:
|
||||
next: ^13.0.0 || ^14.0.0 || ^15.0.0
|
||||
react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
|
||||
|
||||
'@nodelib/fs.scandir@2.1.5':
|
||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||
engines: {node: '>= 8'}
|
||||
@ -2687,8 +2681,8 @@ packages:
|
||||
resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==}
|
||||
engines: {node: ^16.14.0 || >=18.0.0}
|
||||
|
||||
html-entities@2.5.5:
|
||||
resolution: {integrity: sha512-24CG9o869vSa86BGCf7x65slrAztzFTU5VBQzEIwqjhKuB4zCC7xlH/7NCcZ1EN5MdmGx9lUqugfutuT6J+jKQ==}
|
||||
html-entities@2.6.0:
|
||||
resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==}
|
||||
|
||||
html-escaper@2.0.2:
|
||||
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
|
||||
@ -3702,6 +3696,12 @@ packages:
|
||||
react-is@19.1.0:
|
||||
resolution: {integrity: sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==}
|
||||
|
||||
react-lite-youtube-embed@2.4.0:
|
||||
resolution: {integrity: sha512-Xo6cM1zPlROvvM97JkqQIoXstlQDaC4+DawmM7BB7Hh1cXrkBHEGq1iJlQxBTUWAUklmpcC7ph7qg7CztXtABQ==}
|
||||
peerDependencies:
|
||||
react: '>=18.2.0'
|
||||
react-dom: '>=18.2.0'
|
||||
|
||||
react-promise-suspense@0.3.4:
|
||||
resolution: {integrity: sha512-I42jl7L3Ze6kZaq+7zXWSunBa3b1on5yfvUW6Eo/3fFOj6dZ5Bqmcd264nJbTK/gn1HjjILAjSwnZbV4RpSaNQ==}
|
||||
|
||||
@ -3713,8 +3713,8 @@ packages:
|
||||
schema-dts: '>=0.7.4'
|
||||
typescript: '>=3.1.6'
|
||||
|
||||
react-textarea-autosize@8.5.8:
|
||||
resolution: {integrity: sha512-iUiIj70JefrTuSJ4LbVFiSqWiHHss5L63L717bqaWHMgkm9sz6eEvro4vZ3uQfGJbevzwT6rHOszHKA8RkhRMg==}
|
||||
react-textarea-autosize@8.5.9:
|
||||
resolution: {integrity: sha512-U1DGlIQN5AwgjTyOEnI1oCcMuEr1pv1qOtklB2l4nyMGbHzWrI0eFsYK0zos2YWqAolJyG0IWJaqWmWj5ETh0A==}
|
||||
engines: {node: '>=10'}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
@ -4246,9 +4246,6 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
third-party-capital@1.0.20:
|
||||
resolution: {integrity: sha512-oB7yIimd8SuGptespDAZnNkzIz+NWaJCu2RMsbs4Wmp9zSDUM8Nhi3s2OOcqYuv3mN4hitXc8DVx+LyUmbUDiA==}
|
||||
|
||||
tinyglobby@0.2.12:
|
||||
resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
@ -5081,12 +5078,6 @@ snapshots:
|
||||
'@next/swc-win32-x64-msvc@15.3.0-canary.25':
|
||||
optional: true
|
||||
|
||||
'@next/third-parties@15.3.0-canary.25(next@15.3.0-canary.25(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-aeaed83-20250323)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)':
|
||||
dependencies:
|
||||
next: 15.3.0-canary.25(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@19.0.0-beta-aeaed83-20250323)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
react: 19.1.0
|
||||
third-party-capital: 1.0.20
|
||||
|
||||
'@nodelib/fs.scandir@2.1.5':
|
||||
dependencies:
|
||||
'@nodelib/fs.stat': 2.0.5
|
||||
@ -7460,7 +7451,7 @@ snapshots:
|
||||
dependencies:
|
||||
lru-cache: 10.4.3
|
||||
|
||||
html-entities@2.5.5: {}
|
||||
html-entities@2.6.0: {}
|
||||
|
||||
html-escaper@2.0.2: {}
|
||||
|
||||
@ -8727,6 +8718,11 @@ snapshots:
|
||||
|
||||
react-is@19.1.0: {}
|
||||
|
||||
react-lite-youtube-embed@2.4.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
|
||||
dependencies:
|
||||
react: 19.1.0
|
||||
react-dom: 19.1.0(react@19.1.0)
|
||||
|
||||
react-promise-suspense@0.3.4:
|
||||
dependencies:
|
||||
fast-deep-equal: 2.0.1
|
||||
@ -8737,7 +8733,7 @@ snapshots:
|
||||
schema-dts: 1.1.5
|
||||
typescript: 5.8.2
|
||||
|
||||
react-textarea-autosize@8.5.8(@types/react@19.0.12)(react@19.1.0):
|
||||
react-textarea-autosize@8.5.9(@types/react@19.0.12)(react@19.1.0):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.27.0
|
||||
react: 19.1.0
|
||||
@ -9527,8 +9523,6 @@ snapshots:
|
||||
commander: 2.20.3
|
||||
source-map-support: 0.5.21
|
||||
|
||||
third-party-capital@1.0.20: {}
|
||||
|
||||
tinyglobby@0.2.12:
|
||||
dependencies:
|
||||
fdir: 6.4.3(picomatch@4.0.2)
|
||||
|
@ -1,64 +0,0 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
=sqOH
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
Loading…
x
Reference in New Issue
Block a user