diff --git a/.env.test b/.env.test
index 0f034e22..3896b778 100644
--- a/.env.test
+++ b/.env.test
@@ -7,6 +7,8 @@ UNILOGIN_API_URL=https://et-broker.unilogin.dk
UNILOGIN_CLIENT_ID=https://stg.ereolengo.itkdev.dk/
UNILOGIN_CLIENT_SECRET=XXX
UNILOGIN_SESSION_SECRET=XXX
+UNILOGIN_WELLKNOWN_URL=https://hi-i-am-well-known-url.com
NEXT_PUBLIC_APP_URL=https://hellboy.the-movie.com
-UNILOGIN_WELLKNOWN_URL=https://hi-i-am-well-known-url.com
+
+REVALIDATE_CACHE_SECRET=i9yUwqwgVLfvQ+4f8TnNRZcmHOYOKuUOTpZraUIWUCc=
diff --git a/__tests__/revalidating-cache.test.ts b/__tests__/revalidating-cache.test.ts
new file mode 100644
index 00000000..f05c4081
--- /dev/null
+++ b/__tests__/revalidating-cache.test.ts
@@ -0,0 +1,181 @@
+// @vitest-environment node
+import { testApiHandler } from "next-test-api-route-handler"
+import { revalidatePath, revalidateTag } from "next/cache"
+import { describe, test } from "vitest"
+
+// @ts-ignore
+import * as revalidateCacheHandler from "@/app/cache/revalidate/route"
+
+vi.mock("next/cache", () => ({
+ revalidatePath: vi.fn(),
+ revalidateTag: vi.fn(),
+}))
+
+beforeEach(() => {
+ // Mock the revalidatePath and revalidateTag functions
+ // @ts-ignore
+ revalidatePath.mockReturnValue(true)
+ // @ts-ignore
+ revalidateTag.mockReturnValue(true)
+})
+
+describe("Revalidate cache test access via bearer token", () => {
+ test("That the cache revalidation endpoint returns 401 if no bearer token is provided", async () => {
+ await testApiHandler({
+ appHandler: revalidateCacheHandler,
+ url: `/cache/revalidate`,
+ async test({ fetch }) {
+ const res = await fetch({
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ type: "tag", tags: ["tag1", "tag2"] }),
+ })
+ expect(res.status).toBe(401)
+ },
+ })
+ })
+
+ test("That the cache revalidation endpoint returns 200 if a valid bearer token is provided", async () => {
+ await testApiHandler({
+ appHandler: revalidateCacheHandler,
+ url: `/cache/revalidate`,
+ async test({ fetch }) {
+ const res = await fetch({
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: "Bearer i9yUwqwgVLfvQ+4f8TnNRZcmHOYOKuUOTpZraUIWUCc=",
+ },
+ body: JSON.stringify({ type: "tag", tags: ["tag1", "tag2"] }),
+ })
+ expect(res.status).toBe(200)
+ },
+ })
+ })
+})
+
+describe("Revalidate cache test combination of payloads", () => {
+ test("That the cache revalidation endpoint returns 422 upon wrong input", async () => {
+ await testApiHandler({
+ appHandler: revalidateCacheHandler,
+ url: `/cache/revalidate`,
+ async test({ fetch }) {
+ const res = await fetch({
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: "Bearer i9yUwqwgVLfvQ+4f8TnNRZcmHOYOKuUOTpZraUIWUCc=",
+ },
+ body: JSON.stringify({ type: "unknown-type" }),
+ })
+ expect(res.status).toBe(422)
+ },
+ })
+
+ await testApiHandler({
+ appHandler: revalidateCacheHandler,
+ url: `/cache/revalidate`,
+ async test({ fetch }) {
+ const res = await fetch({
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: "Bearer i9yUwqwgVLfvQ+4f8TnNRZcmHOYOKuUOTpZraUIWUCc=",
+ },
+ body: JSON.stringify({ type: "tag", theTags: ["tag1", "tag2"] }),
+ })
+ expect(res.status).toBe(422)
+ },
+ })
+ })
+
+ test("That the cache revalidation endpoint returns 200 upon successful tag invalidation", async () => {
+ await testApiHandler({
+ appHandler: revalidateCacheHandler,
+ url: `/cache/revalidate`,
+ async test({ fetch }) {
+ const res = await fetch({
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: "Bearer i9yUwqwgVLfvQ+4f8TnNRZcmHOYOKuUOTpZraUIWUCc=",
+ },
+ body: JSON.stringify({ type: "tag", tags: ["tag1", "tag2"] }),
+ })
+ expect(res.status).toBe(200)
+ },
+ })
+ })
+
+ test("That the cache revalidation endpoint returns 200 upon successful path invalidation", async () => {
+ await testApiHandler({
+ appHandler: revalidateCacheHandler,
+ url: `/cache/revalidate`,
+ async test({ fetch }) {
+ const res = await fetch({
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: "Bearer i9yUwqwgVLfvQ+4f8TnNRZcmHOYOKuUOTpZraUIWUCc=",
+ },
+ body: JSON.stringify({ type: "path", paths: ["/some/path", "/some/path"] }),
+ })
+ expect(res.status).toBe(200)
+ },
+ })
+ })
+})
+
+describe("Revalidate cache test different path and tag formats", async () => {
+ test("That the cache revalidation endpoint returns 422 if a wrongly formatted path is given", async () => {
+ await testApiHandler({
+ appHandler: revalidateCacheHandler,
+ url: `/cache/revalidate`,
+ async test({ fetch }) {
+ const res = await fetch({
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: "Bearer i9yUwqwgVLfvQ+4f8TnNRZcmHOYOKuUOTpZraUIWUCc=",
+ },
+ body: JSON.stringify({ type: "path", paths: ["some/path", "/some/path"] }),
+ })
+ expect(res.status).toBe(422)
+ },
+ })
+ })
+ test("That the cache revalidation endpoint returns 422 if a wrongly formatted path is given", async () => {
+ await testApiHandler({
+ appHandler: revalidateCacheHandler,
+ url: `/cache/revalidate`,
+ async test({ fetch }) {
+ const res = await fetch({
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: "Bearer i9yUwqwgVLfvQ+4f8TnNRZcmHOYOKuUOTpZraUIWUCc=",
+ },
+ body: JSON.stringify({ type: "path", paths: ["/some/*path", "/some/path"] }),
+ })
+ expect(res.status).toBe(422)
+ },
+ })
+ })
+ test("That the cache revalidation endpoint returns 422 if a wrongly formatted tag is given", async () => {
+ await testApiHandler({
+ appHandler: revalidateCacheHandler,
+ url: `/cache/revalidate`,
+ async test({ fetch }) {
+ const res = await fetch({
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: "Bearer i9yUwqwgVLfvQ+4f8TnNRZcmHOYOKuUOTpZraUIWUCc=",
+ },
+ body: JSON.stringify({ type: "tag", paths: ["!wrong-tag", "another tag"] }),
+ })
+ expect(res.status).toBe(422)
+ },
+ })
+ })
+})
diff --git a/app/article/[id]/article.dpl-cms.graphql b/app/article/[id]/article.dpl-cms.graphql
deleted file mode 100644
index 165345ba..00000000
--- a/app/article/[id]/article.dpl-cms.graphql
+++ /dev/null
@@ -1,14 +0,0 @@
-query getArticle($id: ID!) {
- nodeArticle(id: $id) {
- title
- subtitle
- paragraphs {
- __typename
- ... on ParagraphTextBody {
- body {
- value
- }
- }
- }
- }
-}
diff --git a/app/article/[id]/loadArticle.ts b/app/article/[id]/loadArticle.ts
deleted file mode 100644
index 5f91e267..00000000
--- a/app/article/[id]/loadArticle.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import getQueryClient from "@/lib/getQueryClient"
-import { GetArticleQuery, useGetArticleQuery } from "@/lib/graphql/generated/dpl-cms/graphql"
-
-const loadArticle = async (id: string) => {
- const queryClient = getQueryClient()
-
- const data = await queryClient.fetchQuery({
- queryKey: useGetArticleQuery.getKey({ id }),
- queryFn: useGetArticleQuery.fetcher({ id }),
- })
-
- return data
-}
-
-export default loadArticle
diff --git a/app/article/[id]/page.tsx b/app/article/[id]/page.tsx
deleted file mode 100644
index 5fbd9598..00000000
--- a/app/article/[id]/page.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import { Suspense } from "react"
-
-import loadArticle from "./loadArticle"
-
-const Page = async (props: { params: Promise<{ id: string }> }) => {
- const params = await props.params
-
- const { id } = params
-
- const data = await loadArticle(id)
- return (
- Loading...
}>
- {JSON.stringify(data, null, 2)}
-
- )
-}
-
-export default Page
diff --git a/app/artikel/[...pathElements]/article.dpl-cms.graphql b/app/artikel/[...pathElements]/article.dpl-cms.graphql
new file mode 100644
index 00000000..b655210a
--- /dev/null
+++ b/app/artikel/[...pathElements]/article.dpl-cms.graphql
@@ -0,0 +1,35 @@
+query getArticle($id: ID!) {
+ nodeArticle(id: $id) {
+ title
+ subtitle
+ paragraphs {
+ __typename
+ ... on ParagraphTextBody {
+ body {
+ value
+ }
+ }
+ }
+ }
+}
+
+query getArticleByRoute($path: String!) {
+ route(path: $path) {
+ ... on RouteInternal {
+ entity {
+ ... on NodeArticle {
+ title
+ subtitle
+ paragraphs {
+ __typename
+ ... on ParagraphTextBody {
+ body {
+ value
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/artikel/[...pathElements]/loadArticle.ts b/app/artikel/[...pathElements]/loadArticle.ts
new file mode 100644
index 00000000..8e75e61b
--- /dev/null
+++ b/app/artikel/[...pathElements]/loadArticle.ts
@@ -0,0 +1,15 @@
+import { fetcher } from "@/lib/graphql/fetchers/dpl-cms.fetcher"
+import {
+ GetArticleByRouteDocument,
+ GetArticleByRouteQuery,
+} from "@/lib/graphql/generated/dpl-cms/graphql"
+
+const loadArticle = async (path: string) => {
+ const data = await fetcher(GetArticleByRouteDocument, {
+ path,
+ })()
+
+ return data
+}
+
+export default loadArticle
diff --git a/app/artikel/[...pathElements]/loadArticlesSsg.ts b/app/artikel/[...pathElements]/loadArticlesSsg.ts
new file mode 100644
index 00000000..6ca2eeb6
--- /dev/null
+++ b/app/artikel/[...pathElements]/loadArticlesSsg.ts
@@ -0,0 +1,45 @@
+// import getQueryClient from "@/lib/getQueryClient"
+// import {
+// ExtractArticlesQuery,
+// useExtractArticlesQuery,
+// } from "@/lib/graphql/generated/dpl-cms/graphql"
+
+// const loadArticlesSsg = async () => {
+// const queryClient = getQueryClient()
+// const pageSize = 100
+// // We have a while loop.
+// // Just to be safe we do not allow more than 100 iterations.
+// const maxRuns = 100
+// let runNumber = 0
+
+// const {
+// nodeArticles: { nodes, edges, pageInfo },
+// } = await queryClient.fetchQuery({
+// queryKey: useExtractArticlesQuery.getKey({ pageSize }),
+// queryFn: useExtractArticlesQuery.fetcher({ pageSize }),
+// })
+// let allNodes = nodes
+// let allEdges = edges
+// let cursor = edges[edges.length - 1]?.cursor
+
+// while (pageInfo.hasNextPage && runNumber < maxRuns) {
+// const {
+// nodeArticles: { nodes: newNodes, edges: newEdges },
+// } = await queryClient.fetchQuery({
+// queryKey: useExtractArticlesQuery.getKey({ pageSize, cursor }),
+// queryFn: useExtractArticlesQuery.fetcher({ pageSize, cursor }),
+// })
+
+// allNodes = [...allNodes, ...newNodes]
+// allEdges = [...allEdges, ...newEdges]
+// cursor = newEdges[newEdges.length - 1]?.cursor
+// // eslint-disable-next-line no-console
+// console.log({ allNodes, allEdges, cursor })
+
+// runNumber += 1
+// }
+
+// return { nodes: allNodes }
+// }
+
+// export default loadArticlesSsg
diff --git a/app/artikel/[...pathElements]/page.tsx b/app/artikel/[...pathElements]/page.tsx
new file mode 100644
index 00000000..04f09830
--- /dev/null
+++ b/app/artikel/[...pathElements]/page.tsx
@@ -0,0 +1,19 @@
+import loadArticle from "./loadArticle"
+
+// import loadArticlesSsg from "./loadArticlesSsg"
+
+const Page = async (props: { params: Promise<{ pathElements: string[] }> }) => {
+ const params = await props.params
+
+ const { pathElements } = params
+
+ const path = [...pathElements].join("/")
+ const data = await loadArticle(path)
+ return {JSON.stringify(data, null, 2)}
+}
+
+export default Page
+
+export async function generateStaticParams() {
+ return []
+}
diff --git a/app/auth/token/refresh/route.ts b/app/auth/token/refresh/route.ts
deleted file mode 100644
index 26d57980..00000000
--- a/app/auth/token/refresh/route.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import { NextRequest, NextResponse } from "next/server"
-import * as client from "openid-client"
-import { z } from "zod"
-
-import goConfig from "@/lib/config/goConfig"
-import { getUniloginClientConfig } from "@/lib/session/oauth/uniloginClient"
-import { getSession, setTokensOnSession } from "@/lib/session/session"
-import { TTokenSet } from "@/lib/types/session"
-
-const sessionTokenSchema = z.object({
- isLoggedIn: z.boolean(),
- access_token: z.string(),
- refresh_token: z.string(),
-})
-
-export async function GET(request: NextRequest, response: NextResponse) {
- const appUrl = String(goConfig("app.url"))
- const config = await getUniloginClientConfig()
- // TODO: Fix refresh token flow with new openid-client.
-
- const session = await getSession()
- const frontpage = `${appUrl}/`
-
- // If the user is not logged in, we redirect to the frontpage.
- if (!session.isLoggedIn) {
- return NextResponse.redirect(frontpage, { headers: response.headers })
- }
- const redirect = request.nextUrl.searchParams.get("redirect")
- // We need the redirect URL to be present in the query string.
- if (!redirect) {
- return NextResponse.redirect(frontpage, { headers: response.headers })
- }
-
- try {
- // TODO: Consider if we want to handle different types of sessions than unilogin.
- const tokens = sessionTokenSchema.parse(session)
- const newTokens = client.refreshTokenGrant(config, tokens.refresh_token) as unknown as TTokenSet
- setTokensOnSession(session, newTokens)
- await session.save()
- } catch (error) {
- // TODO: maybe distinguish between ZodError and other errors?
- // TODO: Should we redirect to an end-of-session page?
- // Session is corrupt so we need to destroy it.
- session.destroy()
-
- const isZodError = error instanceof z.ZodError
- console.error(isZodError ? JSON.stringify(error.errors) : error)
- } finally {
- return NextResponse.redirect(redirect, { headers: response.headers })
- }
-}
-
-export const dynamic = "force-dynamic"
diff --git a/app/cache/revalidate/helper.ts b/app/cache/revalidate/helper.ts
new file mode 100644
index 00000000..710560b2
--- /dev/null
+++ b/app/cache/revalidate/helper.ts
@@ -0,0 +1,32 @@
+import { z } from "zod"
+
+export const paramsSchema = z.union([
+ z.object({
+ type: z.literal("tag"),
+ tags: z.array(z.string().regex(/^[a-zA-Z0-9-]+$/)),
+ }),
+ z.object({
+ type: z.literal("path"),
+ paths: z.array(z.string().regex(/^\/[a-zA-Z0-9-\/]+$/)),
+ contentType: z.string().optional(),
+ }),
+])
+
+export const resolveRevalidationPath = ({
+ path,
+ params,
+}: {
+ path: string
+ params: z.infer
+}) => {
+ if (params.type !== "path") {
+ return
+ }
+
+ switch (params.contentType ?? "unknown") {
+ case "article":
+ return `/artikel${path}`
+ case "unknown":
+ return path
+ }
+}
diff --git a/app/cache/revalidate/route.ts b/app/cache/revalidate/route.ts
new file mode 100644
index 00000000..b9b81cba
--- /dev/null
+++ b/app/cache/revalidate/route.ts
@@ -0,0 +1,61 @@
+import { revalidatePath, revalidateTag } from "next/cache"
+import { NextRequest, NextResponse } from "next/server"
+import { z } from "zod"
+
+import goConfig from "@/lib/config/goConfig"
+
+import { resolveRevalidationPath } from "./helper"
+
+const paramsSchema = z.union([
+ z.object({
+ type: z.literal("tag"),
+ tags: z.array(z.string().regex(/^[a-zA-Z0-9-:]+$/)),
+ }),
+ z.object({
+ type: z.literal("path"),
+ paths: z.array(z.string().regex(/^\/[a-zA-Z0-9-\/]+$/)),
+ contentType: z.string().optional(),
+ }),
+])
+
+export async function POST(request: NextRequest) {
+ const secret = goConfig("cache.revalidate.secret")
+ const authToken = (request.headers.get("authorization") ?? "").split("Bearer ").at(1)
+
+ if (!authToken || authToken !== secret) {
+ return NextResponse.json({ error: "Not authorized" }, { status: 401 })
+ }
+
+ const body = await request.json()
+ try {
+ const params = paramsSchema.parse(body)
+ switch (params.type) {
+ case "tag":
+ params.tags.forEach(tag => {
+ // eslint-disable-next-line no-console
+ console.log("Revalidating tag:", tag)
+ revalidateTag(tag)
+ })
+ break
+ case "path":
+ params.paths.forEach(path => {
+ const pathToRevalidate = resolveRevalidationPath({ path, params })
+ if (pathToRevalidate) {
+ // eslint-disable-next-line no-console
+ console.log("Revalidating path:", pathToRevalidate)
+ revalidatePath(pathToRevalidate)
+ }
+ })
+ break
+ }
+
+ return NextResponse.json({ params })
+ } catch (e) {
+ console.error(body)
+ // TODO: Error logging
+ console.error(e)
+ return NextResponse.json({ error: "Wrong input" }, { status: 422 })
+ }
+}
+
+export const dynamic = "force-dynamic"
diff --git a/app/work/[id]/read/page.tsx b/app/work/[id]/read/page.tsx
deleted file mode 100644
index 2f261079..00000000
--- a/app/work/[id]/read/page.tsx
+++ /dev/null
@@ -1,20 +0,0 @@
-"use client"
-
-import React from "react"
-
-import Reader from "@/components/shared/publizonReader/PublizonReader"
-
-function Page({ searchParams: { id } }: { searchParams: { id: string } }) {
- const handleBack = () => {
- window.history.back()
- }
-
- return (
-
-
-
handleBack()} type="demo" identifier={id} />
-
- )
-}
-
-export default Page
diff --git a/codegen.ts b/codegen.ts
index a4bb69ba..81ebb4c8 100644
--- a/codegen.ts
+++ b/codegen.ts
@@ -5,7 +5,7 @@ import goConfig from "./lib/config/goConfig"
const { loadEnvConfig } = require("@next/env")
loadEnvConfig(process.cwd())
-
+process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"
const config: CodegenConfig = {
overwrite: true,
generates: {
@@ -15,7 +15,7 @@ const config: CodegenConfig = {
schema: {
[`${process.env.NEXT_PUBLIC_GRAPHQL_SCHEMA_ENDPOINT_DPL_CMS}`]: {
headers: {
- Authorization: `Basic ${process.env.GRAPHQL_SCHEMA_ENDPOINT_BASIC_TOKEN_DPL_CMS}`,
+ Authorization: `Basic Z3JhcGhxbF9jb25zdW1lcjp0ZXN0`,
},
},
},
diff --git a/lib/config/dpl-cms/dplCmsConfig.ts b/lib/config/dpl-cms/dplCmsConfig.ts
index 699ae769..5d6843c0 100644
--- a/lib/config/dpl-cms/dplCmsConfig.ts
+++ b/lib/config/dpl-cms/dplCmsConfig.ts
@@ -1,32 +1,35 @@
-import { QueryClient } from "@tanstack/react-query"
-
-import {
- GetDplCmsConfigurationQuery,
- useGetDplCmsConfigurationQuery,
-} from "@/lib/graphql/generated/dpl-cms/graphql"
-
-const queryDplCmsConfig = async (queryClient: QueryClient) => {
- const { dplConfiguration } = await queryClient.fetchQuery({
- queryKey: useGetDplCmsConfigurationQuery.getKey(),
- queryFn: useGetDplCmsConfigurationQuery.fetcher(),
- // Cache 5 minutes unless invalidated
- staleTime: 5 * 60 * 1000, // 5 mins
- })
-
- return dplConfiguration ?? null
-}
+// import {
+// GetDplCmsConfigurationQuery,
+// useGetDplCmsConfigurationQuery,
+// } from "@/lib/graphql/generated/dpl-cms/graphql"
+
+// eslint-disable-next-line
+// const queryDplCmsConfig = async (queryClient: QueryClient) => {
+// const { dplConfiguration } = await queryClient.fetchQuery({
+// queryKey: useGetDplCmsConfigurationQuery.getKey(),
+// queryFn: useGetDplCmsConfigurationQuery.fetcher(),
+// // Cache 5 minutes unless invalidated
+// staleTime: 5 * 60 * 1000, // 5 mins
+// })
+
+// return dplConfiguration ?? null
+// }
+
+// eslint-disable-next-line
+// const queryDplCmsConfig = async (queryClient: QueryClient) => {
+// return null
+// }
// eslint-disable-next-line prefer-const
-let dplCmsConfigClient = new QueryClient({})
+// let dplCmsConfigClient = new QueryClient({})
const getDplCmsConfig = async () => {
- const result = await queryDplCmsConfig(dplCmsConfigClient)
-
- return result
+ return {}
}
export const getDplCmsUniloginConfig = async () => {
const config = await getDplCmsConfig()
+ // @ts-ignore
return config?.unilogin ?? null
}
diff --git a/lib/config/resolvers/cache.ts b/lib/config/resolvers/cache.ts
new file mode 100644
index 00000000..dfdb37a6
--- /dev/null
+++ b/lib/config/resolvers/cache.ts
@@ -0,0 +1,9 @@
+const cache = {
+ "cache.revalidate.secret": () => {
+ if (process.env.REVALIDATE_CACHE_SECRET) {
+ return process.env.REVALIDATE_CACHE_SECRET
+ }
+ },
+}
+
+export default cache
diff --git a/lib/config/resolvers/index.ts b/lib/config/resolvers/index.ts
index 3c498f96..d2efba70 100644
--- a/lib/config/resolvers/index.ts
+++ b/lib/config/resolvers/index.ts
@@ -1,4 +1,5 @@
import app from "./app"
+import cache from "./cache"
import search from "./search"
import serviceFbi from "./service.fbi"
import serviceUnilogin from "./service.unilogin"
@@ -10,6 +11,7 @@ export const resolvers = {
...serviceUnilogin,
...search,
...token,
+ ...cache,
}
export type TResolvers = typeof resolvers
diff --git a/lib/graphql/fetchers/dpl-cms.fetcher.ts b/lib/graphql/fetchers/dpl-cms.fetcher.ts
index cfc4df4f..3812e822 100644
--- a/lib/graphql/fetchers/dpl-cms.fetcher.ts
+++ b/lib/graphql/fetchers/dpl-cms.fetcher.ts
@@ -5,12 +5,12 @@ export function fetcher(
) {
const dplCmsGraphqlEndpoint = process.env.NEXT_PUBLIC_GRAPHQL_SCHEMA_ENDPOINT_DPL_CMS
const dplCmsGraphqlBasicToken = process.env.NEXT_PUBLIC_GRAPHQL_BASIC_TOKEN_DPL_CMS
-
+ // console.log({ dplCmsGraphqlEndpoint })
if (!dplCmsGraphqlEndpoint || !dplCmsGraphqlBasicToken) {
throw new Error("Missing DPL CMS GraphQL endpoint or basic token")
}
-
return async (): Promise => {
+ // console.log("debug req", JSON.stringify({ query, variables }))
const res = await fetch(dplCmsGraphqlEndpoint, {
method: "POST",
...{
@@ -22,15 +22,11 @@ export function fetcher(
},
body: JSON.stringify({ query, variables }),
})
-
const json = await res.json()
-
if (json.errors) {
const { message } = json.errors[0]
-
throw new Error(message)
}
-
return json.data
}
}
diff --git a/lib/graphql/generated/dpl-cms/graphql.tsx b/lib/graphql/generated/dpl-cms/graphql.tsx
index 55fdbd3b..f337f935 100644
--- a/lib/graphql/generated/dpl-cms/graphql.tsx
+++ b/lib/graphql/generated/dpl-cms/graphql.tsx
@@ -549,6 +549,10 @@ export type Query = {
info: SchemaInformation;
/** Load a NodeArticle entity by id */
nodeArticle?: Maybe;
+ /** Load a Route by path. */
+ route?: Maybe;
+ /** NextJs SSG Node Information. */
+ ssgNodeInformation: SsgNodeInformation;
};
@@ -559,6 +563,68 @@ export type QueryNodeArticleArgs = {
revision?: InputMaybe;
};
+
+/** The schema's entry-point for queries. */
+export type QueryRouteArgs = {
+ langcode?: InputMaybe;
+ path: Scalars['String']['input'];
+};
+
+
+/** The schema's entry-point for queries. */
+export type QuerySsgNodeInformationArgs = {
+ type: Scalars['String']['input'];
+};
+
+/** Routes represent incoming requests that resolve to content. */
+export type Route = {
+ /** Whether this route is internal or external. */
+ internal: Scalars['Boolean']['output'];
+ /** URL of this route. */
+ url: Scalars['String']['output'];
+};
+
+/** A list of possible entities that can be returned by URL. */
+export type RouteEntityUnion = NodeArticle;
+
+/** Route outside of this website. */
+export type RouteExternal = Route & {
+ __typename?: 'RouteExternal';
+ /** Whether this route is internal or external. */
+ internal: Scalars['Boolean']['output'];
+ /** URL of this route. */
+ url: Scalars['String']['output'];
+};
+
+/** Route within this website. */
+export type RouteInternal = Route & {
+ __typename?: 'RouteInternal';
+ /** Breadcrumb links for this route. */
+ breadcrumbs?: Maybe>;
+ /** Content assigned to this route. */
+ entity?: Maybe;
+ /** Whether this route is internal or external. */
+ internal: Scalars['Boolean']['output'];
+ /** URL of this route. */
+ url: Scalars['String']['output'];
+};
+
+/** Redirect to another URL with status. */
+export type RouteRedirect = Route & {
+ __typename?: 'RouteRedirect';
+ /** Whether this route is internal or external. */
+ internal: Scalars['Boolean']['output'];
+ /** Utility prop. Always true for redirects. */
+ redirect: Scalars['Boolean']['output'];
+ /** Suggested status for redirect. Eg 301. */
+ status: Scalars['Int']['output'];
+ /** URL of this route. */
+ url: Scalars['String']['output'];
+};
+
+/** Route types that can exist in the system. */
+export type RouteUnion = RouteExternal | RouteInternal | RouteRedirect;
+
/** Schema information provided by the system. */
export type SchemaInformation = {
__typename?: 'SchemaInformation';
@@ -580,6 +646,15 @@ export enum SortDirection {
Desc = 'DESC'
}
+/** Schema information provided by the system. */
+export type SsgNodeInformation = {
+ __typename?: 'SsgNodeInformation';
+ /** The connected cache tags. */
+ cacheTags?: Maybe;
+ /** The node UUID. */
+ nid?: Maybe;
+};
+
/** The schema's entry-point for subscriptions. */
export type Subscription = {
__typename?: 'Subscription';
@@ -798,6 +873,13 @@ export type GetArticleQueryVariables = Exact<{
export type GetArticleQuery = { __typename?: 'Query', nodeArticle?: { __typename?: 'NodeArticle', title: string, subtitle?: string | null, paragraphs?: Array<{ __typename: 'ParagraphAccordion' } | { __typename: 'ParagraphBanner' } | { __typename: 'ParagraphBreadcrumbChildren' } | { __typename: 'ParagraphCardGridAutomatic' } | { __typename: 'ParagraphCardGridManual' } | { __typename: 'ParagraphContentSlider' } | { __typename: 'ParagraphContentSliderAutomatic' } | { __typename: 'ParagraphFilteredEventList' } | { __typename: 'ParagraphManualEventList' } | { __typename: 'ParagraphTextBody', body?: { __typename?: 'Text', value?: string | null } | null }> | null } | null };
+export type GetArticleByRouteQueryVariables = Exact<{
+ path: Scalars['String']['input'];
+}>;
+
+
+export type GetArticleByRouteQuery = { __typename?: 'Query', route?: { __typename?: 'RouteExternal' } | { __typename?: 'RouteInternal', entity?: { __typename?: 'NodeArticle', title: string, subtitle?: string | null, paragraphs?: Array<{ __typename: 'ParagraphAccordion' } | { __typename: 'ParagraphBanner' } | { __typename: 'ParagraphBreadcrumbChildren' } | { __typename: 'ParagraphCardGridAutomatic' } | { __typename: 'ParagraphCardGridManual' } | { __typename: 'ParagraphContentSlider' } | { __typename: 'ParagraphContentSliderAutomatic' } | { __typename: 'ParagraphFilteredEventList' } | { __typename: 'ParagraphManualEventList' } | { __typename: 'ParagraphTextBody', body?: { __typename?: 'Text', value?: string | null } | null }> | null } | null } | { __typename?: 'RouteRedirect' } | null };
+
export type GetDplCmsConfigurationQueryVariables = Exact<{ [key: string]: never; }>;
@@ -861,6 +943,68 @@ useSuspenseGetArticleQuery.getKey = (variables: GetArticleQueryVariables) => ['g
useGetArticleQuery.fetcher = (variables: GetArticleQueryVariables, options?: RequestInit['headers']) => fetcher(GetArticleDocument, variables, options);
+export const GetArticleByRouteDocument = `
+ query getArticleByRoute($path: String!) {
+ route(path: $path) {
+ ... on RouteInternal {
+ entity {
+ ... on NodeArticle {
+ title
+ subtitle
+ paragraphs {
+ __typename
+ ... on ParagraphTextBody {
+ body {
+ value
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+ `;
+
+export const useGetArticleByRouteQuery = <
+ TData = GetArticleByRouteQuery,
+ TError = unknown
+ >(
+ variables: GetArticleByRouteQueryVariables,
+ options?: Omit, 'queryKey'> & { queryKey?: UseQueryOptions['queryKey'] }
+ ) => {
+
+ return useQuery(
+ {
+ queryKey: ['getArticleByRoute', variables],
+ queryFn: fetcher(GetArticleByRouteDocument, variables),
+ ...options
+ }
+ )};
+
+useGetArticleByRouteQuery.getKey = (variables: GetArticleByRouteQueryVariables) => ['getArticleByRoute', variables];
+
+export const useSuspenseGetArticleByRouteQuery = <
+ TData = GetArticleByRouteQuery,
+ TError = unknown
+ >(
+ variables: GetArticleByRouteQueryVariables,
+ options?: Omit, 'queryKey'> & { queryKey?: UseSuspenseQueryOptions['queryKey'] }
+ ) => {
+
+ return useSuspenseQuery(
+ {
+ queryKey: ['getArticleByRouteSuspense', variables],
+ queryFn: fetcher(GetArticleByRouteDocument, variables),
+ ...options
+ }
+ )};
+
+useSuspenseGetArticleByRouteQuery.getKey = (variables: GetArticleByRouteQueryVariables) => ['getArticleByRouteSuspense', variables];
+
+
+useGetArticleByRouteQuery.fetcher = (variables: GetArticleByRouteQueryVariables, options?: RequestInit['headers']) => fetcher(GetArticleByRouteDocument, variables, options);
+
export const GetDplCmsConfigurationDocument = `
query getDplCmsConfiguration {
dplConfiguration {
diff --git a/lib/graphql/generated/fbi/graphql.tsx b/lib/graphql/generated/fbi/graphql.tsx
index 9841e287..caa41982 100644
--- a/lib/graphql/generated/fbi/graphql.tsx
+++ b/lib/graphql/generated/fbi/graphql.tsx
@@ -229,6 +229,12 @@ export type ComplexSearchSuggestion = {
__typename?: 'ComplexSearchSuggestion';
/** The suggested term which can be searched for */
term: Scalars['String']['output'];
+ /**
+ * A unique identifier for tracking user interactions with this suggestion.
+ * It is generated in the response and should be included in subsequent
+ * API calls when this suggestion is selected.
+ */
+ traceId: Scalars['String']['output'];
/** The type of suggestion */
type: Scalars['String']['output'];
/** A work related to the term */
@@ -780,8 +786,12 @@ export type Manifestation = {
languages?: Maybe;
/** Details about the latest printing of this manifestation */
latestPrinting?: Maybe;
+ /** Identification of the local id of this manifestation */
+ localId?: Maybe;
/** Tracks on music album, sheet music content, or articles/short stories etc. in this manifestation */
manifestationParts?: Maybe;
+ /** Field for presenting bibliographic records in MARC format */
+ marc?: Maybe;
/** The type of material of the manifestation based on bibliotek.dk types */
materialTypes: Array;
/** Notes about the manifestation */
@@ -804,6 +814,8 @@ export type Manifestation = {
review?: Maybe;
/** Series for this manifestation */
series: Array;
+ /** Material that can be identified as sheet music */
+ sheetMusicCategories?: Maybe;
/** Information about on which shelf in the library this manifestation can be found */
shelfmark?: Maybe;
/** The source of the manifestation, e.g. own library catalogue (Bibliotekskatalog) or online source e.g. Filmstriben, Ebook Central, eReolen Global etc. */
@@ -814,6 +826,12 @@ export type Manifestation = {
tableOfContents?: Maybe;
/** Different kinds of titles for this work */
titles: ManifestationTitles;
+ /**
+ * A unique identifier for tracking user interactions with this manifestation.
+ * It is generated in the response and should be included in subsequent
+ * API calls when this manifestation is selected.
+ */
+ traceId: Scalars['String']['output'];
/** id of the manifestaion unit */
unit?: Maybe;
/** Universes for this manifestation */
@@ -902,6 +920,33 @@ export type Manifestations = {
mostRelevant: Array;
};
+export type Marc = {
+ __typename?: 'Marc';
+ /** Gets the MARC record collection for the given record identifier, containing either standalone or head and/or section and volume records. */
+ getMarcByRecordId?: Maybe;
+};
+
+
+export type MarcGetMarcByRecordIdArgs = {
+ recordId: Scalars['String']['input'];
+};
+
+export type MarcRecord = {
+ __typename?: 'MarcRecord';
+ /** The library agency */
+ agencyId: Scalars['String']['output'];
+ /** The bibliographic record identifier */
+ bibliographicRecordId: Scalars['String']['output'];
+ /** The MARC record collection content as marcXchange XML string */
+ content: Scalars['String']['output'];
+ /** The serialization format of the MARC record content. Defaults to 'marcXchange' */
+ contentSerializationFormat: Scalars['String']['output'];
+ /** Flag indicating whether or not the record is deleted */
+ deleted: Scalars['Boolean']['output'];
+ /** The marc record identifier */
+ id: Scalars['String']['output'];
+};
+
export type MaterialType = {
__typename?: 'MaterialType';
/** jed 1.1 - the general materialtype */
@@ -1077,6 +1122,14 @@ export type MoodTagRecommendResponse = {
work: Work;
};
+export type MusicalExercise = {
+ __typename?: 'MusicalExercise';
+ /** The types of instrument 'schools' intended to practise with */
+ display: Array;
+ /** Information whether material is intended for practising and in combination with an instrument */
+ forExercise: Scalars['Boolean']['output'];
+};
+
export type Mutation = {
__typename?: 'Mutation';
elba: ElbaServices;
@@ -1106,6 +1159,7 @@ export enum NoteTypeEnum {
Dissertation = 'DISSERTATION',
Edition = 'EDITION',
EstimatedPlayingTimeForGames = 'ESTIMATED_PLAYING_TIME_FOR_GAMES',
+ ExpectedPublicationDate = 'EXPECTED_PUBLICATION_DATE',
Frequency = 'FREQUENCY',
MusicalEnsembleOrCast = 'MUSICAL_ENSEMBLE_OR_CAST',
NotSpecified = 'NOT_SPECIFIED',
@@ -1214,6 +1268,8 @@ export type Query = {
localSuggest: LocalSuggestResponse;
manifestation?: Maybe;
manifestations: Array>;
+ /** Field for presenting bibliographic records in MARC format */
+ marc: Marc;
mood: MoodQueries;
ors: OrsQuery;
/** Get recommendations */
@@ -1615,6 +1671,20 @@ export type Setting = SubjectInterface & {
type: SubjectTypeEnum | '%future added value';
};
+export type SheetMusicCategory = {
+ __typename?: 'SheetMusicCategory';
+ /** The types of chamber music material covers */
+ chamberMusicTypes: Array;
+ /** The types of choir material covers */
+ choirTypes: Array;
+ /** The types of instruments material covers */
+ instruments: Array;
+ /** Material intended to practice with */
+ musicalExercises?: Maybe;
+ /** The types of orchestra material covers */
+ orchestraTypes: Array;
+};
+
export type Shelfmark = {
__typename?: 'Shelfmark';
/** A postfix to the shelfmark, eg. 99.4 Christensen, Inger. f. 1935 */
@@ -1714,6 +1784,12 @@ export type Suggestion = {
__typename?: 'Suggestion';
/** The suggested term which can be searched for */
term: Scalars['String']['output'];
+ /**
+ * A unique identifier for tracking user interactions with this suggestion.
+ * It is generated in the response and should be included in subsequent
+ * API calls when this suggestion is selected.
+ */
+ traceId: Scalars['String']['output'];
/** The type of suggestion: creator, subject or title */
type: SuggestionTypeEnum | '%future added value';
/** A work related to the term */
@@ -1866,6 +1942,8 @@ export type Work = {
mainLanguages: Array;
/** Details about the manifestations of this work */
manifestations: Manifestations;
+ /** Field for presenting bibliographic records in MARC format */
+ marc?: Maybe;
/** The type of material of the manifestation based on bibliotek.dk types */
materialTypes: Array;
/** Relations to other manifestations */
@@ -1875,6 +1953,12 @@ export type Work = {
/** Subjects for this work */
subjects: SubjectContainer;
titles: WorkTitles;
+ /**
+ * A unique identifier for tracking user interactions with this work.
+ * It is generated in the response and should be included in subsequent
+ * API calls when this work is selected.
+ */
+ traceId: Scalars['String']['output'];
/** Literary/movie universes this work is part of, e.g. Wizarding World, Marvel Universe */
universes: Array;
/** Unique identification of the work based on work-presentation id e.g work-of:870970-basis:54029519 */
diff --git a/next.config.mjs b/next.config.mjs
index f4019068..d2ae052d 100644
--- a/next.config.mjs
+++ b/next.config.mjs
@@ -1,7 +1,16 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
+ logging: {
+ fetches: {
+ fullUrl: true,
+ },
+ },
+
experimental: {
serverSourceMaps: true,
+ // We cannot use "use cache" directive with react query in canary.
+ // When it is working properly, we can add this back.
+ // dynamicIO: true,
},
images: {
remotePatterns: [
diff --git a/package.json b/package.json
index 703f7d04..41c90f89 100644
--- a/package.json
+++ b/package.json
@@ -5,19 +5,19 @@
"type": "module",
"scripts": {
"build-storybook": "storybook build",
- "build": "next build",
+ "build": "NODE_EXTRA_CA_CERTS=\"$(mkcert -CAROOT)/rootCA.pem\" next build",
"ci-check": "yarn typecheck && yarn lint && yarn format:check && yarn test:unit:once",
"codegen:all-rest-services": "orval",
"codegen:covers": "rm -rf src/lib/rest/cover-service-api/generated/model/*.* && orval --project coverService",
- "codegen:graphql": "graphql-codegen --require tsconfig-paths/register --config codegen.ts",
+ "codegen:graphql": "NODE_TLS_REJECT_UNAUTHORIZED=0 graphql-codegen --require tsconfig-paths/register --config codegen.ts",
"codegen:publizon": "rm -rf lib/rest/publizon-api/generated/model/*.* && orval --project publizonAdapter",
"dev:https": "next dev --experimental-https",
- "dev": "next dev",
+ "dev": "NODE_EXTRA_CA_CERTS=\"$(mkcert -CAROOT)/rootCA.pem\" next dev",
"format:check": "prettier --check .",
"format:write": "prettier --write .",
"lint": "next lint",
"start:with-server-source-maps": "NODE_OPTIONS='--enable-source-maps=true' next start",
- "start": "next start",
+ "start": "NODE_EXTRA_CA_CERTS=\"$(mkcert -CAROOT)/rootCA.pem\" next start",
"storybook": "storybook dev -p 6006",
"test:accessibility": "test-storybook",
"test:unit:once": "vitest run",
@@ -43,7 +43,7 @@
"iron-session": "^8.0.3",
"lodash": "^4.17.21",
"lucide-react": "^0.446.0",
- "next": "15.0.3",
+ "next": "^15.1.0",
"next-drupal": "^2.0.0-beta.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
diff --git a/yarn.lock b/yarn.lock
index 04bbeea3..8ee28f74 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2870,6 +2870,11 @@
resolved "https://registry.yarnpkg.com/@next/env/-/env-15.0.3.tgz#a2e9bf274743c52b74d30f415f3eba750d51313a"
integrity sha512-t9Xy32pjNOvVn2AS+Utt6VmyrshbpfUMhIjFO60gI58deSo/KgLOp31XZ4O+kY/Is8WAGYwA5gR7kOb1eORDBA==
+"@next/env@15.1.0":
+ version "15.1.0"
+ resolved "https://registry.yarnpkg.com/@next/env/-/env-15.1.0.tgz#35b00a5f60ff10dc275182928c325d25c29379ae"
+ integrity sha512-UcCO481cROsqJuszPPXJnb7GGuLq617ve4xuAyyNG4VSSocJNtMU5Fsx+Lp6mlN8c7W58aZLc5y6D/2xNmaK+w==
+
"@next/eslint-plugin-next@15.0.3":
version "15.0.3"
resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-15.0.3.tgz#ce953098036d462f6901e423cc6445fc165b78c4"
@@ -2882,70 +2887,70 @@
resolved "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.15.tgz"
integrity sha512-Rvh7KU9hOUBnZ9TJ28n2Oa7dD9cvDBKua9IKx7cfQQ0GoYUwg9ig31O2oMwH3wm+pE3IkAQ67ZobPfEgurPZIA==
-"@next/swc-darwin-arm64@15.0.3":
- version "15.0.3"
- resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.0.3.tgz#4c40c506cf3d4d87da0204f4cccf39e6bdc46a71"
- integrity sha512-s3Q/NOorCsLYdCKvQlWU+a+GeAd3C8Rb3L1YnetsgwXzhc3UTWrtQpB/3eCjFOdGUj5QmXfRak12uocd1ZiiQw==
+"@next/swc-darwin-arm64@15.1.0":
+ version "15.1.0"
+ resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.1.0.tgz#30cb89220e719244c9fa7391641e515a078ade46"
+ integrity sha512-ZU8d7xxpX14uIaFC3nsr4L++5ZS/AkWDm1PzPO6gD9xWhFkOj2hzSbSIxoncsnlJXB1CbLOfGVN4Zk9tg83PUw==
"@next/swc-darwin-x64@14.2.15":
version "14.2.15"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.15.tgz#b7baeedc6a28f7545ad2bc55adbab25f7b45cb89"
integrity sha512-5TGyjFcf8ampZP3e+FyCax5zFVHi+Oe7sZyaKOngsqyaNEpOgkKB3sqmymkZfowy3ufGA/tUgDPPxpQx931lHg==
-"@next/swc-darwin-x64@15.0.3":
- version "15.0.3"
- resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.0.3.tgz#8e06cacae3dae279744f9fbe88dea679ec2c1ca3"
- integrity sha512-Zxl/TwyXVZPCFSf0u2BNj5sE0F2uR6iSKxWpq4Wlk/Sv9Ob6YCKByQTkV2y6BCic+fkabp9190hyrDdPA/dNrw==
+"@next/swc-darwin-x64@15.1.0":
+ version "15.1.0"
+ resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.1.0.tgz#c24c4f5d1016dd161da32049305b0ddddfc80951"
+ integrity sha512-DQ3RiUoW2XC9FcSM4ffpfndq1EsLV0fj0/UY33i7eklW5akPUCo6OX2qkcLXZ3jyPdo4sf2flwAED3AAq3Om2Q==
"@next/swc-linux-arm64-gnu@14.2.15":
version "14.2.15"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.15.tgz#fa13c59d3222f70fb4cb3544ac750db2c6e34d02"
integrity sha512-3Bwv4oc08ONiQ3FiOLKT72Q+ndEMyLNsc/D3qnLMbtUYTQAmkx9E/JRu0DBpHxNddBmNT5hxz1mYBphJ3mfrrw==
-"@next/swc-linux-arm64-gnu@15.0.3":
- version "15.0.3"
- resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.0.3.tgz#c144ad1f21091b9c6e1e330ecc2d56188763191d"
- integrity sha512-T5+gg2EwpsY3OoaLxUIofmMb7ohAUlcNZW0fPQ6YAutaWJaxt1Z1h+8zdl4FRIOr5ABAAhXtBcpkZNwUcKI2fw==
+"@next/swc-linux-arm64-gnu@15.1.0":
+ version "15.1.0"
+ resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.1.0.tgz#08ed540ecdac74426a624cc7d736dc709244b004"
+ integrity sha512-M+vhTovRS2F//LMx9KtxbkWk627l5Q7AqXWWWrfIzNIaUFiz2/NkOFkxCFyNyGACi5YbA8aekzCLtbDyfF/v5Q==
"@next/swc-linux-arm64-musl@14.2.15":
version "14.2.15"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.15.tgz#30e45b71831d9a6d6d18d7ac7d611a8d646a17f9"
integrity sha512-k5xf/tg1FBv/M4CMd8S+JL3uV9BnnRmoe7F+GWC3DxkTCD9aewFRH1s5rJ1zkzDa+Do4zyN8qD0N8c84Hu96FQ==
-"@next/swc-linux-arm64-musl@15.0.3":
- version "15.0.3"
- resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.0.3.tgz#3ccb71c6703bf421332f177d1bb0e10528bc73a2"
- integrity sha512-WkAk6R60mwDjH4lG/JBpb2xHl2/0Vj0ZRu1TIzWuOYfQ9tt9NFsIinI1Epma77JVgy81F32X/AeD+B2cBu/YQA==
+"@next/swc-linux-arm64-musl@15.1.0":
+ version "15.1.0"
+ resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.1.0.tgz#dfddbd40087d018266aa92515ec5b3e251efa6dd"
+ integrity sha512-Qn6vOuwaTCx3pNwygpSGtdIu0TfS1KiaYLYXLH5zq1scoTXdwYfdZtwvJTpB1WrLgiQE2Ne2kt8MZok3HlFqmg==
"@next/swc-linux-x64-gnu@14.2.15":
version "14.2.15"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.15.tgz#5065db17fc86f935ad117483f21f812dc1b39254"
integrity sha512-kE6q38hbrRbKEkkVn62reLXhThLRh6/TvgSP56GkFNhU22TbIrQDEMrO7j0IcQHcew2wfykq8lZyHFabz0oBrA==
-"@next/swc-linux-x64-gnu@15.0.3":
- version "15.0.3"
- resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.0.3.tgz#b90aa9b07001b4000427c35ab347a9273cbeebb3"
- integrity sha512-gWL/Cta1aPVqIGgDb6nxkqy06DkwJ9gAnKORdHWX1QBbSZZB+biFYPFti8aKIQL7otCE1pjyPaXpFzGeG2OS2w==
+"@next/swc-linux-x64-gnu@15.1.0":
+ version "15.1.0"
+ resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.1.0.tgz#a7b5373a1b28c0acecbc826a3790139fc0d899e5"
+ integrity sha512-yeNh9ofMqzOZ5yTOk+2rwncBzucc6a1lyqtg8xZv0rH5znyjxHOWsoUtSq4cUTeeBIiXXX51QOOe+VoCjdXJRw==
"@next/swc-linux-x64-musl@14.2.15":
version "14.2.15"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.15.tgz#3c4a4568d8be7373a820f7576cf33388b5dab47e"
integrity sha512-PZ5YE9ouy/IdO7QVJeIcyLn/Rc4ml9M2G4y3kCM9MNf1YKvFY4heg3pVa/jQbMro+tP6yc4G2o9LjAz1zxD7tQ==
-"@next/swc-linux-x64-musl@15.0.3":
- version "15.0.3"
- resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.0.3.tgz#0ac9724fb44718fc97bfea971ac3fe17e486590e"
- integrity sha512-QQEMwFd8r7C0GxQS62Zcdy6GKx999I/rTO2ubdXEe+MlZk9ZiinsrjwoiBL5/57tfyjikgh6GOU2WRQVUej3UA==
+"@next/swc-linux-x64-musl@15.1.0":
+ version "15.1.0"
+ resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.1.0.tgz#b82a29903ee2f12d8b64163ddf208ac519869550"
+ integrity sha512-t9IfNkHQs/uKgPoyEtU912MG6a1j7Had37cSUyLTKx9MnUpjj+ZDKw9OyqTI9OwIIv0wmkr1pkZy+3T5pxhJPg==
"@next/swc-win32-arm64-msvc@14.2.15":
version "14.2.15"
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.15.tgz#fb812cc4ca0042868e32a6a021da91943bb08b98"
integrity sha512-2raR16703kBvYEQD9HNLyb0/394yfqzmIeyp2nDzcPV4yPjqNUG3ohX6jX00WryXz6s1FXpVhsCo3i+g4RUX+g==
-"@next/swc-win32-arm64-msvc@15.0.3":
- version "15.0.3"
- resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.0.3.tgz#932437d4cf27814e963ba8ae5f033b4421fab9ca"
- integrity sha512-9TEp47AAd/ms9fPNgtgnT7F3M1Hf7koIYYWCMQ9neOwjbVWJsHZxrFbI3iEDJ8rf1TDGpmHbKxXf2IFpAvheIQ==
+"@next/swc-win32-arm64-msvc@15.1.0":
+ version "15.1.0"
+ resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.1.0.tgz#98deae6cb1fccfb6a600e9faa6aa714402a9ab9a"
+ integrity sha512-WEAoHyG14t5sTavZa1c6BnOIEukll9iqFRTavqRVPfYmfegOAd5MaZfXgOGG6kGo1RduyGdTHD4+YZQSdsNZXg==
"@next/swc-win32-ia32-msvc@14.2.15":
version "14.2.15"
@@ -2957,10 +2962,10 @@
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.15.tgz#18d68697002b282006771f8d92d79ade9efd35c4"
integrity sha512-SzqGbsLsP9OwKNUG9nekShTwhj6JSB9ZLMWQ8g1gG6hdE5gQLncbnbymrwy2yVmH9nikSLYRYxYMFu78Ggp7/g==
-"@next/swc-win32-x64-msvc@15.0.3":
- version "15.0.3"
- resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.0.3.tgz#940a6f7b370cdde0cc67eabe945d9e6d97e0be9f"
- integrity sha512-VNAz+HN4OGgvZs6MOoVfnn41kBzT+M+tB+OK4cww6DNyWS6wKaDpaAm/qLeOUbnMh0oVx1+mg0uoYARF69dJyA==
+"@next/swc-win32-x64-msvc@15.1.0":
+ version "15.1.0"
+ resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.1.0.tgz#4b04a6a667c41fecdc63db57dd71ca7e84d0946b"
+ integrity sha512-J1YdKuJv9xcixzXR24Dv+4SaDKc2jj31IVUEMdO5xJivMTXuE6MAdIi4qPjSymHuFG8O5wbfWKnhJUcHHpj5CA==
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
@@ -4334,12 +4339,12 @@
resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9"
integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==
-"@swc/helpers@0.5.13":
- version "0.5.13"
- resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.13.tgz#33e63ff3cd0cade557672bd7888a39ce7d115a8c"
- integrity sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==
+"@swc/helpers@0.5.15":
+ version "0.5.15"
+ resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.15.tgz#79efab344c5819ecf83a43f3f9f811fc84b516d7"
+ integrity sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==
dependencies:
- tslib "^2.4.0"
+ tslib "^2.8.0"
"@swc/helpers@0.5.5":
version "0.5.5"
@@ -4365,10 +4370,10 @@
dependencies:
"@swc/counter" "^0.1.3"
-"@tanstack/query-core@5.59.13":
- version "5.59.13"
- resolved "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.59.13.tgz"
- integrity sha512-Oou0bBu/P8+oYjXsJQ11j+gcpLAMpqW42UlokQYEz4dE7+hOtVO9rVuolJKgEccqzvyFzqX4/zZWY+R/v1wVsQ==
+"@tanstack/query-core@5.62.3":
+ version "5.62.3"
+ resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.62.3.tgz#7cfde68f7d78807faebee2a2bb1e31b81067f46b"
+ integrity sha512-Jp/nYoz8cnO7kqhOlSv8ke/0MJRJVGuZ0P/JO9KQ+f45mpN90hrerzavyTKeSoT/pOzeoOUkv1Xd0wPsxAWXfg==
"@tanstack/query-devtools@5.58.0":
version "5.58.0"
@@ -4383,11 +4388,11 @@
"@tanstack/query-devtools" "5.58.0"
"@tanstack/react-query@^5.59.0":
- version "5.59.14"
- resolved "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.59.14.tgz"
- integrity sha512-2cM4x3Ka4Thl7/wnjf++EMGA2Is/RgPynn83D4kfGiJOGSjb5T2D3EEOlC8Nt6U2htLS3imOXjOSMEjC3K7JNg==
+ version "5.62.3"
+ resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.62.3.tgz#c6766b1764dcf924f6ed5fd88daf8d246e2f5c14"
+ integrity sha512-y2zDNKuhgiuMgsKkqd4AcsLIBiCfEO8U11AdrtAUihmLbRNztPrlcZqx2lH1GacZsx+y1qRRbCcJLYTtF1vKsw==
dependencies:
- "@tanstack/query-core" "5.59.13"
+ "@tanstack/query-core" "5.62.3"
"@testing-library/dom@10.4.0":
version "10.4.0"
@@ -10061,29 +10066,6 @@ next-test-api-route-handler@^4.0.12:
cookie "^1.0.1"
core-js "^3.38.1"
-next@15.0.3:
- version "15.0.3"
- resolved "https://registry.yarnpkg.com/next/-/next-15.0.3.tgz#804f5b772e7570ef1f088542a59860914d3288e9"
- integrity sha512-ontCbCRKJUIoivAdGB34yCaOcPgYXr9AAkV/IwqFfWWTXEPUgLYkSkqBhIk9KK7gGmgjc64B+RdoeIDM13Irnw==
- dependencies:
- "@next/env" "15.0.3"
- "@swc/counter" "0.1.3"
- "@swc/helpers" "0.5.13"
- busboy "1.6.0"
- caniuse-lite "^1.0.30001579"
- postcss "8.4.31"
- styled-jsx "5.1.6"
- optionalDependencies:
- "@next/swc-darwin-arm64" "15.0.3"
- "@next/swc-darwin-x64" "15.0.3"
- "@next/swc-linux-arm64-gnu" "15.0.3"
- "@next/swc-linux-arm64-musl" "15.0.3"
- "@next/swc-linux-x64-gnu" "15.0.3"
- "@next/swc-linux-x64-musl" "15.0.3"
- "@next/swc-win32-arm64-msvc" "15.0.3"
- "@next/swc-win32-x64-msvc" "15.0.3"
- sharp "^0.33.5"
-
"next@^13.4 || ^14":
version "14.2.15"
resolved "https://registry.npmjs.org/next/-/next-14.2.15.tgz"
@@ -10107,6 +10089,29 @@ next@15.0.3:
"@next/swc-win32-ia32-msvc" "14.2.15"
"@next/swc-win32-x64-msvc" "14.2.15"
+next@^15.1.0:
+ version "15.1.0"
+ resolved "https://registry.yarnpkg.com/next/-/next-15.1.0.tgz#be847cf67ac94ae23b57f3ea6d10642f3fc1ad69"
+ integrity sha512-QKhzt6Y8rgLNlj30izdMbxAwjHMFANnLwDwZ+WQh5sMhyt4lEBqDK9QpvWHtIM4rINKPoJ8aiRZKg5ULSybVHw==
+ dependencies:
+ "@next/env" "15.1.0"
+ "@swc/counter" "0.1.3"
+ "@swc/helpers" "0.5.15"
+ busboy "1.6.0"
+ caniuse-lite "^1.0.30001579"
+ postcss "8.4.31"
+ styled-jsx "5.1.6"
+ optionalDependencies:
+ "@next/swc-darwin-arm64" "15.1.0"
+ "@next/swc-darwin-x64" "15.1.0"
+ "@next/swc-linux-arm64-gnu" "15.1.0"
+ "@next/swc-linux-arm64-musl" "15.1.0"
+ "@next/swc-linux-x64-gnu" "15.1.0"
+ "@next/swc-linux-x64-musl" "15.1.0"
+ "@next/swc-win32-arm64-msvc" "15.1.0"
+ "@next/swc-win32-x64-msvc" "15.1.0"
+ sharp "^0.33.5"
+
nimma@0.2.2:
version "0.2.2"
resolved "https://registry.npmjs.org/nimma/-/nimma-0.2.2.tgz"
@@ -12626,7 +12631,7 @@ tslib@^1.14.1:
resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
-tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0:
+tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.8.0:
version "2.8.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==