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

deploy to Vercel

This commit is contained in:
Jake Jarvis 2021-06-04 10:19:34 -04:00
parent 034babd9af
commit 82c42f8322
Signed by: jake
GPG Key ID: 2B0C9CF251E69A39
23 changed files with 236 additions and 3823 deletions

View File

@ -11,7 +11,7 @@
"es6": true
},
"overrides": [{
"files": ["functions/**/*.js"],
"files": ["api/**/*.js"],
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module"

View File

@ -1,100 +0,0 @@
name: CI
on:
push:
branches:
- main
pull_request:
jobs:
deploy:
runs-on: ubuntu-latest
# "[skip ci]" also causes Netlify to skip, so these are automatically in harmony
# https://docs.netlify.com/site-deploys/manage-deploys/#skip-a-deploy
if: "github.actor == 'jakejarvis' && !contains(github.event.head_commit.message, '[skip ci]')"
timeout-minutes: 20
steps:
- name: Wait for Netlify
# installing via `npx` each run takes a long time, but deploys always take longer
run: npx netlify-cli watch
env:
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
audit:
runs-on: ubuntu-latest
needs: deploy
env:
LHCI_TOKEN: ${{ secrets.LHCI_TOKEN }}
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 2
lfs: false
- uses: actions/setup-node@v2
with:
node-version: 16.x
- name: Install LHCI
run: npm install -g @lhci/cli
- name: Check LHCI
run: |
lhci --version
lhci healthcheck
- name: Audit deploy preview
if: "github.event_name == 'pull_request'"
continue-on-error: true
run: |
lhci autorun \
--collect.url=https://deploy-preview-${{ github.event.number }}--jakejarvis.netlify.app/ \
--collect.url=https://deploy-preview-${{ github.event.number }}--jakejarvis.netlify.app/notes/how-to-pull-request-fork-github/
- name: Audit production site
if: "github.event_name == 'push' && github.ref == 'refs/heads/main'"
continue-on-error: true
run: |
lhci autorun \
--collect.url=https://jarv.is/ \
--collect.url=https://jarv.is/notes/how-to-pull-request-fork-github/
- name: Upload results as artifact
uses: actions/upload-artifact@v2
if: success()
with:
name: lhci-results
path: ./.lighthouseci
lint:
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, '[skip ci]')"
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 1
lfs: false
- uses: actions/setup-node@v2
with:
node-version: 16.x
- name: Get Yarn cache path
# https://github.com/actions/cache/blob/master/examples.md#node---yarn
# https://github.com/actions/cache/issues/60
id: yarn-cache
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Cache dependencies
uses: actions/cache@v2
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install dependencies
run: yarn install --no-ignore-optional --frozen-lockfile
- name: Audit dependencies
run: yarn audit || true
continue-on-error: true
- name: Build preview
run: yarn build:hugo --environment development --baseURL / --buildDrafts --buildFuture
- name: Lint
run: yarn lint
- name: Percy snapshots
uses: percy/snapshot-action@v0.1.2
env:
PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}

View File

@ -1,71 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ main ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
schedule:
- cron: '41 7 * * 6'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'javascript' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
- run: |
yarn install --no-ignore-optional --frozen-lockfile
yarn build:functions
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View File

@ -1,15 +0,0 @@
name: Purge old artifacts
on:
schedule:
- cron: '0 9 * * 3' # every Wednesday at 9 AM UTC == 5 AM EDT
workflow_dispatch:
jobs:
purge-artifacts:
runs-on: ubuntu-latest
steps:
- uses: kolpav/purge-artifacts-action@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
expire-in: 0

4
.gitignore vendored
View File

@ -11,8 +11,8 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local Netlify config
.netlify/
# local Vercel config
.vercel/
# Lighthouse CI
.lighthouseci/

View File

@ -16,9 +16,10 @@ postcss.config.js
devcontainer.json
# miscellaneous
vercel.json
.vercel/
.github/
.lighthouseci/
.netlify/
.vscode/
LICENSE.md
content/notes/dark-mode/example.html

View File

@ -1,13 +1,12 @@
# 🏡  [jarv.is](https://jarv.is/)
[![Netlify](https://img.shields.io/netlify/a7403a53-fd9d-44c0-a708-a84d9fc1454d?logo=netlify&logoColor=white)](https://app.netlify.com/sites/jakejarvis/deploys)
[![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/jakejarvis/jarv.is/CI/main?label=build&logo=github&logoColor=white)](https://github.com/jakejarvis/jarv.is/actions?query=workflow%3ACI+branch%3Amain)
[![Hugo v0.83.1](https://img.shields.io/badge/hugo-0.83.1-ff4088?logo=hugo&logoColor=white)](https://github.com/gohugoio/hugo)
[![Licensed under CC-BY-4.0](https://img.shields.io/badge/license-CC--BY--4.0-fb7828?logo=creative-commons&logoColor=white)](LICENSE.md)
[![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)
[![Tor mirror status](https://img.shields.io/uptimerobot/status/m788172098-a4fcb769c8779f9a37a60775?color=7e4798&label=tor%20mirror&logo=tor-project&logoColor=white)](http://jarvis2i2vp4j4tbxjogsnqdemnte5xhzyi7hziiyzxwge3hzmh57zad.onion/)
Personal website of [@jakejarvis](https://github.com/jakejarvis), created and deployed using [Hugo](https://github.com/gohugoio/hugo), [Netlify](https://www.netlify.com/), [and more](https://jarv.is/uses/).
Personal website of [@jakejarvis](https://github.com/jakejarvis), created and deployed using [Hugo](https://github.com/gohugoio/hugo), [Vercel](https://vercel.com/), [and more](https://jarv.is/uses/).
I keep an ongoing list of [blog post ideas](https://github.com/jakejarvis/jarv.is/issues/1) and [coding to-dos](https://github.com/jakejarvis/jarv.is/issues/11) as issues in this repo.

View File

@ -6,20 +6,16 @@ const numeral = require("numeral");
const pluralize = require("pluralize");
require("dotenv").config();
// .....??????
// https://github.com/netlify/netlify-lambda/issues/201
require("encoding");
exports.handler = async (event) => {
const { slug } = event.queryStringParameters;
module.exports = async (req, res) => {
const { slug } = req.query;
try {
// some rudimentary error handling
if (!process.env.FAUNADB_SERVER_SECRET) {
throw new Error("Database credentials aren't set.");
}
if (event.httpMethod !== "GET") {
throw new Error(`Method ${event.httpMethod} not allowed.`);
if (req.method !== "GET") {
throw new Error(`Method ${req.method} not allowed.`);
}
if (!slug || slug === "/") {
throw new Error("Parameter `slug` is required.");
@ -33,32 +29,21 @@ exports.handler = async (event) => {
const result = await client.query(q.Call(q.Function("hit"), slug));
// send client the new hit count
return {
statusCode: 200,
headers: {
"Content-Type": "application/json; charset=utf-8",
"Cache-Control": "private, no-cache, no-store, must-revalidate",
Expires: "0",
Pragma: "no-cache",
"Access-Control-Allow-Methods": "GET",
"Access-Control-Allow-Origin": "*",
},
body: JSON.stringify({
slug: result.data.slug,
hits: result.data.hits,
pretty_hits: numeral(result.data.hits).format("0,0"),
pretty_unit: pluralize("hit", result.data.hits),
}),
};
res.setHeader("Cache-Control", "private, no-cache, no-store, must-revalidate");
res.setHeader("Expires", 0);
res.setHeader("Pragma", "no-cache");
res.setHeader("Access-Control-Allow-Methods", "GET");
res.setHeader("Access-Control-Allow-Origin", "*");
return res.json({
slug: result.data.slug,
hits: result.data.hits,
pretty_hits: numeral(result.data.hits).format("0,0"),
pretty_unit: pluralize("hit", result.data.hits),
});
} catch (error) {
console.error(error);
return {
statusCode: 400,
body: JSON.stringify({
message: error.message,
}),
};
return res.status(400).json({ message: error.message });
}
};

View File

@ -64,11 +64,11 @@ async function fetchRepos(sort, limit) {
return currentRepos;
}
exports.handler = async (event) => {
module.exports = async (req, res) => {
try {
// some rudimentary error handling
if (event.httpMethod !== "GET") {
throw new Error(`Method ${event.httpMethod} not allowed.`);
if (req.method !== "GET") {
throw new Error(`Method ${req.method} not allowed.`);
}
if (!process.env.GH_PUBLIC_TOKEN) {
throw new Error("GitHub API credentials aren't set.");
@ -77,27 +77,18 @@ exports.handler = async (event) => {
// default to latest repos
let sortBy = "PUSHED_AT";
// get most popular repos (/projects?top)
if (typeof event.queryStringParameters.top !== "undefined") sortBy = "STARGAZERS";
if (typeof req.query.top !== "undefined") sortBy = "STARGAZERS";
const repos = await fetchRepos(sortBy, 16);
return {
statusCode: 200,
headers: {
"Content-Type": "application/json; charset=utf-8",
"Access-Control-Allow-Methods": "GET",
"Access-Control-Allow-Origin": "*",
},
body: JSON.stringify(repos),
};
// let Vercel edge cache results for 10 mins
res.setHeader("Cache-Control", "s-maxage=600, stale-while-revalidate");
res.setHeader("Access-Control-Allow-Methods", "GET");
res.setHeader("Access-Control-Allow-Origin", "*");
return res.json(repos);
} catch (error) {
console.error(error);
return {
statusCode: 400,
body: JSON.stringify({
message: error.message,
}),
};
return res.status(400).json({ message: error.message });
}
};

View File

@ -9,14 +9,14 @@ require("dotenv").config();
const baseUrl = "https://jarv.is/";
exports.handler = async (event) => {
module.exports = async (req, res) => {
try {
// some rudimentary error handling
if (!process.env.FAUNADB_SERVER_SECRET) {
throw new Error("Database credentials aren't set.");
}
if (event.httpMethod !== "GET") {
throw new Error(`Method ${event.httpMethod} not allowed.`);
if (req.method !== "GET") {
throw new Error(`Method ${req.method} not allowed.`);
}
const parser = new rssParser({
@ -73,23 +73,12 @@ exports.handler = async (event) => {
stats.total.pretty_hits = numeral(stats.total.hits).format("0,0");
stats.total.pretty_unit = pluralize("hit", stats.total.hits);
return {
statusCode: 200,
headers: {
"Content-Type": "application/json; charset=utf-8",
"Access-Control-Allow-Methods": "GET",
"Access-Control-Allow-Origin": "*",
},
body: JSON.stringify(stats),
};
res.setHeader("Access-Control-Allow-Methods", "GET");
res.setHeader("Access-Control-Allow-Origin", "*");
return res.json(stats);
} catch (error) {
console.error(error);
return {
statusCode: 400,
body: JSON.stringify({
message: error.message,
}),
};
return res.status(400).json({ message: error.message });
}
};

View File

@ -16,7 +16,7 @@
// this will return an error from the API anyways
if (!slug || slug === "/") return;
fetch("/api/hits?slug=" + slug)
fetch("/api/hits/?slug=" + slug)
.then((response) => response.json())
.then((data) => {
if (typeof data.hits !== "undefined") {

View File

@ -3,7 +3,7 @@
var wrapper = document.getElementById("github-cards");
if (wrapper) {
fetch("/api/projects?top")
fetch("/api/projects/?top")
.then((response) => response.json())
.then((data) => {
data.forEach((repo) => {

View File

@ -21,9 +21,6 @@ disableKinds = ["taxonomy", "term"]
# don't worry, inserted manually :)
disableHugoGeneratorInject = true
# prefer Netlify's _redirects file, see outputs below
disableAliases = true
[params]
description = "Hi there! I'm a frontend web developer based in Boston, Massachusetts specializing in the JAMstack, modern JavaScript frameworks, and progressive web apps."
image = "img/logo.png" # relative to assetDir root
@ -96,7 +93,7 @@ disableAliases = true
weight = 4
[outputs]
home = ["HTML", "RSS", "ATOM", "MANIFEST", "REDIRECTS", "HEADERS"]
home = ["HTML", "RSS", "ATOM", "MANIFEST"]
section = ["HTML"]
page = ["HTML"]
@ -116,24 +113,12 @@ disableAliases = true
baseName = "site" # /site.webmanifest
isPlainText = true
notAlternative = true
[outputFormats.REDIRECTS]
mediaType = "text/netlify"
baseName = "_redirects"
isPlainText = true
notAlternative = true
[outputFormats.HEADERS]
mediaType = "text/netlify"
baseName = "_headers"
isPlainText = true
notAlternative = true
[mediaTypes]
[mediaTypes."application/atom+xml"]
suffixes = ["atom"]
[mediaTypes."application/manifest+json"]
suffixes = ["webmanifest"]
[mediaTypes."text/netlify"]
delimiter = "" # no dot/extension for _headers & _redirects files
[sitemap]
filename = "sitemap.xml"
@ -183,14 +168,3 @@ disableAliases = true
writeStats = true
# don't use cache for SCSS compilation, better to throw error than be stale
useResourceCacheWhen = "never"
[server]
# proxy /api requests to netlify-lambda's local server (port 9337) for each function
[[server.redirects]]
from = "/api/**"
to = "http://localhost:9337/"
status = 200
[[server.headers]]
for = "/**"
[server.headers.values]
Access-Control-Allow-Origin = "*"

View File

@ -30,8 +30,7 @@
# TECHNOLOGY
Hugo
Netlify
GitHub Actions
Vercel
...and much more: https://jarv.is/uses/
# VIEW SOURCE

View File

@ -15,7 +15,7 @@ This website uses a simple hit counter on each post to tally an aggregate number
## Hosting
Pages and first-party assets on this website are served by [**Netlify**](https://www.netlify.com/). Refer to their [privacy policy](https://www.netlify.com/privacy/) and [GDPR statement](https://www.netlify.com/gdpr/) for more information.
Pages and first-party assets on this website are served by [**Vercel**](https://vercel.com/). Refer to their [privacy policy](https://vercel.com/legal/privacy-policy) for more information.
For a likely excessive level of privacy and security, this website is also mirrored on the [🧅 Tor network](https://www.torproject.org/) at: [**jarvis2i2vp4j4tbxjogsnqdemnte5xhzyi7hziiyzxwge3hzmh57zad.onion**](http://jarvis2i2vp4j4tbxjogsnqdemnte5xhzyi7hziiyzxwge3hzmh57zad.onion).

View File

@ -172,7 +172,7 @@ I've been making recent efforts to [de-Google](https://www.stallman.org/google.h
Other geeky stuff:
- [**DNSimple**](https://dnsimple.com/) [(referral link)](https://dnsimple.com/r/eb6ced548f1e0a) & [**Cloudflare**](https://www.cloudflare.com/) for domain DNS.
- [**Netlify**](https://www.netlify.com/) for static sites.
- [**Netlify**](https://www.netlify.com/) and [**Vercel**](https://vercel.com/) for static sites.
- [**Linode**](https://www.linode.com/) [(referral link)](https://www.linode.com/?r=0c5aeace9bd591be9fbf32f96f58470295f1ee05) and [**DigitalOcean**](https://www.digitalocean.com/) [(referral link)](https://m.do.co/c/afcf288a7dac) for virtual Linux servers.
- [**Backblaze**](https://www.backblaze.com/) [(referral link)](https://secure.backblaze.com/r/00x84e) for off-site MacBook backups.
- [**Gitea**](https://gitea.io/en-us/) as a [self-hosted](https://code.jarv.is/) Git backup/mirror.

View File

@ -1,16 +0,0 @@
# Cache static assets (webfonts, emojis, etc.) for a long time (1 month)
/vendor/*
Cache-Control: max-age=2628000
# Recommended MIME type for PWA manifests:
# https://github.com/w3c/manifest/issues/689
/site.webmanifest
Content-Type: application/manifest+json
# Set matching Onion-Location headers for each permalink
{{- range $page := .Site.Pages }}
{{- range .AlternativeOutputFormats }}
{{ .RelPermalink }}
Onion-Location: {{ $.Site.Params.baseOnionURL }}{{ .RelPermalink }}
{{ end -}}
{{ end -}}

View File

@ -1,26 +0,0 @@
/index.php* / 301
/feed /feed.xml 301
/rss /feed.xml 301
/index.xml /feed.xml 301
{{- with .Site.Params.social.webmentionIO }}
/xmlrpc.php https://webmention.io/{{ . }}/xmlrpc 302
{{ end -}}
/favicon.ico /img/favicon.ico 200
/favicon-* /img/favicon-:splat 200
/apple-touch-icon.png /img/apple-touch-icon.png 200
/apple-touch-icon-precomposed.png /img/apple-touch-icon.png 200
/safari-pinned-tab.svg /img/safari-pinned-tab.svg 200
# Hugo aliases: prefer HTTP 301 redirects over meta tags
{{- range $page := .Site.Pages }}
{{- range .Aliases }}
{{ . }} {{ $page.RelPermalink }} 301
{{- end }}
{{- end }}
# Redirect old AMP URLs to the normal HTML page
{{- range $page := .Site.Pages }}
{{ print .RelPermalink "amp.html" }} {{ .RelPermalink }} 301!
{{ end -}}

View File

@ -1,4 +1,4 @@
{{ if .Site.Params.social.webmentionIO }}
<link rel="pingback" href="{{ "api/ping" | absURL }}">
<link rel="webmention" href="{{ "api/mention" | absURL }}">
{{ with .Site.Params.social.webmentionIO }}
<link rel="webmention" href="https://webmention.io/{{ . }}/webmention">
<link rel="pingback" href="https://webmention.io/{{ . }}/xmlrpc">
{{ end }}

View File

@ -1,253 +0,0 @@
[build]
command = "yarn build"
publish = "public"
functions = ".netlify/functions"
[build.environment]
NODE_VERSION = "16"
YARN_VERSION = "1.22.10"
YARN_FLAGS = "--no-ignore-optional --frozen-lockfile"
# Ensure *only* Pretty URLs are enabled, even though this is already set up in
# the Netlify dashboard.
[build.processing]
skip_processing = false
[build.processing.css]
bundle = false
minify = false
[build.processing.js]
bundle = false
minify = false
[build.processing.html]
pretty_urls = true
[build.processing.images]
compress = false
[context.deploy-preview]
command = "yarn build:functions && yarn build:hugo --environment development --baseURL $DEPLOY_PRIME_URL --buildDrafts --buildFuture"
[context.branch-deploy]
command = "yarn build:functions && yarn build:hugo --environment development --baseURL $DEPLOY_PRIME_URL --buildDrafts --buildFuture"
# https://github.com/netlify/cli/blob/master/docs/netlify-dev.md#netlifytoml-dev-block
[dev]
framework = "#custom"
# only start Hugo, `netlify dev` builds/serves functions itself
command = "yarn start:hugo --port=1338 --baseURL=/ --appendPort=false --disableLiveReload"
# swap ports to keep consistent w/ normal local server
targetPort = 1338
port = 1337
# don't launch browser automatically
autoLaunch = false
# Enable local Netlify build plugins:
[[plugins]]
package = "@netlify/plugin-local-install-core"
# Cache resoures between builds:
# https://github.com/jakejarvis/netlify-plugin-cache
[[plugins]]
package = "netlify-plugin-cache"
[plugins.inputs]
paths = ["public", "builds", "_vendor"]
# List cached resources for debugging:
# [[plugins]]
# package = "netlify-plugin-debug-cache"
# The most important headers and redirects are specified in the _headers and
# _redirects files generated by Hugo. These are additional custom rules, mostly
# unrelated to the actual website.
# Global security headers:
[[headers]]
for = "/*"
[headers.values]
Content-Security-Policy = '''
default-src 'self';
base-uri 'none';
connect-src 'self' api.github.com platform.twitter.com;
font-src 'self';
form-action 'none';
frame-ancestors 'self';
frame-src 'self' jakejarvis.github.io buttons.github.io codepen.io cdpn.io platform.twitter.com www.youtube-nocookie.com;
img-src 'self' data: https:;
manifest-src 'self';
media-src 'self' data: https:;
object-src 'none';
script-src 'self' buttons.github.io gist.github.com syndication.twitter.com platform.twitter.com 'sha256-1j1MKfE70TTCp5KmiC2YImxw2RMS52uCH5yXl1heG9U=' 'sha256-y3Xr/40/KQnUvqk/kZO5us6t3i/I49BsbYjsH8ELhVg=' 'sha256-JGG0npUp+0ABq/NY1azjpQ0WBtm+m5gU58mzF+2DCXY=';
style-src 'self' 'unsafe-inline' github.githubassets.com;
worker-src 'self';
block-all-mixed-content;
report-uri https://jarv.is/api/csp_wizard;
report-to default'''
NEL = '''
{"report_to":"default","max_age":604800}'''
Report-To = '''
{"group":"default","max_age":604800,"endpoints":[{"url":"https://jarv.is/api/report"}],"include_subdomains":false}'''
# More generic security headers:
Feature-Policy = "accelerometer 'none'; camera 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; payment 'none'; usb 'none'"
Permissions-Policy = "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), interest-cohort=()"
Referrer-Policy = "no-referrer-when-downgrade"
X-Content-Type-Options = "nosniff"
X-Frame-Options = "SAMEORIGIN"
X-XSS-Protection = "1; mode=block"
X-Got-Milk = "2%"
X-View-Source = "https://github.com/jakejarvis/jarv.is"
# PGP key: open in browser, download correctly
[[headers]]
for = "/pubkey.asc"
[headers.values]
Cache-Control = "no-cache"
Content-Type = "text/plain; charset=UTF-8"
Content-Disposition = "inline; filename=\"pubkey.asc\""
# Redirect Netlify and www subdomains to primary domain:
[[redirects]]
from = "https://jakejarvis.netlify.com/*"
to = "https://jarv.is/:splat"
status = 301
force = true
[[redirects]]
from = "https://jakejarvis.netlify.app/*"
to = "https://jarv.is/:splat"
status = 301
force = true
[[redirects]]
from = "https://www.jarv.is/*"
to = "https://jarv.is/:splat"
status = 301
force = true
# External API redirects/mirrors:
# Must set `force = true` and wildcard /api/* rule goes last.
## Report URI endpoints
[[redirects]]
from = "/api/report"
to = "https://jarvis.report-uri.com/a/d/g"
status = 200
force = true
[[redirects]]
from = "/api/csp_wizard"
to = "https://jarvis.report-uri.com/r/d/csp/enforce"
status = 200
force = true
## Webmention.io endpoints
[[redirects]]
from = "/api/mention"
to = "https://webmention.io/jarv.is/webmention"
status = 200
force = true
[[redirects]]
from = "/api/ping"
to = "https://webmention.io/jarv.is/xmlrpc"
status = 200
force = true
## Prettier URLs for Netlify Functions
[[redirects]]
from = "/api/*"
to = "/.netlify/functions/:splat"
status = 200
# More miscellaneous mirrors/redirects:
[[redirects]]
from = "/blog/*"
to = "/notes/"
status = 301
[[redirects]]
from = "/archives/*"
to = "/notes/"
status = 301
[[redirects]]
from = "/resume"
to = "/resume.pdf"
status = 302
# Fix some 404s after moving files around somewhat recklessly:
[[redirects]]
from = "/keybase.txt"
to = "/.well-known/keybase.txt"
status = 301
[[redirects]]
from = "/jarvis.asc"
to = "/pubkey.asc"
status = 301
[[redirects]]
from = "/img/logo.svg"
to = "/img/favicon.svg"
status = 302
[[redirects]]
from = "/img/me_large.jpg"
to = "/img/me.jpg"
status = 301
[[redirects]]
from = "/me.jpg"
to = "/img/me.jpg"
status = 301
[[redirects]]
from = "/me_large.jpg"
to = "/img/me.jpg"
status = 301
[[redirects]]
from = "/img/me_hu1c1a997e30e234e83718deb8b3f52283_130509_320x320_resize_q90_lanczos.jpg"
to = "/img/me.jpg"
status = 301
[[redirects]]
from = "/twemoji/svg/*"
to = "/vendor/emoji/svg/:splat"
status = 301
[[redirects]]
from = "/vendor/inter/*"
to = "/vendor/fonts/:splat"
status = 301
# Moved these random sites/projects elsewhere (mostly GitHub Pages) to keep
# this repo and domain squeaky clean:
[[redirects]]
from = "/y2k/*"
to = "https://jakejarvis.github.io/my-first-website/:splat"
status = 302
[[redirects]]
from = "/ios-trackers/*"
to = "https://jakejarvis.github.io/ios-trackers/:splat"
status = 302
[[redirects]]
from = "/awesome/*"
to = "https://synonymsforawesome.com/"
status = 302
[[redirects]]
from = "/hugo-node/*"
to = "https://github.com/jakejarvis/hugo-extended"
status = 302
[[redirects]]
from = "/comp20/*"
to = "https://jakejarvis.github.io/comp20/:splat"
status = 302
[[redirects]]
from = "/scrabble/*"
to = "https://jakejarvis.github.io/scrabble/:splat"
status = 302
# H A C K E R M A N ( ͡° ͜ʖ ͡°)
[[redirects]]
from = "*/wp-admin/*"
to = "/403.html"
status = 403
[[redirects]]
from = "*/admin/*"
to = "/403.html"
status = 403
[[redirects]]
from = "*/wp-login.php"
to = "/403.html"
status = 403
[[redirects]]
from = "*/login.php"
to = "/403.html"
status = 403
[[redirects]]
from = "*/wlwmanifest.xml"
to = "/403.html"
status = 403
[[redirects]]
from = "*/.git/*"
to = "/403.html"
status = 403

View File

@ -14,13 +14,10 @@
"url": "git+https://github.com/jakejarvis/jarv.is.git"
},
"scripts": {
"clean": "rimraf public/ resources/ builds/ _vendor/ .netlify/{cache,functions}/ $TMPDIR/hugo_cache/ hugo_stats.json",
"start": "run-p start:**",
"start:hugo": "hugo server --disableFastRender --buildDrafts --buildFuture --port=1337 --baseURL=/ --appendPort=false --bind=0.0.0.0 --verbose",
"start:functions": "netlify-lambda serve --port 9337 functions",
"clean": "rimraf public/ resources/ builds/ _vendor/ .vercel/cache/ $TMPDIR/hugo_cache/ hugo_stats.json",
"start": "hugo server --buildDrafts --buildFuture --port=${PORT:-1337} --baseURL=/ --appendPort=false --bind=0.0.0.0 --verbose",
"build": "run-s build:** minify:**",
"build:hugo": "hugo --gc --cleanDestinationDir --verbose",
"build:functions": "netlify-lambda build functions",
"minify:html": "html-minifier --html5 --collapse-whitespace --collapse-boolean-attributes --preserve-line-breaks --minify-css --remove-comments --file-ext html --input-dir public --output-dir public **/*.html",
"minify:js": "terser --compress passes=3,negate_iife=false,keep_fargs=false,sequences=false,reduce_vars=false --mangle reserved=['sa','sa_event'] --output public/js/app.js -- public/js/app.js",
"minify:img": "glob-exec --parallel --foreach 'public/**/{img,images}/' -- imagemin '{{file.path}}*' --plugin=mozjpeg --plugin.mozjpeg.progressive --plugin.mozjpeg.quality=85 --plugin=pngquant --plugin.pngquant.quality={0.1,0.3} --plugin.pngquant.speed=1 --plugin.pngquant.strip --plugin=gifsicle --plugin=svgo --out-dir='{{file.path}}'",
@ -37,7 +34,6 @@
"@fontsource/inter": "4.4.2",
"@fontsource/roboto-mono": "4.4.2",
"dotenv": "^10.0.0",
"encoding": "^0.1.13",
"faunadb": "fauna/faunadb-js#master",
"graphql": "^15.5.0",
"graphql-request": "^3.4.0",
@ -63,8 +59,6 @@
"imagemin-cli": "^6.0.0",
"lint-staged": "^11.0.0",
"markdownlint-cli": "~0.27.1",
"netlify-lambda": "^2.0.8",
"netlify-plugin-cache": "^1.0.3",
"npm-run-all": "^4.1.5",
"postcss": "^8.3.0",
"postcss-clean": "jakejarvis/postcss-clean#master",
@ -93,10 +87,6 @@
"imagemin-pngquant": "^9.0.2",
"imagemin-svgo": "^9.0.0"
},
"engines": {
"node": "^10 || ^12 || >=14",
"yarn": "^1.22.4"
},
"simple-git-hooks": {
"pre-commit": "npx lint-staged"
},

110
vercel.json Normal file
View File

@ -0,0 +1,110 @@
{
"public": false,
"trailingSlash": true,
"rewrites": [
{ "source": "/favicon.ico", "destination": "/img/favicon.ico" },
{ "source": "/favicon-(.*)", "destination": "/img/favicon-$1xxxxxxxx" },
{ "source": "/apple-touch-icon.png", "destination": "/img/apple-touch-icon.png" },
{ "source": "/apple-touch-icon-precomposed.png", "destination": "/img/apple-touch-icon.png" },
{ "source": "/safari-pinned-tab.svg", "destination": "/img/safari-pinned-tab.svg" }
],
"redirects": [
{ "source": "/notes/:slug/amp.html", "destination": "/notes/:slug/", "statusCode": 301 },
{ "source": "/blog/(.*)", "destination": "/notes/" },
{ "source": "/archives/(.*)", "destination": "/notes/" },
{ "source": "/feed", "destination": "/feed.xml" },
{ "source": "/rss", "destination": "/feed.xml" },
{ "source": "/index.xml", "destination": "/feed.xml" },
{ "source": "/resume/", "destination": "/resume.pdf" },
{ "source": "/keybase.txt", "destination": "/.well-known/keybase.txt" },
{ "source": "/jarvis.asc", "destination": "/pubkey.asc" },
{ "source": "/img/logo.svg", "destination": "/img/favicon.svg" },
{ "source": "/img/me_large.jpg", "destination": "/img/me.jpg" },
{ "source": "/me.jpg", "destination": "/img/me.jpg" },
{ "source": "/me_large.jpg", "destination": "/img/me.jpg" },
{ "source": "/img/me_hu1c1a997e30e234e83718deb8b3f52283_130509_320x320_resize_q90_lanczos.jpg", "destination": "/img/me.jpg" },
{ "source": "/y2k/(.*)", "destination": "https://jakejarvis.github.io/my-first-website/$1" },
{ "source": "/ios-trackers/(.*)", "destination": "https://jakejarvis.github.io/ios-trackers/$1" },
{ "source": "/awesome/", "destination": "https://synonymsforawesome.com/" },
{ "source": "/hugo-node/", "destination": "https://github.com/jakejarvis/hugo-extended" },
{ "source": "/comp20/(.*)", "destination": "https://jakejarvis.github.io/comp20/$1" },
{ "source": "/scrabble/(.*)", "destination": "https://jakejarvis.github.io/scrabble/$1" }
],
"headers": [
{
"source": "/vendor/(.*)",
"headers": [
{
"key": "Cache-Control",
"value": "public, max-age=2628000"
}
]
},
{
"source": "/pubkey.asc",
"headers": [
{
"key": "Cache-Control",
"value": "private, no-cache, no-store, must-revalidate"
},
{
"key": "Content-Type",
"value": "text/plain; charset=utf-8"
}
]
},
{
"source": "/(.*)",
"headers" : [
{
"key": "Onion-Location",
"value": "http://jarvis2i2vp4j4tbxjogsnqdemnte5xhzyi7hziiyzxwge3hzmh57zad.onion/$1"
},
{
"key": "Content-Security-Policy",
"value": "default-src 'self'; base-uri 'none'; connect-src 'self' api.github.com platform.twitter.com; font-src 'self'; form-action 'none'; frame-ancestors 'self'; frame-src 'self' jakejarvis.github.io buttons.github.io codepen.io cdpn.io platform.twitter.com www.youtube-nocookie.com; img-src 'self' data: https:; manifest-src 'self'; media-src 'self' data: https:; object-src 'none'; script-src 'self' buttons.github.io gist.github.com syndication.twitter.com platform.twitter.com 'sha256-1j1MKfE70TTCp5KmiC2YImxw2RMS52uCH5yXl1heG9U=' 'sha256-y3Xr/40/KQnUvqk/kZO5us6t3i/I49BsbYjsH8ELhVg=' 'sha256-JGG0npUp+0ABq/NY1azjpQ0WBtm+m5gU58mzF+2DCXY='; style-src 'self' 'unsafe-inline' github.githubassets.com; worker-src 'self'; block-all-mixed-content; report-uri https://jarvis.report-uri.com/r/d/csp/enforce; report-to default"
},
{
"key": "Report-To",
"value": "{\"group\":\"default\",\"max_age\":604800,\"endpoints\":[{\"url\":\"https://jarvis.report-uri.com/a/d/g\"}],\"include_subdomains\":false}"
},
{
"key": "NEL",
"value": "{\"report_to\":\"default\",\"max_age\":604800}"
},
{
"key": "Feature-Policy",
"value": "accelerometer 'none'; camera 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; payment 'none'; usb 'none'"
},
{
"key": "Permissions-Policy",
"value": "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), interest-cohort=()"
},
{
"key": "Referrer-Policy",
"value": "no-referrer-when-downgrade"
},
{
"key": "X-Content-Type-Options",
"value": "nosniff"
},
{
"key": "X-Frame-Options",
"value": "SAMEORIGIN"
},
{
"key": "X-XSS-Protection",
"value": "1; mode=block"
},
{
"key": "x-view-source",
"value": "https://github.com/jakejarvis/jarv.is"
},
{
"key" : "x-got-milk",
"value" : "2%"
}
]
}
]
}

3296
yarn.lock

File diff suppressed because it is too large Load Diff