From 8c6a53fdf632a2936d32676cf700537dfb79b683 Mon Sep 17 00:00:00 2001 From: Chris Amico Date: Tue, 26 Nov 2024 20:10:04 -0500 Subject: [PATCH 1/4] Set basic cache headers on embeds --- src/config/config.js | 2 ++ src/routes/embed/documents/[id]-[slug]/+page.ts | 10 ++++++---- .../documents/[id]/annotations/[note_id]/+page.ts | 11 +++++++++-- src/routes/embed/documents/[id]/pages/[page]/+page.ts | 8 +++++++- .../embed/projects/[project_id]-[slug]/+page.ts | 9 ++++++++- 5 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/config/config.js b/src/config/config.js index 3b4222aa2..d7367060c 100644 --- a/src/config/config.js +++ b/src/config/config.js @@ -37,6 +37,8 @@ export const SIGN_IN_URL = new URL(DC_LOGIN, DC_BASE).toString(); export const SIGN_UP_URL = new URL(SQUARELET_SIGNUP, SQUARELET_BASE).toString(); export const SIGN_OUT_URL = new URL(DC_LOGOUT, DC_BASE).toString(); +export const EMBED_MAX_AGE = 60 * 10; + export const VERIFICATION_FORM_URL = "https://airtable.com/app93Yt5cwdVWTnqn/pagogIhgB1jZTzq00/form"; export const SQUARELET_ORGS_URL = diff --git a/src/routes/embed/documents/[id]-[slug]/+page.ts b/src/routes/embed/documents/[id]-[slug]/+page.ts index e6a8c54d0..a57b39c78 100644 --- a/src/routes/embed/documents/[id]-[slug]/+page.ts +++ b/src/routes/embed/documents/[id]-[slug]/+page.ts @@ -2,13 +2,13 @@ import type { ReadMode } from "$lib/api/types"; import { redirect } from "@sveltejs/kit"; +import { EMBED_MAX_AGE } from "@/config/config.js"; import { getEmbedSettings, type EmbedSettings } from "$lib/utils/embed.js"; -import { getQuery } from "$lib/utils/search.js"; import loadDocument from "$lib/load/document"; import * as documents from "$lib/api/documents"; /** @type {import('./$types').PageLoad} */ -export async function load({ fetch, url, params, depends }) { +export async function load({ fetch, url, params, depends, setHeaders }) { let { document, asset_url, mode } = await loadDocument({ fetch, url, @@ -25,13 +25,15 @@ export async function load({ fetch, url, params, depends }) { let settings: Partial = getEmbedSettings(url.searchParams); - const query = getQuery(url, "q"); + setHeaders({ + "cache-control": `public, max-age=${EMBED_MAX_AGE}`, + "last-modified": new Date(document.updated_at).toUTCString(), + }); return { document, mode, asset_url, settings, - query, }; } diff --git a/src/routes/embed/documents/[id]/annotations/[note_id]/+page.ts b/src/routes/embed/documents/[id]/annotations/[note_id]/+page.ts index cd2491313..de4ff918f 100644 --- a/src/routes/embed/documents/[id]/annotations/[note_id]/+page.ts +++ b/src/routes/embed/documents/[id]/annotations/[note_id]/+page.ts @@ -1,9 +1,11 @@ // load a note for embedding import { error } from "@sveltejs/kit"; -import * as documents from "@/lib/api/documents"; + +import { EMBED_MAX_AGE } from "@/config/config.js"; +import * as documents from "$lib/api/documents"; import * as notesApi from "$lib/api/notes"; -export async function load({ params, fetch }) { +export async function load({ params, fetch, setHeaders }) { const [document, note] = await Promise.all([ documents.get(+params.id, fetch), notesApi.get(+params.id, parseInt(params.note_id), fetch), @@ -13,6 +15,11 @@ export async function load({ params, fetch }) { return error(404, "Document not found"); } + setHeaders({ + "cache-control": `public, max-age=${EMBED_MAX_AGE}`, + "last-modified": new Date(document.data.updated_at).toUTCString(), + }); + return { document: document.data, note: note.data, diff --git a/src/routes/embed/documents/[id]/pages/[page]/+page.ts b/src/routes/embed/documents/[id]/pages/[page]/+page.ts index 2e34ece5b..7f08058e3 100644 --- a/src/routes/embed/documents/[id]/pages/[page]/+page.ts +++ b/src/routes/embed/documents/[id]/pages/[page]/+page.ts @@ -1,11 +1,12 @@ // load data for a single page embed import { error } from "@sveltejs/kit"; +import { EMBED_MAX_AGE } from "@/config/config.js"; import * as documents from "$lib/api/documents"; import * as notesApi from "$lib/api/notes"; /** @type {import('./$types').PageLoad} */ -export async function load({ params, fetch }) { +export async function load({ params, fetch, setHeaders }) { const page = +params.page; let [document, notes] = await Promise.all([ documents.get(+params.id, fetch), @@ -16,6 +17,11 @@ export async function load({ params, fetch }) { return error(404, "Document not found"); } + setHeaders({ + "cache-control": `public, max-age=${EMBED_MAX_AGE}`, + "last-modified": new Date(document.data.updated_at).toUTCString(), + }); + return { document: document.data, notes: diff --git a/src/routes/embed/projects/[project_id]-[slug]/+page.ts b/src/routes/embed/projects/[project_id]-[slug]/+page.ts index 64fcea953..0dc7ca839 100644 --- a/src/routes/embed/projects/[project_id]-[slug]/+page.ts +++ b/src/routes/embed/projects/[project_id]-[slug]/+page.ts @@ -2,13 +2,15 @@ import type { Maybe } from "$lib/api/types"; import { error, redirect } from "@sveltejs/kit"; + +import { EMBED_MAX_AGE } from "@/config/config.js"; import { search } from "$lib/api/documents"; import { get, embedUrl } from "$lib/api/projects"; const OLD_PATTERN = /(\D+)-(\d+)/; /** @type {import('./$types').PageLoad} */ -export async function load({ params, fetch, url }) { +export async function load({ params, fetch, url, setHeaders }) { // handle old URLs let { project_id, slug }: Record> = params; if (`${project_id}-${slug}`.match(OLD_PATTERN)) { @@ -35,6 +37,11 @@ export async function load({ params, fetch, url }) { return redirect(302, embedUrl(project.data)); } + setHeaders({ + "cache-control": `public, max-age=${EMBED_MAX_AGE}`, + "last-modified": new Date(project.data.updated_at).toUTCString(), + }); + return { documents, error: project.error, From 191281ece06e68507076dc3d56cf1b4c90ba7bdd Mon Sep 17 00:00:00 2001 From: Chris Amico Date: Tue, 26 Nov 2024 20:21:01 -0500 Subject: [PATCH 2/4] Set cache headers on pages --- src/config/config.js | 2 ++ src/routes/(pages)/[...path]/+page.ts | 13 +++++++++---- src/routes/(pages)/home/+page.ts | 13 ++++++++++--- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/config/config.js b/src/config/config.js index d7367060c..eea2cb78e 100644 --- a/src/config/config.js +++ b/src/config/config.js @@ -38,6 +38,8 @@ export const SIGN_UP_URL = new URL(SQUARELET_SIGNUP, SQUARELET_BASE).toString(); export const SIGN_OUT_URL = new URL(DC_LOGOUT, DC_BASE).toString(); export const EMBED_MAX_AGE = 60 * 10; +export const PAGE_MAX_AGE = 60 * 10; +export const VIEWER_MAX_AGE = 60 * 10; export const VERIFICATION_FORM_URL = "https://airtable.com/app93Yt5cwdVWTnqn/pagogIhgB1jZTzq00/form"; diff --git a/src/routes/(pages)/[...path]/+page.ts b/src/routes/(pages)/[...path]/+page.ts index 8b8bbd13b..8790ab540 100644 --- a/src/routes/(pages)/[...path]/+page.ts +++ b/src/routes/(pages)/[...path]/+page.ts @@ -1,18 +1,23 @@ // load data for flatpages import { error } from "@sveltejs/kit"; +import { PAGE_MAX_AGE } from "@/config/config.js"; import * as flatpages from "$lib/api/flatpages"; -export async function load({ fetch, params }) { +export async function load({ fetch, params, setHeaders }) { const { data, error: err } = await flatpages.get(params.path, fetch); + if (err) { + return error(err.status, { message: err.message }); + } + if (!data) { return error(404, "Page not found"); } - if (err) { - return error(err.status, { message: err.message }); - } + setHeaders({ + "cache-control": `public, max-age=${PAGE_MAX_AGE}`, + }); return data; } diff --git a/src/routes/(pages)/home/+page.ts b/src/routes/(pages)/home/+page.ts index 5c7ab0acc..a49f5e133 100644 --- a/src/routes/(pages)/home/+page.ts +++ b/src/routes/(pages)/home/+page.ts @@ -4,23 +4,30 @@ import DOMPurify from "isomorphic-dompurify"; import { marked } from "marked"; import { gfmHeadingId } from "marked-gfm-heading-id"; +import { PAGE_MAX_AGE } from "@/config/config.js"; import * as flatpages from "$lib/api/flatpages"; import { getMe } from "$lib/api/accounts"; marked.use(gfmHeadingId()); -export async function load({ fetch }) { +export async function load({ fetch, setHeaders }) { const [{ data: page, error: err }, me] = await Promise.all([ flatpages.get("/home/", fetch), getMe(fetch), ]); + if (err) { + return error(err.status, { message: err.message }); + } + if (!page) { return error(404, "Page not found"); } - if (err) { - return error(err.status, { message: err.message }); + if (!me) { + setHeaders({ + "cache-control": `public, max-age=${PAGE_MAX_AGE}`, + }); } return { From e01b4f9ba4cb5ccf170c4983d8e0dce65e523f1a Mon Sep 17 00:00:00 2001 From: Chris Amico Date: Tue, 26 Nov 2024 20:43:36 -0500 Subject: [PATCH 3/4] projects, add-ons, redirect upload if not-logged in --- src/routes/(app)/+layout.ts | 3 +++ src/routes/(app)/+page.server.ts | 6 ++++-- src/routes/(app)/add-ons/+layout.ts | 11 +++++++++- .../(app)/projects/[id]-[slug]/+page.ts | 13 ++++++++++-- src/routes/(app)/upload/+page.ts | 21 ++++++++----------- 5 files changed, 37 insertions(+), 17 deletions(-) diff --git a/src/routes/(app)/+layout.ts b/src/routes/(app)/+layout.ts index a0cb1d757..fb407d5a7 100644 --- a/src/routes/(app)/+layout.ts +++ b/src/routes/(app)/+layout.ts @@ -7,6 +7,7 @@ import type { Project, User, } from "$lib/api/types"; + import { getMe, orgUsers, userOrgs } from "$lib/api/accounts"; import { getTipOfDay } from "$lib/api/flatpages"; import { getPinnedAddons } from "$lib/api/addons"; @@ -24,6 +25,7 @@ export async function load({ fetch }) { let pinnedAddons: Promise>>> = Promise.resolve(null); let pinnedProjects: Promise = Promise.resolve([]); + if (me && org) { user_orgs = userOrgs(me, fetch).catch((e) => { console.error(e); @@ -34,6 +36,7 @@ export async function load({ fetch }) { return []; }); } + if (me) { pinnedAddons = getPinnedAddons(fetch).catch((e) => { console.error(e); diff --git a/src/routes/(app)/+page.server.ts b/src/routes/(app)/+page.server.ts index 594b3b3dc..ecaff74a9 100644 --- a/src/routes/(app)/+page.server.ts +++ b/src/routes/(app)/+page.server.ts @@ -1,8 +1,10 @@ -import { _ } from "svelte-i18n"; -import { createFeedback, type Feedback } from "@/lib/api/feedback"; import type { Actions } from "./$types"; + +import { _ } from "svelte-i18n"; import { fail } from "@sveltejs/kit"; +import { createFeedback, type Feedback } from "$lib/api/feedback"; + export const actions = { feedback: async ({ request, fetch }) => { const data = await request.formData(); diff --git a/src/routes/(app)/add-ons/+layout.ts b/src/routes/(app)/add-ons/+layout.ts index 40c6f5a6e..a2b48cde4 100644 --- a/src/routes/(app)/add-ons/+layout.ts +++ b/src/routes/(app)/add-ons/+layout.ts @@ -1,9 +1,18 @@ +import { VIEWER_MAX_AGE } from "@/config/config.js"; import { breadcrumbTrail } from "$lib/utils/navigation"; -export async function load({ parent }) { +export async function load({ parent, setHeaders }) { + const { me } = await parent(); const breadcrumbs = await breadcrumbTrail(parent, [ { href: "/add-ons/", title: "Add-Ons" }, ]); + + if (!me) { + setHeaders({ + "max-age": `public, max-age=${VIEWER_MAX_AGE}`, + }); + } + return { breadcrumbs, }; diff --git a/src/routes/(app)/projects/[id]-[slug]/+page.ts b/src/routes/(app)/projects/[id]-[slug]/+page.ts index 578166830..e99ceaf86 100644 --- a/src/routes/(app)/projects/[id]-[slug]/+page.ts +++ b/src/routes/(app)/projects/[id]-[slug]/+page.ts @@ -7,13 +7,13 @@ import type { import { error, redirect } from "@sveltejs/kit"; -import { DEFAULT_PER_PAGE } from "@/config/config.js"; +import { DEFAULT_PER_PAGE, VIEWER_MAX_AGE } from "@/config/config.js"; import * as projects from "$lib/api/projects"; import * as collaborators from "$lib/api/collaborators"; import { search } from "$lib/api/documents"; import { breadcrumbTrail } from "$lib/utils/navigation"; -export async function load({ params, url, parent, data, fetch }) { +export async function load({ params, url, parent, data, fetch, setHeaders }) { const id = parseInt(params.id, 10); const [project, users]: [ @@ -42,6 +42,8 @@ export async function load({ params, url, parent, data, fetch }) { { href: url.pathname, title: project.data.title }, ]); + const { me } = await parent(); + const query = url.searchParams.get("q") ?? ""; const cursor = url.searchParams.get("cursor") ?? ""; const per_page = +(url.searchParams.get("per_page") || DEFAULT_PER_PAGE); @@ -51,6 +53,13 @@ export async function load({ params, url, parent, data, fetch }) { fetch, ); + if (!me) { + setHeaders({ + "cache-control": `public, max-age=${VIEWER_MAX_AGE}`, + "last-modified": new Date(project.data.updated_at).toUTCString(), + }); + } + return { ...(data ?? {}), // include csrf_token breadcrumbs, diff --git a/src/routes/(app)/upload/+page.ts b/src/routes/(app)/upload/+page.ts index bc08ef904..e827f983e 100644 --- a/src/routes/(app)/upload/+page.ts +++ b/src/routes/(app)/upload/+page.ts @@ -1,25 +1,22 @@ /** * Data loading for upload */ - +import { redirect } from "@sveltejs/kit"; import * as projectsApi from "$lib/api/projects"; export async function load({ fetch, parent }) { const { me } = await parent(); - if (me) { - const projects = await projectsApi.list( - { per_page: 100, user: me.id }, - fetch, - ); - - return { - projects: projects.data, - }; + if (!me) { + return redirect(302, "/home/"); } - // anonymous gets empty results + const projects = await projectsApi.list( + { per_page: 100, user: me.id }, + fetch, + ); + return { - projects: { results: [] }, + projects: projects.data, }; } From 266f7fd90e678b603ff0d231a533289f36a52a80 Mon Sep 17 00:00:00 2001 From: Chris Amico Date: Tue, 26 Nov 2024 20:46:52 -0500 Subject: [PATCH 4/4] documents --- src/routes/(app)/documents/+layout.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/routes/(app)/documents/+layout.ts b/src/routes/(app)/documents/+layout.ts index a169797e3..55da3cd3b 100644 --- a/src/routes/(app)/documents/+layout.ts +++ b/src/routes/(app)/documents/+layout.ts @@ -1,10 +1,19 @@ import { breadcrumbTrail } from "$lib/utils/navigation"; -export async function load({ parent }) { +import { VIEWER_MAX_AGE } from "@/config/config.js"; + +export async function load({ parent, setHeaders }) { + const { me } = await parent(); const breadcrumbs = await breadcrumbTrail(parent, [ { href: "/documents/", title: "Documents" }, ]); + if (!me) { + setHeaders({ + "max-age": `public, max-age=${VIEWER_MAX_AGE}`, + }); + } + return { breadcrumbs, };