1
mirror of https://github.com/jakejarvis/jarv.is.git synced 2025-06-29 08:25:41 -04:00

vercel analytics ➡️ umami

This commit is contained in:
2025-03-11 14:28:29 -04:00
parent fa54a4f978
commit 125a6932c2
17 changed files with 151 additions and 170 deletions

View File

@ -1,35 +1,41 @@
{
"name": "Node.js",
"image": "mcr.microsoft.com/devcontainers/javascript-node:22-bookworm",
"postCreateCommand": "bash -i -c 'rm -rf node_modules && nvm install $(cat .node-version) -y && nvm use $(cat .node-version) && npm install -g corepack@latest && corepack enable && CI=true pnpm install'",
"postCreateCommand": ". ${NVM_DIR}/nvm.sh && nvm install $(cat .node-version) && nvm use $(cat .node-version) && corepack enable && pnpm install --frozen-lockfile",
"customizations": {
"vscode": {
"settings": {
"typescript.tsdk": "node_modules/typescript/lib",
"telemetry.enableTelemetry": false
"editor.rulers": [
120
],
"extensions.ignoreRecommendations": true,
"git.allowForcePush": true,
"git.autofetch": true,
"git.autoStash": true,
"git.enableCommitSigning": true,
"git.fetchOnPull": true,
"git.rebaseWhenSync": true,
"telemetry.telemetryLevel": "off",
"typescript.preferences.importModuleSpecifierEnding": "minimal",
"typescript.tsdk": "node_modules/typescript/lib"
},
"extensions": [
"EditorConfig.EditorConfig",
"dbaeumer.vscode-eslint",
"prisma.prisma",
"unifiedjs.vscode-mdx",
"wix.vscode-import-cost"
"unifiedjs.vscode-mdx"
]
}
},
"tasks": {
"build": "pnpm install --frozen-lockfile && pnpm build"
},
"forwardPorts": [
3000
],
"portsAttributes": {
"3000": {
"label": "next dev",
"onAutoForward": "notify"
}
},
"otherPortsAttributes": {
"onAutoForward": "silent"
},
"containerEnv": {
"CHECKPOINT_DISABLE": "1",
"COREPACK_ENABLE_DOWNLOAD_PROMPT": "0",
"NEXT_TELEMETRY_DISABLED": "1"
}
}

View File

@ -9,6 +9,14 @@ DATABASE_URL=
# https://github.com/settings/tokens/new?scopes=public_repo
GITHUB_TOKEN=
# optional. privacy-friendly tracking via Umami, either managed or self-hosted.
# this ID can be found in Settings > Websites > Edit > Details.
NEXT_PUBLIC_UMAMI_WEBSITE_ID=
# optional. the base URL of a self-hosted Umami instance (including https://) to proxy requests to. if the website ID is
# set but this isn't, the managed Umami Cloud endpoint is used.
# https://umami.is/docs/bypass-ad-blockers
NEXT_PUBLIC_UMAMI_HOST=
# optional. enables comments on blog posts via GitHub discussions.
# https://giscus.app/
NEXT_PUBLIC_GISCUS_REPO_ID=

View File

@ -1,8 +0,0 @@
{
"recommendations": [
"EditorConfig.EditorConfig",
"dbaeumer.vscode-eslint",
"prisma.prisma",
"unifiedjs.vscode-mdx"
]
}

18
.vscode/settings.json vendored
View File

@ -1,18 +0,0 @@
{
"editor.insertSpaces": true,
"editor.tabSize": 2,
"eslint.runtime": "node",
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"markdown",
"mdx"
],
"files.eol": "\n",
"files.insertFinalNewline": true,
"files.trimTrailingWhitespace": true,
"typescript.preferences.importModuleSpecifierEnding": "minimal",
"typescript.tsdk": "node_modules/typescript/lib"
}

View File

@ -5,7 +5,7 @@
[![Licensed under CC-BY-4.0](https://img.shields.io/badge/license-CC--BY--4.0-fb7828?logo=creative-commons&logoColor=white)](LICENSE)
[![GitHub repo size](https://img.shields.io/github/repo-size/jakejarvis/jarv.is?color=009cdf&label=repo%20size&logo=git&logoColor=white)](https://github.com/jakejarvis/jarv.is)
My humble abode on the World Wide Web, created and deployed using [Next.js](https://nextjs.org/), [Vercel](https://vercel.com/), [Neon Postgres](https://neon.tech/), [Prisma](https://www.prisma.io/postgres), [and more](https://jarv.is/humans.txt).
My humble abode on the World Wide Web, created and deployed using [Next.js](https://nextjs.org/), [Vercel](https://vercel.com/), [Neon Postgres](https://neon.tech/), [Prisma](https://www.prisma.io/postgres), [Umami](https://umami.is/), [and more](https://jarv.is/humans.txt).
I keep an ongoing list of [post ideas](https://github.com/jakejarvis/jarv.is/issues/1) and [coding to-dos](https://github.com/jakejarvis/jarv.is/issues/714) as issues in this repo. Outside contributions, improvements, and/or corrections are welcome too!
@ -21,12 +21,12 @@ Most production steps are handled [automatically by Vercel](https://vercel.com/d
## 🌎 Related
- [💻 /uses](https://jarv.is/uses/) Things and stuff I use.
- [🕰️ /previously](https://jarv.is/previously/) An embarrassing trip down this site's memory lane.
- Visit [/y2k](https://jarv.is/y2k/) if you want to experience the _fully_ immersive time machine, but don't say I didn't warn you...
- [📈 /stats](https://jarv.is/stats) - Public [Umami](https://umami.is/) dashboard.
- [💻 /uses](https://jarv.is/uses) Things and stuff I use.
- [🕰️ /previously](https://jarv.is/previously) An embarrassing trip down this site's memory lane.
- Visit [/y2k](https://jarv.is/y2k) if you want to experience the _fully_ immersive time machine, but don't say I didn't warn you...
- [🧅 Tor (.onion) mirror](http://jarvis2i2vp4j4tbxjogsnqdemnte5xhzyi7hziiyzxwge3hzmh57zad.onion/) For an excessive level of privacy and security.
- [🧮 jakejarvis/website-stats](https://github.com/jakejarvis/website-stats) Daily raw snapshots of the [hit counter](app/api/hits/route.ts) database.
- [🔗 jakejarvis/jrvs.io](https://github.com/jakejarvis/jrvs.io) Personal link shortener.
## 📜 License

18
app/analytics.tsx Normal file
View File

@ -0,0 +1,18 @@
import Script from "next/script";
const Analytics = () => {
if (!process.env.NEXT_PUBLIC_UMAMI_WEBSITE_ID || process.env.NEXT_PUBLIC_VERCEL_ENV !== "production") {
return null;
}
return (
<Script
src="/_stream/u/script.js" // see next.config.ts rewrite
strategy="afterInteractive"
data-website-id={process.env.NEXT_PUBLIC_UMAMI_WEBSITE_ID}
data-domains={process.env.NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL}
/>
);
};
export default Analytics;

View File

@ -27,7 +27,7 @@ export async function sendMessage(
// backup to client-side validations just in case someone squeezes through without them
if (!validatedFields.success) {
console.error("[contact form] validation error:", validatedFields.error.flatten());
console.debug("[contact form] validation error:", validatedFields.error.flatten());
return {
success: false,

View File

@ -1,5 +1,5 @@
import clsx from "clsx";
import { Analytics } from "@vercel/analytics/next";
import Analytics from "./analytics";
import { ThemeProvider } from "../contexts/ThemeContext";
import Header from "../components/Header";
import Footer from "../components/Footer";

View File

@ -32,7 +32,7 @@ A very simple hit counter on each blog post tallies an aggregate number of pagev
The [database schema](https://github.com/jakejarvis/jarv.is/blob/main/prisma/schema.prisma), [serverless function](https://github.com/jakejarvis/jarv.is/blob/main/app/api/hits/route.ts) and [client script](https://github.com/jakejarvis/jarv.is/blob/main/app/notes/%5Bslug%5D/counter.tsx) are open source, and [snapshots of the database](https://github.com/jakejarvis/website-stats) are public.
[**Vercel Analytics**](https://vercel.com/products/observability) is also used to gain insights into referrers, search terms, etc. [without collecting anything identifiable](https://vercel.com/docs/analytics/privacy-policy#data-point-information) about you.
A self-hosted [**Umami**](https://umami.is/) instance is also used to gain insights into referrers, search terms, etc. [without collecting anything identifiable](https://umami.is/blog/why-privacy-matters) about you. [The dashboard is even public!](/stats)
## Third-Party Content

View File

@ -42,7 +42,7 @@ type Project = {
async function getRepos(): Promise<Project[] | null> {
// don't fail the entire site build if the required API key for this page is missing
if (!process.env.GITHUB_TOKEN || process.env.GITHUB_TOKEN === "") {
if (!process.env.GITHUB_TOKEN) {
console.warn(`ERROR: I can't fetch any GitHub projects without "GITHUB_TOKEN" set! Skipping for now...`);
return null;

View File

@ -11,12 +11,13 @@ const sitemap = async (): Promise<MetadataRoute.Sitemap> => {
const routes: MetadataRoute.Sitemap = [
{
// homepage
url: `${config.baseUrl}/`,
url: config.baseUrl,
priority: 1.0,
lastModified: new Date(process.env.RELEASE_DATE || Date.now()), // timestamp frozen when a new build is deployed
},
{ url: `${config.baseUrl}/tweets/` },
{ url: `${config.baseUrl}/y2k/` },
{ url: `${config.baseUrl}/stats` },
{ url: `${config.baseUrl}/tweets` },
{ url: `${config.baseUrl}/y2k` },
];
// add each directory in the app folder as a route (excluding special routes)
@ -34,7 +35,7 @@ const sitemap = async (): Promise<MetadataRoute.Sitemap> => {
).forEach((route) => {
routes.push({
// remove matching page.(tsx|mdx) file and make all URLs absolute
url: `${config.baseUrl}/${route.replace(/page\.(tsx|mdx)$/, "")}`,
url: `${config.baseUrl}/${route.replace(/\/page\.(tsx|mdx)$/, "")}`,
});
});

View File

@ -61,7 +61,7 @@ export const getFrontMatter = async (slug: string): Promise<FrontMatter> => {
htmlTitle,
slug,
date: formatDate(frontmatter.date), // validate/normalize the date string provided from front matter
permalink: `${config.baseUrl}/${POSTS_DIR}/${slug}/`,
permalink: `${config.baseUrl}/${POSTS_DIR}/${slug}`,
image: frontmatter.image ? `${config.baseUrl}${frontmatter.image}` : undefined,
};
};

View File

@ -20,6 +20,6 @@ export function middleware(request: NextRequest) {
export const config = {
// save compute time by skipping middleware for static and metadata files
matcher: [
"/((?!_next/static|_next/image|_vercel|static|.well-known|favicon.ico|icon.png|apple-icon.png|manifest.webmanifest).*)",
"/((?!_next/static|_next/image|_stream|_vercel|static|.well-known|favicon.ico|icon.png|apple-icon.png|manifest.webmanifest).*)",
],
};

View File

@ -5,7 +5,6 @@ import * as mdxPlugins from "./lib/helpers/remark-rehype-plugins";
const nextConfig: NextConfig = {
reactStrictMode: true,
trailingSlash: true,
productionBrowserSourceMaps: true,
env: {
// freeze timestamp at build time for when server-side pages need a "last updated" date. calling Date.now() from
@ -43,16 +42,20 @@ const nextConfig: NextConfig = {
],
rewrites: async () => ({
beforeFiles: [
// https://github.com/jakejarvis/tweets/deployments/github-pages
// https://umami.is/docs/guides/running-on-vercel#proxy-umami-analytics-via-vercel
{
source: "/tweets/:path*/",
destination: "https://jakejarvis.github.io/tweets/:path*/",
source: "/_stream/u/script.js",
destination: `${process.env.NEXT_PUBLIC_UMAMI_HOST || "https://cloud.umami.is"}/script.js`,
},
{
// workaround for broken trailing slash redirects:
// https://github.com/vercel/next.js/discussions/36219#discussioncomment-4167863
source: "/_stream/u/api/:path*",
destination: `${process.env.NEXT_PUBLIC_UMAMI_HOST || "https://cloud.umami.is"}/api/:path*`,
},
// https://github.com/jakejarvis/tweets
{
source: "/tweets/:path*",
destination: "https://jakejarvis.github.io/tweets/:path*",
destination: "https://tweets-khaki.vercel.app/:path*",
},
],
afterFiles: [
@ -66,6 +69,11 @@ const nextConfig: NextConfig = {
}),
redirects: async () => [
{ source: "/y2k", destination: "https://y2k.pages.dev", permanent: false },
{
source: "/stats",
destination: "https://umami-wine-eight.vercel.app/share/wwTaTpLgC6gP9VyX/jarv.is",
permanent: false,
},
// NOTE: don't remove this, it ensures de-AMPing the site hasn't offended our google overlords too badly!
// https://developers.google.com/search/docs/advanced/experience/remove-amp#remove-only-amp

View File

@ -16,20 +16,19 @@
"start": "next start",
"lint": "next lint --no-cache",
"typecheck": "tsc",
"postinstall": "prisma generate"
"postinstall": "prisma generate --no-hints"
},
"dependencies": {
"@emotion/hash": "^0.9.2",
"@giscus/react": "^3.1.0",
"@mdx-js/loader": "^3.1.0",
"@mdx-js/react": "^3.1.0",
"@next/bundle-analyzer": "15.2.2-canary.6",
"@next/mdx": "15.2.2-canary.6",
"@next/third-parties": "15.2.2-canary.6",
"@next/bundle-analyzer": "15.2.2-canary.7",
"@next/mdx": "15.2.2-canary.7",
"@next/third-parties": "15.2.2-canary.7",
"@octokit/graphql": "^8.2.1",
"@octokit/graphql-schema": "^15.26.0",
"@prisma/client": "^6.4.1",
"@vercel/analytics": "^1.5.0",
"clsx": "^2.1.1",
"comma-number": "^2.1.0",
"copy-to-clipboard": "^3.3.3",
@ -37,7 +36,7 @@
"fast-glob": "^3.3.3",
"feed": "^4.2.2",
"modern-normalize": "^3.0.1",
"next": "15.2.2-canary.6",
"next": "15.2.2-canary.7",
"obj-str": "^1.1.0",
"p-map": "^7.0.3",
"p-memoize": "^7.1.1",
@ -79,7 +78,7 @@
"@types/react-is": "^19.0.0",
"cross-env": "^7.0.3",
"eslint": "^9.22.0",
"eslint-config-next": "15.2.2-canary.6",
"eslint-config-next": "15.2.2-canary.7",
"eslint-config-prettier": "^10.1.1",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
@ -100,7 +99,7 @@
"engines": {
"node": ">=20.x"
},
"packageManager": "pnpm@10.6.1+sha512.40ee09af407fa9fbb5fbfb8e1cb40fbb74c0af0c3e10e9224d7b53c7658528615b2c92450e74cfad91e3a2dcafe3ce4050d80bda71d757756d2ce2b66213e9a3",
"packageManager": "pnpm@10.6.2+sha512.47870716bea1572b53df34ad8647b42962bc790ce2bf4562ba0f643237d7302a3d6a8ecef9e4bdfc01d23af1969aa90485d4cebb0b9638fa5ef1daef656f6c1b",
"cacheDirectories": [
"node_modules",
".next/cache"

166
pnpm-lock.yaml generated
View File

@ -21,14 +21,14 @@ importers:
specifier: ^3.1.0
version: 3.1.0(@types/react@19.0.10)(react@19.0.0)
'@next/bundle-analyzer':
specifier: 15.2.2-canary.6
version: 15.2.2-canary.6
specifier: 15.2.2-canary.7
version: 15.2.2-canary.7
'@next/mdx':
specifier: 15.2.2-canary.6
version: 15.2.2-canary.6(@mdx-js/loader@3.1.0(acorn@8.14.1))(@mdx-js/react@3.1.0(@types/react@19.0.10)(react@19.0.0))
specifier: 15.2.2-canary.7
version: 15.2.2-canary.7(@mdx-js/loader@3.1.0(acorn@8.14.1))(@mdx-js/react@3.1.0(@types/react@19.0.10)(react@19.0.0))
'@next/third-parties':
specifier: 15.2.2-canary.6
version: 15.2.2-canary.6(next@15.2.2-canary.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)
specifier: 15.2.2-canary.7
version: 15.2.2-canary.7(next@15.2.2-canary.7(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)
'@octokit/graphql':
specifier: ^8.2.1
version: 8.2.1
@ -38,9 +38,6 @@ importers:
'@prisma/client':
specifier: ^6.4.1
version: 6.4.1(prisma@6.4.1(typescript@5.8.2))(typescript@5.8.2)
'@vercel/analytics':
specifier: ^1.5.0
version: 1.5.0(next@15.2.2-canary.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)
clsx:
specifier: ^2.1.1
version: 2.1.1
@ -63,8 +60,8 @@ importers:
specifier: ^3.0.1
version: 3.0.1
next:
specifier: 15.2.2-canary.6
version: 15.2.2-canary.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
specifier: 15.2.2-canary.7
version: 15.2.2-canary.7(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
obj-str:
specifier: ^1.1.0
version: 1.1.0
@ -184,8 +181,8 @@ importers:
specifier: ^9.22.0
version: 9.22.0
eslint-config-next:
specifier: 15.2.2-canary.6
version: 15.2.2-canary.6(eslint@9.22.0)(typescript@5.8.2)
specifier: 15.2.2-canary.7
version: 15.2.2-canary.7(eslint@9.22.0)(typescript@5.8.2)
eslint-config-prettier:
specifier: ^10.1.1
version: 10.1.1(eslint@9.22.0)
@ -605,17 +602,17 @@ packages:
'@types/react': '>=16'
react: '>=16'
'@next/bundle-analyzer@15.2.2-canary.6':
resolution: {integrity: sha512-PlraPKmOD0FbLCxwT44ncjH5oR7fUJPE7RC7jXra4QS6zJoH0zaREt0BEvmm1BbwjQBFRIiaJqtCmM+btDRrAA==}
'@next/bundle-analyzer@15.2.2-canary.7':
resolution: {integrity: sha512-VC24nH2u5sIr0+dySVIqCzPkxx75O1VQXgnlAtxdj2BZuWUWgA3MY7nl/4aMERI3Iz670slt1eeO8J/uPJE9/w==}
'@next/env@15.2.2-canary.6':
resolution: {integrity: sha512-gpYplVqEis/ANjpYIR6cmLOCwm7rZnQAEtCpsFbhYVkQzZ/NsknERvXoQ0qnSTwCNEe8pa12RThcie4y20LFzw==}
'@next/env@15.2.2-canary.7':
resolution: {integrity: sha512-j1y9ucHqzNNbEN6Jqd7AWimUYzk/oG00SbDb9IaGX/61J6aOKTF5cSZ8AAgkm2IqhvELaXfOhk/hHwG8N0I2uQ==}
'@next/eslint-plugin-next@15.2.2-canary.6':
resolution: {integrity: sha512-HN7pRJcuABHlqwM+Jt0if13lX56DZgIkQs48MBMeG/BeAZ4NG9CLpEG6hpRCCh+AhJ7Oj8rLuKfuiqv1FmtJlg==}
'@next/eslint-plugin-next@15.2.2-canary.7':
resolution: {integrity: sha512-wuxlmTw3PiRwHOdlb+43vH9ggcS9HLLzC3nROkFp3AWjj/ZQg71T0zybB64Vu8OicYoLTwaZOJP/EFDYLpHTMA==}
'@next/mdx@15.2.2-canary.6':
resolution: {integrity: sha512-z2slR7FQSOQHI3LrYeX6hRqAWurmpudOmDY4QUvnDN4UMF3SvmR3Y4nigraGocQripSTaruSTXgAoQsZeP6Pig==}
'@next/mdx@15.2.2-canary.7':
resolution: {integrity: sha512-CZzPi6YQvA86IE0EqkeIn9Qh95baOLZ/0yqXsMBhHOwx9nV1g9twOEFGP0ro0DM+7R++e32N7zCEaBG7PTi+zA==}
peerDependencies:
'@mdx-js/loader': '>=0.15.0'
'@mdx-js/react': '>=0.15.0'
@ -625,56 +622,56 @@ packages:
'@mdx-js/react':
optional: true
'@next/swc-darwin-arm64@15.2.2-canary.6':
resolution: {integrity: sha512-MyjhCU1GInYgiaWkfzqPnikOJPkYAEZuRgXDoF3qkYEwEjFeTHp2aimrAVln16JmIb5nTcLEWSBkVt9UHb/ucA==}
'@next/swc-darwin-arm64@15.2.2-canary.7':
resolution: {integrity: sha512-C2++v9N6LowkahZj9IsuJ0JIzD/mVkGJ189iS1TM+zc39UyOJ1U6dgyW6MZ9ogDO+p4l9Tj8tO0S2ZU0DXmUwA==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
'@next/swc-darwin-x64@15.2.2-canary.6':
resolution: {integrity: sha512-e9Xk71UVqTQ3QmLuHJWW4doBr9/zlrJqha4fCuDb0/6ZaRNnG0s3oIEdSEWK/jTdlKWAv3v/ev+2ILpV78Mr2g==}
'@next/swc-darwin-x64@15.2.2-canary.7':
resolution: {integrity: sha512-dikxwyTTdbHnqt+ISiCBv9TZFDdpusXkvIM5Ldwxfeqe5wzBXRyJp8dDs6JSJ871txqInt3aZrUQy73MdL9kfA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
'@next/swc-linux-arm64-gnu@15.2.2-canary.6':
resolution: {integrity: sha512-Zacy/jimGiggcQ1EiJWqp8lajKILKLFnWzXiQjrroTApjQ7wtVQVUivatlCet9621c3+wYCzQ4jhn2JOLjy70w==}
'@next/swc-linux-arm64-gnu@15.2.2-canary.7':
resolution: {integrity: sha512-t26JgARXfqbsVFJriQyb2ID4mJMsr8JZRmNZgj5YJK3Ybhnp/xFGWE7QxIZcYdvkrNzzRZr28xZYg2dwEnE5OQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
'@next/swc-linux-arm64-musl@15.2.2-canary.6':
resolution: {integrity: sha512-NA7EWymvTUMr1pZYD1qf0RqH/muUiKGKiQY87+u0HZalgNR2BqxvpENVBWJtOOWqgO6jGEUWSBcNsiyfXvhbEg==}
'@next/swc-linux-arm64-musl@15.2.2-canary.7':
resolution: {integrity: sha512-o8o/ck07RxkYya5K6FzMB6LGtLkN7E6rEFXOhSQsMrwvz0cSjeALWVwYsVEtZmEEywwor1RPLxQM+ndTUo0KUA==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
'@next/swc-linux-x64-gnu@15.2.2-canary.6':
resolution: {integrity: sha512-/JgT1ETMQM9ZdglbD5FvL/+UpqeE1C2mIht/TZxScSFbr+DC/mwO3CIQ0sQcDsavJJCSa1mds6zq8a+MxmFScA==}
'@next/swc-linux-x64-gnu@15.2.2-canary.7':
resolution: {integrity: sha512-JVNNQzrz9wZ0MJNUQwN/KtLCjnm3zAn+j5pe3GjDTHoLcBmO/5YFp0TP/BF2sGSUTic6tgsvU/5lxHuB0Zo49A==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
'@next/swc-linux-x64-musl@15.2.2-canary.6':
resolution: {integrity: sha512-iv6S41lwRbFiX1X1N7rH5hYSqDs5xm4p36yLWztCstNFk1TNR6xxAR/NlOvIwdQcYMnKDq19XjOQUezTOvhcVA==}
'@next/swc-linux-x64-musl@15.2.2-canary.7':
resolution: {integrity: sha512-+8EVLgVk6zNYeTngx+qgXNr8gPlyrKh8gxrvUp5Zu2RdYoPxCLlockgMCQmvOTVfzM6h3GXXPcwMBnJIzFd18Q==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
'@next/swc-win32-arm64-msvc@15.2.2-canary.6':
resolution: {integrity: sha512-rmK8ew7FeoBHLNNOEDGAvxNgHF8uI39KVjo23xzXJO2Ze93ghZwXQQ4a3Kjnsn5ZoWbt7um4phzZwSFMnehCsA==}
'@next/swc-win32-arm64-msvc@15.2.2-canary.7':
resolution: {integrity: sha512-rnoDG7VPT5vr9HJOfUuDYp2xQKNeMDLYbLuS/xySrKnyhEYYJRm0leNRNOtOxMyg4nSQf5Yr2e1MFuAU8/hByw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
'@next/swc-win32-x64-msvc@15.2.2-canary.6':
resolution: {integrity: sha512-g9Lo9jEgpHyXDpJuD3h1FeqDuG4Z2PkKFH0OHMK7RhHN2JiWvpW5cnQM6Lgd2wm+BKDNp8VhSfa3fSu2k8kfMg==}
'@next/swc-win32-x64-msvc@15.2.2-canary.7':
resolution: {integrity: sha512-5eKM1usgTg5H3Mpr275Tdvmr+obdxJbis5MTIxTFNWVw4KbxM4NW3GVbG43Z71DkizLm92AVtqO6O3YoB6bSvA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
'@next/third-parties@15.2.2-canary.6':
resolution: {integrity: sha512-05977Uhvg1/GTDGyKtjiiZQaaEMYKEy91tuA2GJkIODSIt2nJMHcRO5Allk0voyq14V5CJIhjHTT7/N1DyJFEg==}
'@next/third-parties@15.2.2-canary.7':
resolution: {integrity: sha512-d7gsLyprMrFy5FOCHn2t4W2alVs6gIVKcdnSpQrRmMOK6kkc2Qm+AzFpzzALjgdTjGYq38gYjoup5Kbf0iRiZQ==}
peerDependencies:
next: ^13.0.0 || ^14.0.0 || ^15.0.0
react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
@ -934,32 +931,6 @@ packages:
'@ungap/structured-clone@1.3.0':
resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
'@vercel/analytics@1.5.0':
resolution: {integrity: sha512-MYsBzfPki4gthY5HnYN7jgInhAZ7Ac1cYDoRWFomwGHWEX7odTEzbtg9kf/QSo7XEsEAqlQugA6gJ2WS2DEa3g==}
peerDependencies:
'@remix-run/react': ^2
'@sveltejs/kit': ^1 || ^2
next: '>= 13'
react: ^18 || ^19 || ^19.0.0-rc
svelte: '>= 4'
vue: ^3
vue-router: ^4
peerDependenciesMeta:
'@remix-run/react':
optional: true
'@sveltejs/kit':
optional: true
next:
optional: true
react:
optional: true
svelte:
optional: true
vue:
optional: true
vue-router:
optional: true
abbrev@2.0.0:
resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
@ -1399,8 +1370,8 @@ packages:
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
engines: {node: '>=12'}
eslint-config-next@15.2.2-canary.6:
resolution: {integrity: sha512-faID8Wsab1cnVRx4aSao3OVB/Gwx8rsom5knR+W7oBEva3RSkk1cp5a4NSiykTMY+Mxdjig6kFPnWm9rprQV+g==}
eslint-config-next@15.2.2-canary.7:
resolution: {integrity: sha512-/wGWOrfR/S66JnRDGqUVes/tl/s91zA4e/L2g1I3xJNErnU5S1QcV5Io+FJbNYxFsynHtGp0EXqwra3CUbSPHw==}
peerDependencies:
eslint: ^7.23.0 || ^8.0.0 || ^9.0.0
typescript: '>=3.3.1'
@ -2366,8 +2337,8 @@ packages:
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
next@15.2.2-canary.6:
resolution: {integrity: sha512-jowOxjbyuuw4Vncbxux5HlGSeJg89goGiXXwYZu+Zc5nThNzX8gHCZEZdg0FXp/QPVCgHYIqiBBcfLJj0xwIPQ==}
next@15.2.2-canary.7:
resolution: {integrity: sha512-oQt/T9SPT4nhVWwNH3YkPo11GjfmOxImdlAtttkENzOiHDC782ec6HFR/4IZDGJrlHS54zf9mmKG2I6f099kgg==}
engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0}
hasBin: true
peerDependencies:
@ -3618,53 +3589,53 @@ snapshots:
'@types/react': 19.0.10
react: 19.0.0
'@next/bundle-analyzer@15.2.2-canary.6':
'@next/bundle-analyzer@15.2.2-canary.7':
dependencies:
webpack-bundle-analyzer: 4.10.1
transitivePeerDependencies:
- bufferutil
- utf-8-validate
'@next/env@15.2.2-canary.6': {}
'@next/env@15.2.2-canary.7': {}
'@next/eslint-plugin-next@15.2.2-canary.6':
'@next/eslint-plugin-next@15.2.2-canary.7':
dependencies:
fast-glob: 3.3.1
'@next/mdx@15.2.2-canary.6(@mdx-js/loader@3.1.0(acorn@8.14.1))(@mdx-js/react@3.1.0(@types/react@19.0.10)(react@19.0.0))':
'@next/mdx@15.2.2-canary.7(@mdx-js/loader@3.1.0(acorn@8.14.1))(@mdx-js/react@3.1.0(@types/react@19.0.10)(react@19.0.0))':
dependencies:
source-map: 0.7.4
optionalDependencies:
'@mdx-js/loader': 3.1.0(acorn@8.14.1)
'@mdx-js/react': 3.1.0(@types/react@19.0.10)(react@19.0.0)
'@next/swc-darwin-arm64@15.2.2-canary.6':
'@next/swc-darwin-arm64@15.2.2-canary.7':
optional: true
'@next/swc-darwin-x64@15.2.2-canary.6':
'@next/swc-darwin-x64@15.2.2-canary.7':
optional: true
'@next/swc-linux-arm64-gnu@15.2.2-canary.6':
'@next/swc-linux-arm64-gnu@15.2.2-canary.7':
optional: true
'@next/swc-linux-arm64-musl@15.2.2-canary.6':
'@next/swc-linux-arm64-musl@15.2.2-canary.7':
optional: true
'@next/swc-linux-x64-gnu@15.2.2-canary.6':
'@next/swc-linux-x64-gnu@15.2.2-canary.7':
optional: true
'@next/swc-linux-x64-musl@15.2.2-canary.6':
'@next/swc-linux-x64-musl@15.2.2-canary.7':
optional: true
'@next/swc-win32-arm64-msvc@15.2.2-canary.6':
'@next/swc-win32-arm64-msvc@15.2.2-canary.7':
optional: true
'@next/swc-win32-x64-msvc@15.2.2-canary.6':
'@next/swc-win32-x64-msvc@15.2.2-canary.7':
optional: true
'@next/third-parties@15.2.2-canary.6(next@15.2.2-canary.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)':
'@next/third-parties@15.2.2-canary.7(next@15.2.2-canary.7(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)':
dependencies:
next: 15.2.2-canary.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
next: 15.2.2-canary.7(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
react: 19.0.0
third-party-capital: 1.0.20
@ -3979,11 +3950,6 @@ snapshots:
'@ungap/structured-clone@1.3.0': {}
'@vercel/analytics@1.5.0(next@15.2.2-canary.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)':
optionalDependencies:
next: 15.2.2-canary.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
react: 19.0.0
abbrev@2.0.0: {}
acorn-jsx@5.3.2(acorn@8.14.1):
@ -4513,9 +4479,9 @@ snapshots:
escape-string-regexp@5.0.0: {}
eslint-config-next@15.2.2-canary.6(eslint@9.22.0)(typescript@5.8.2):
eslint-config-next@15.2.2-canary.7(eslint@9.22.0)(typescript@5.8.2):
dependencies:
'@next/eslint-plugin-next': 15.2.2-canary.6
'@next/eslint-plugin-next': 15.2.2-canary.7
'@rushstack/eslint-patch': 1.10.5
'@typescript-eslint/eslint-plugin': 8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0)(typescript@5.8.2))(eslint@9.22.0)(typescript@5.8.2)
'@typescript-eslint/parser': 8.26.0(eslint@9.22.0)(typescript@5.8.2)
@ -5959,9 +5925,9 @@ snapshots:
natural-compare@1.4.0: {}
next@15.2.2-canary.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
next@15.2.2-canary.7(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
dependencies:
'@next/env': 15.2.2-canary.6
'@next/env': 15.2.2-canary.7
'@swc/counter': 0.1.3
'@swc/helpers': 0.5.15
busboy: 1.6.0
@ -5971,14 +5937,14 @@ snapshots:
react-dom: 19.0.0(react@19.0.0)
styled-jsx: 5.1.6(react@19.0.0)
optionalDependencies:
'@next/swc-darwin-arm64': 15.2.2-canary.6
'@next/swc-darwin-x64': 15.2.2-canary.6
'@next/swc-linux-arm64-gnu': 15.2.2-canary.6
'@next/swc-linux-arm64-musl': 15.2.2-canary.6
'@next/swc-linux-x64-gnu': 15.2.2-canary.6
'@next/swc-linux-x64-musl': 15.2.2-canary.6
'@next/swc-win32-arm64-msvc': 15.2.2-canary.6
'@next/swc-win32-x64-msvc': 15.2.2-canary.6
'@next/swc-darwin-arm64': 15.2.2-canary.7
'@next/swc-darwin-x64': 15.2.2-canary.7
'@next/swc-linux-arm64-gnu': 15.2.2-canary.7
'@next/swc-linux-arm64-musl': 15.2.2-canary.7
'@next/swc-linux-x64-gnu': 15.2.2-canary.7
'@next/swc-linux-x64-musl': 15.2.2-canary.7
'@next/swc-win32-arm64-msvc': 15.2.2-canary.7
'@next/swc-win32-x64-msvc': 15.2.2-canary.7
sharp: 0.33.5
transitivePeerDependencies:
- '@babel/core'

View File

@ -32,6 +32,7 @@
- Vercel
- Neon Postgres
- Prisma
- Umami
- Giscus
- Resend
- ...and more: https://jarv.is/uses/