@anthusai/papyrus 1.0.0-next.21 → 1.0.0-next.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/newsroom/[section]/[...selection]/page.tsx +6 -5
- package/app/newsroom/[section]/page.tsx +4 -3
- package/components/newsroom-access-gate.tsx +2 -1
- package/components/papyrus-console-shell.tsx +4 -2
- package/components/topic-steering-workspace.tsx +5 -4
- package/infra/build-specs.js +7 -3
- package/infra/build-specs.ts +7 -3
- package/lib/newsroom-base-path.ts +12 -3
- package/lib/newsroom-category-drilldown.ts +3 -2
- package/lib/newsroom-forum-routes.ts +6 -4
- package/lib/newsroom-index-filters.ts +14 -10
- package/lib/semantic-graph.ts +5 -0
- package/lib/staging-gated-path.ts +2 -1
- package/middleware.ts +6 -3
- package/package.json +1 -1
- package/routes.manifest.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { notFound, redirect } from "next/navigation";
|
|
2
|
+
import { toPublicNewsroomPath } from "../../../../lib/newsroom-base-path";
|
|
2
3
|
import { NewsDeskPage } from "../../../../components/news-desk-page";
|
|
3
4
|
import type { NewsDeskTab } from "../../../../components/topic-steering-workspace";
|
|
4
5
|
|
|
@@ -37,13 +38,13 @@ const NEWS_DESK_ROUTE_SECTIONS = new Set<NewsDeskTab>([
|
|
|
37
38
|
|
|
38
39
|
export default async function NewsDeskNestedSectionPage({ params, searchParams }: NewsDeskNestedSectionPageProps) {
|
|
39
40
|
const { section, selection } = await params;
|
|
40
|
-
if (section === "users") redirect("/newsroom/administration/users");
|
|
41
|
-
if (section === "doctrine") redirect("/newsroom/administration/policies");
|
|
42
|
-
if (section === "administration" && selection[0] === "analysis") redirect("/newsroom/assignments");
|
|
41
|
+
if (section === "users") redirect(toPublicNewsroomPath("/newsroom/administration/users"));
|
|
42
|
+
if (section === "doctrine") redirect(toPublicNewsroomPath("/newsroom/administration/policies"));
|
|
43
|
+
if (section === "administration" && selection[0] === "analysis") redirect(toPublicNewsroomPath("/newsroom/assignments"));
|
|
43
44
|
if (section === "desks") {
|
|
44
45
|
const category = selection[0] ? decodeURIComponent(selection[0]) : null;
|
|
45
|
-
if (category) redirect(`/newsroom/topics?category=${encodeURIComponent(category)}`);
|
|
46
|
-
redirect("/newsroom/topics");
|
|
46
|
+
if (category) redirect(toPublicNewsroomPath(`/newsroom/topics?category=${encodeURIComponent(category)}`));
|
|
47
|
+
redirect(toPublicNewsroomPath("/newsroom/topics"));
|
|
47
48
|
}
|
|
48
49
|
if (!NEWS_DESK_ROUTE_SECTIONS.has(section as NewsDeskTab)) notFound();
|
|
49
50
|
return <NewsDeskPage section={section} selectionPath={selection} searchParams={searchParams} />;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { notFound, redirect } from "next/navigation";
|
|
2
|
+
import { toPublicNewsroomPath } from "../../../lib/newsroom-base-path";
|
|
2
3
|
import { NewsDeskPage } from "../../../components/news-desk-page";
|
|
3
4
|
import type { NewsDeskTab } from "../../../components/topic-steering-workspace";
|
|
4
5
|
|
|
@@ -39,9 +40,9 @@ const NEWS_DESK_ROUTE_SECTIONS = new Set<NewsDeskTab>([
|
|
|
39
40
|
|
|
40
41
|
export default async function NewsDeskSectionPage({ params, searchParams }: NewsDeskSectionPageProps) {
|
|
41
42
|
const { section } = await params;
|
|
42
|
-
if (section === "users") redirect("/newsroom/administration/users");
|
|
43
|
-
if (section === "doctrine") redirect("/newsroom/administration/policies");
|
|
44
|
-
if (section === "desks") redirect("/newsroom/topics");
|
|
43
|
+
if (section === "users") redirect(toPublicNewsroomPath("/newsroom/administration/users"));
|
|
44
|
+
if (section === "doctrine") redirect(toPublicNewsroomPath("/newsroom/administration/policies"));
|
|
45
|
+
if (section === "desks") redirect(toPublicNewsroomPath("/newsroom/topics"));
|
|
45
46
|
if (!NEWS_DESK_ROUTE_SECTIONS.has(section as NewsDeskTab)) notFound();
|
|
46
47
|
return <NewsDeskPage section={section} searchParams={searchParams} />;
|
|
47
48
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
+
import { newsroomHref } from "../lib/newsroom-base-path";
|
|
3
4
|
import Link from "next/link";
|
|
4
5
|
import { SITE_BRAND } from "../lib/site-brand";
|
|
5
6
|
import type { NewsDeskShellState } from "../lib/news-desk-session";
|
|
@@ -32,7 +33,7 @@ export function NewsDeskAccessGate({ shell, showSectionTabs = false }: { shell:
|
|
|
32
33
|
<p className="m-0 text-sm text-foreground">{formatAccessActionDetail(shell)}</p>
|
|
33
34
|
{shell?.phase === "signedOut" || shell?.phase === "error" ? (
|
|
34
35
|
<div className="news-desk-access-panel__auth">
|
|
35
|
-
<ReaderAuthControl postAuthPath=
|
|
36
|
+
<ReaderAuthControl postAuthPath={newsroomHref()} showIdentity />
|
|
36
37
|
</div>
|
|
37
38
|
) : null}
|
|
38
39
|
</div>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
+
import { browserPathToInternalNewsroomPath } from "../lib/newsroom-base-path";
|
|
3
4
|
import type { BotAvatarState } from "anthus-vultus";
|
|
4
5
|
import dynamic from "next/dynamic";
|
|
5
6
|
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
|
@@ -152,7 +153,8 @@ export function PapyrusConsoleShell({ children }: PapyrusConsoleShellProps) {
|
|
|
152
153
|
const [session, setSession] = useState<ReaderSessionSnapshot | null>(null);
|
|
153
154
|
const [open, setOpen] = useState(false);
|
|
154
155
|
const [openingReferenceChat, setOpeningReferenceChat] = useState(false);
|
|
155
|
-
const
|
|
156
|
+
const internalPathname = browserPathToInternalNewsroomPath(pathname);
|
|
157
|
+
const isNewsroomPath = internalPathname === "/newsroom" || internalPathname.startsWith("/newsroom/");
|
|
156
158
|
const canUseConsole = Boolean(session?.hasSession && session.groups.some((group) => group === "editor" || group === "admin"));
|
|
157
159
|
const shouldOfferConsole = isNewsroomPath && canUseConsole;
|
|
158
160
|
|
|
@@ -433,7 +435,7 @@ function ConsolePanel({ actorEmail, actorLabel, onClose }: { actorEmail: string
|
|
|
433
435
|
const handledNavigationMessageIdsRef = useRef<Set<string>>(new Set());
|
|
434
436
|
|
|
435
437
|
const currentWebPath = useMemo(() => {
|
|
436
|
-
const path = pathname ?? "/newsroom";
|
|
438
|
+
const path = browserPathToInternalNewsroomPath(pathname ?? "/newsroom");
|
|
437
439
|
const query = searchParams.toString();
|
|
438
440
|
return query ? `${path}?${query}` : path;
|
|
439
441
|
}, [pathname, searchParams]);
|
|
@@ -76,6 +76,7 @@ import { buildNewsroomKnowledgeQueryInput, type NewsroomKnowledgeQueryAnchor as
|
|
|
76
76
|
import { NewsroomConsoleProgressToggle, PapyrusConsoleChatIcon, usePapyrusConsole } from "./papyrus-console-shell";
|
|
77
77
|
import { useResolvedPapyrusTheme } from "./use-resolved-papyrus-theme";
|
|
78
78
|
import { SITE_BRAND } from "../lib/site-brand";
|
|
79
|
+
import { browserPathToInternalNewsroomPath, toPublicNewsroomPath } from "../lib/newsroom-base-path";
|
|
79
80
|
import { getNewsroomNavHref } from "../lib/newsroom-nav";
|
|
80
81
|
import { cn } from "../lib/utils";
|
|
81
82
|
import { useOptionalNewsDeskClient } from "./news-desk-client-provider";
|
|
@@ -15187,14 +15188,14 @@ function normalizeKnowledgeQueryAnchorKind(value: string | null | undefined): Kn
|
|
|
15187
15188
|
|
|
15188
15189
|
function normalizeNewsroomFromHref(value: string | null | undefined): string | null {
|
|
15189
15190
|
if (!value) return null;
|
|
15190
|
-
const trimmed = value.trim();
|
|
15191
|
+
const trimmed = browserPathToInternalNewsroomPath(value.trim());
|
|
15191
15192
|
if (!trimmed.startsWith("/newsroom")) return null;
|
|
15192
|
-
return trimmed;
|
|
15193
|
+
return toPublicNewsroomPath(trimmed);
|
|
15193
15194
|
}
|
|
15194
15195
|
|
|
15195
15196
|
function currentNewsroomOriginHref(fallback: string | null): string | null {
|
|
15196
15197
|
if (typeof window === "undefined") return fallback;
|
|
15197
|
-
const current = `${window.location.pathname}${window.location.search}
|
|
15198
|
+
const current = browserPathToInternalNewsroomPath(`${window.location.pathname}${window.location.search}`);
|
|
15198
15199
|
return current.startsWith("/newsroom/search") ? fallback : normalizeNewsroomFromHref(current);
|
|
15199
15200
|
}
|
|
15200
15201
|
|
|
@@ -15228,7 +15229,7 @@ function buildNewsroomSearchHref(request: NewsroomSearchRequest, demo?: boolean)
|
|
|
15228
15229
|
if (request.from) params.set("from", request.from);
|
|
15229
15230
|
if (demo) params.set("demo", "1");
|
|
15230
15231
|
const queryString = params.toString();
|
|
15231
|
-
return queryString ? `/newsroom/search?${queryString}` : "/newsroom/search";
|
|
15232
|
+
return toPublicNewsroomPath(queryString ? `/newsroom/search?${queryString}` : "/newsroom/search");
|
|
15232
15233
|
}
|
|
15233
15234
|
|
|
15234
15235
|
function focusNewsroomSearchForm() {
|
package/infra/build-specs.js
CHANGED
|
@@ -15,7 +15,7 @@ function commandLines(commands, indent) {
|
|
|
15
15
|
const NPM_CLEAN_INSTALL = "npm ci --cache .npm --prefer-offline";
|
|
16
16
|
const FRONTEND_ENVIRONMENT_CAPTURE = "env | grep -e '^PAPYRUS_' -e '^SITE_ENV=' -e '^NEXT_PUBLIC_' >> .env.production";
|
|
17
17
|
const CHECKOUT_AS_PAPYRUS_ROOT = "PAPYRUS_ROOT=\"$PWD\"";
|
|
18
|
-
const
|
|
18
|
+
const RUNTIME_OUTPUTS_COMMANDS = [
|
|
19
19
|
"cp amplify_outputs.json .next/amplify_outputs.json",
|
|
20
20
|
"echo PAPYRUS_AMPLIFY_OUTPUTS=.next/amplify_outputs.json >> .env.production",
|
|
21
21
|
];
|
|
@@ -55,7 +55,11 @@ export function cmsProductionBuildSpec(config) {
|
|
|
55
55
|
"if [ -z \"${PAPYRUS_CONSOLE_RESPONDER_IMAGE_URI:-}\" ]; then export PAPYRUS_CONSOLE_RESPONDER_ALLOW_LOCAL_BUILD=true; fi",
|
|
56
56
|
"npx ampx pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID",
|
|
57
57
|
], " "),
|
|
58
|
-
...frontendSection([], [
|
|
58
|
+
...frontendSection([], [
|
|
59
|
+
FRONTEND_ENVIRONMENT_CAPTURE,
|
|
60
|
+
"npx papyrus-app sync && npm run build",
|
|
61
|
+
...(config.frontend === "pretext" ? RUNTIME_OUTPUTS_COMMANDS : []),
|
|
62
|
+
], ".next", [".next/cache/**/*", ".npm/**/*"]),
|
|
59
63
|
].join("\n") + "\n";
|
|
60
64
|
}
|
|
61
65
|
export function cmsStagingBuildSpec(config) {
|
|
@@ -71,7 +75,7 @@ export function cmsStagingBuildSpec(config) {
|
|
|
71
75
|
...frontendSection(preBuild, [
|
|
72
76
|
FRONTEND_ENVIRONMENT_CAPTURE,
|
|
73
77
|
"npx papyrus-app sync && npm run build",
|
|
74
|
-
...
|
|
78
|
+
...RUNTIME_OUTPUTS_COMMANDS,
|
|
75
79
|
], ".next", cachePaths),
|
|
76
80
|
].join("\n") + "\n";
|
|
77
81
|
}
|
package/infra/build-specs.ts
CHANGED
|
@@ -24,7 +24,7 @@ const FRONTEND_ENVIRONMENT_CAPTURE =
|
|
|
24
24
|
|
|
25
25
|
const CHECKOUT_AS_PAPYRUS_ROOT = "PAPYRUS_ROOT=\"$PWD\"";
|
|
26
26
|
|
|
27
|
-
const
|
|
27
|
+
const RUNTIME_OUTPUTS_COMMANDS = [
|
|
28
28
|
"cp amplify_outputs.json .next/amplify_outputs.json",
|
|
29
29
|
"echo PAPYRUS_AMPLIFY_OUTPUTS=.next/amplify_outputs.json >> .env.production",
|
|
30
30
|
];
|
|
@@ -83,7 +83,11 @@ export function cmsProductionBuildSpec(config: AmplifyAppShellSiteConfig): strin
|
|
|
83
83
|
),
|
|
84
84
|
...frontendSection(
|
|
85
85
|
[],
|
|
86
|
-
[
|
|
86
|
+
[
|
|
87
|
+
FRONTEND_ENVIRONMENT_CAPTURE,
|
|
88
|
+
"npx papyrus-app sync && npm run build",
|
|
89
|
+
...(config.frontend === "pretext" ? RUNTIME_OUTPUTS_COMMANDS : []),
|
|
90
|
+
],
|
|
87
91
|
".next",
|
|
88
92
|
[".next/cache/**/*", ".npm/**/*"],
|
|
89
93
|
),
|
|
@@ -110,7 +114,7 @@ export function cmsStagingBuildSpec(config: AmplifyAppShellSiteConfig): string {
|
|
|
110
114
|
[
|
|
111
115
|
FRONTEND_ENVIRONMENT_CAPTURE,
|
|
112
116
|
"npx papyrus-app sync && npm run build",
|
|
113
|
-
...
|
|
117
|
+
...RUNTIME_OUTPUTS_COMMANDS,
|
|
114
118
|
],
|
|
115
119
|
".next",
|
|
116
120
|
cachePaths,
|
|
@@ -19,13 +19,22 @@ export function usesNewsroomRootPaths(): boolean {
|
|
|
19
19
|
export function toPublicNewsroomPath(internalPath: string): string {
|
|
20
20
|
const publicBase = getPublicNewsroomBasePath();
|
|
21
21
|
if (publicBase !== "") return internalPath;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
const suffixStart = internalPath.search(/[?#]/);
|
|
23
|
+
const pathOnly = suffixStart === -1 ? internalPath : internalPath.slice(0, suffixStart);
|
|
24
|
+
const suffix = suffixStart === -1 ? "" : internalPath.slice(suffixStart);
|
|
25
|
+
if (pathOnly === "/newsroom" || pathOnly === "/newsroom/") return `/${suffix}`;
|
|
26
|
+
if (pathOnly.startsWith("/newsroom/")) {
|
|
27
|
+
return `${pathOnly.slice("/newsroom".length) || "/"}${suffix}`;
|
|
25
28
|
}
|
|
26
29
|
return internalPath;
|
|
27
30
|
}
|
|
28
31
|
|
|
32
|
+
/** Maps a browser pathname to the internal `/newsroom/...` form on CMS-only hosts; identity elsewhere. */
|
|
33
|
+
export function browserPathToInternalNewsroomPath(browserPath: string): string {
|
|
34
|
+
if (!usesNewsroomRootPaths()) return browserPath;
|
|
35
|
+
return toInternalNewsroomPath(browserPath);
|
|
36
|
+
}
|
|
37
|
+
|
|
29
38
|
export function toInternalNewsroomPath(publicPath: string): string {
|
|
30
39
|
const publicBase = getPublicNewsroomBasePath();
|
|
31
40
|
const normalized = publicPath.startsWith("/") ? publicPath : `/${publicPath}`;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { toPublicNewsroomPath } from "./newsroom-base-path";
|
|
1
2
|
import type {
|
|
2
3
|
CategorySteeringCategory,
|
|
3
4
|
SemanticRelationRecord,
|
|
@@ -93,11 +94,11 @@ export function uniqueNeighborGroupsForCategoryContext(graph: CategoryGraph, con
|
|
|
93
94
|
export function topicHref(rootCategoryKey: string, selectedCategoryKey?: string | null): string {
|
|
94
95
|
const encodedRoot = encodeURIComponent(rootCategoryKey);
|
|
95
96
|
const encodedSelected = selectedCategoryKey && selectedCategoryKey !== rootCategoryKey ? `/${encodeURIComponent(selectedCategoryKey)}` : "";
|
|
96
|
-
return `/newsroom/topics/${encodedRoot}${encodedSelected}
|
|
97
|
+
return toPublicNewsroomPath(`/newsroom/topics/${encodedRoot}${encodedSelected}`);
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
export function categoryDrilldownHref(section: "references" | "concepts", categoryKey: string): string {
|
|
100
|
-
return `/newsroom/${section}/${encodeURIComponent(categoryKey)}
|
|
101
|
+
return toPublicNewsroomPath(`/newsroom/${section}/${encodeURIComponent(categoryKey)}`);
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
function matchesCategorySelection(category: CategorySteeringCategory, selection: string): boolean {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { toPublicNewsroomPath } from "./newsroom-base-path";
|
|
2
|
+
|
|
1
3
|
export const FORUM_THREAD_ROUTE_PREFIX = "/newsroom/forum/";
|
|
2
4
|
export const INSIGHT_THREAD_ROUTE_PREFIX = "/newsroom/insights/";
|
|
3
5
|
export const FORUM_MESSAGE_HASH_PREFIX = "message-";
|
|
@@ -81,7 +83,7 @@ export function buildForumThreadUrl(
|
|
|
81
83
|
if (options?.demo) params.set("demo", "1");
|
|
82
84
|
const query = params.toString();
|
|
83
85
|
const hash = options?.messageId ? getForumMessageAnchorId(options.messageId) : "";
|
|
84
|
-
return `/newsroom/forum/${encodedThreadId}${query ? `?${query}` : ""}${hash ? `#${hash}` : ""}
|
|
86
|
+
return toPublicNewsroomPath(`/newsroom/forum/${encodedThreadId}${query ? `?${query}` : ""}${hash ? `#${hash}` : ""}`);
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
export function buildInsightThreadUrl(
|
|
@@ -93,7 +95,7 @@ export function buildInsightThreadUrl(
|
|
|
93
95
|
if (options?.demo) params.set("demo", "1");
|
|
94
96
|
const query = params.toString();
|
|
95
97
|
const hash = options?.messageId ? getForumMessageAnchorId(options.messageId) : "";
|
|
96
|
-
return `${INSIGHT_THREAD_ROUTE_PREFIX}${encodedThreadId}${query ? `?${query}` : ""}${hash ? `#${hash}` : ""}
|
|
98
|
+
return toPublicNewsroomPath(`${INSIGHT_THREAD_ROUTE_PREFIX}${encodedThreadId}${query ? `?${query}` : ""}${hash ? `#${hash}` : ""}`);
|
|
97
99
|
}
|
|
98
100
|
|
|
99
101
|
export function buildThreadUrlForSurface(
|
|
@@ -141,7 +143,7 @@ export function buildNewsroomForumIndexUrl(demo?: boolean): string {
|
|
|
141
143
|
const params = new URLSearchParams();
|
|
142
144
|
if (demo) params.set("demo", "1");
|
|
143
145
|
const query = params.toString();
|
|
144
|
-
return query ? `/newsroom?${query}` : "/newsroom";
|
|
146
|
+
return toPublicNewsroomPath(query ? `/newsroom?${query}` : "/newsroom");
|
|
145
147
|
}
|
|
146
148
|
|
|
147
149
|
export function buildNewsroomInsightsIndexUrl(demo?: boolean, domain?: string): string {
|
|
@@ -149,5 +151,5 @@ export function buildNewsroomInsightsIndexUrl(demo?: boolean, domain?: string):
|
|
|
149
151
|
if (demo) params.set("demo", "1");
|
|
150
152
|
if (domain?.trim()) params.set("domain", domain.trim());
|
|
151
153
|
const query = params.toString();
|
|
152
|
-
return query ? `/newsroom/insights?${query}` : "/newsroom/insights";
|
|
154
|
+
return toPublicNewsroomPath(query ? `/newsroom/insights?${query}` : "/newsroom/insights");
|
|
153
155
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { browserPathToInternalNewsroomPath, toPublicNewsroomPath } from "./newsroom-base-path";
|
|
1
2
|
export type NewsroomIndexTab = "references" | "messages" | "assignments" | "insights";
|
|
2
3
|
|
|
3
4
|
export type ReferenceIndexOrder = "published" | "imported";
|
|
@@ -147,10 +148,10 @@ export function buildNewsroomIndexWebPath(
|
|
|
147
148
|
tab: NewsroomIndexTab,
|
|
148
149
|
filters: ReferencesIndexFilters | MessagesIndexFilters | AssignmentsIndexFilters | InsightsIndexFilters,
|
|
149
150
|
): string {
|
|
150
|
-
if (tab === "references") return `/newsroom/references${buildReferencesIndexQuery(filters as ReferencesIndexFilters)}
|
|
151
|
-
if (tab === "messages") return `/newsroom/messages${buildMessagesIndexQuery(filters as MessagesIndexFilters)}
|
|
152
|
-
if (tab === "insights") return `/newsroom/insights${buildInsightsIndexQuery(filters as InsightsIndexFilters)}
|
|
153
|
-
return `/newsroom/assignments${buildAssignmentsIndexQuery(filters as AssignmentsIndexFilters)}
|
|
151
|
+
if (tab === "references") return toPublicNewsroomPath(`/newsroom/references${buildReferencesIndexQuery(filters as ReferencesIndexFilters)}`);
|
|
152
|
+
if (tab === "messages") return toPublicNewsroomPath(`/newsroom/messages${buildMessagesIndexQuery(filters as MessagesIndexFilters)}`);
|
|
153
|
+
if (tab === "insights") return toPublicNewsroomPath(`/newsroom/insights${buildInsightsIndexQuery(filters as InsightsIndexFilters)}`);
|
|
154
|
+
return toPublicNewsroomPath(`/newsroom/assignments${buildAssignmentsIndexQuery(filters as AssignmentsIndexFilters)}`);
|
|
154
155
|
}
|
|
155
156
|
|
|
156
157
|
export function syncBrowserNewsroomIndexUrl(
|
|
@@ -168,8 +169,9 @@ export function syncBrowserNewsroomIndexUrl(
|
|
|
168
169
|
|
|
169
170
|
/** Lineage id from `/newsroom/references/<id>` (not index-only URLs). */
|
|
170
171
|
export function parseReferenceLineageIdFromNewsroomPathname(pathname: string | null | undefined): string | null {
|
|
171
|
-
|
|
172
|
-
|
|
172
|
+
const internalPathname = pathname ? browserPathToInternalNewsroomPath(pathname) : null;
|
|
173
|
+
if (!internalPathname?.startsWith("/newsroom/references/")) return null;
|
|
174
|
+
const segment = internalPathname.slice("/newsroom/references/".length).split("/")[0]?.trim() ?? "";
|
|
173
175
|
if (!segment) return null;
|
|
174
176
|
try {
|
|
175
177
|
return decodeURIComponent(segment);
|
|
@@ -180,8 +182,9 @@ export function parseReferenceLineageIdFromNewsroomPathname(pathname: string | n
|
|
|
180
182
|
|
|
181
183
|
/** Assignment id from `/newsroom/assignments/<id>` (not index-only URLs). */
|
|
182
184
|
export function parseAssignmentIdFromNewsroomPathname(pathname: string | null | undefined): string | null {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
+
const internalPathname = pathname ? browserPathToInternalNewsroomPath(pathname) : null;
|
|
186
|
+
if (!internalPathname?.startsWith("/newsroom/assignments/")) return null;
|
|
187
|
+
const segment = internalPathname.slice("/newsroom/assignments/".length).split("/")[0]?.trim() ?? "";
|
|
185
188
|
if (!segment) return null;
|
|
186
189
|
try {
|
|
187
190
|
return decodeURIComponent(segment);
|
|
@@ -191,8 +194,9 @@ export function parseAssignmentIdFromNewsroomPathname(pathname: string | null |
|
|
|
191
194
|
}
|
|
192
195
|
|
|
193
196
|
export function parseInsightThreadIdFromNewsroomPathname(pathname: string | null | undefined): string | null {
|
|
194
|
-
|
|
195
|
-
|
|
197
|
+
const internalPathname = pathname ? browserPathToInternalNewsroomPath(pathname) : null;
|
|
198
|
+
if (!internalPathname?.startsWith("/newsroom/insights/")) return null;
|
|
199
|
+
const segment = internalPathname.slice("/newsroom/insights/".length).split("/")[0]?.trim() ?? "";
|
|
196
200
|
if (!segment) return null;
|
|
197
201
|
try {
|
|
198
202
|
return decodeURIComponent(segment);
|
package/lib/semantic-graph.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { toPublicNewsroomPath } from "./newsroom-base-path";
|
|
1
2
|
import type {
|
|
2
3
|
AssignmentRecord,
|
|
3
4
|
CategorySteeringCategory,
|
|
@@ -175,6 +176,10 @@ export function predicateLabel(predicate: string, direction: "outgoing" | "incom
|
|
|
175
176
|
}
|
|
176
177
|
|
|
177
178
|
export function newsDeskHrefForSemanticObject(kind: string, lineageId: string): string {
|
|
179
|
+
return toPublicNewsroomPath(internalNewsDeskHrefForSemanticObject(kind, lineageId));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function internalNewsDeskHrefForSemanticObject(kind: string, lineageId: string): string {
|
|
178
183
|
const encoded = encodeURIComponent(lineageId);
|
|
179
184
|
if (kind === "reference") return `/newsroom/references/${encoded}`;
|
|
180
185
|
if (kind === "category") return `/newsroom/topics?category=${encoded}`;
|
|
@@ -12,7 +12,8 @@ function isStaticOrApiPath(pathname: string): boolean {
|
|
|
12
12
|
|
|
13
13
|
export { isStaticOrApiPath };
|
|
14
14
|
|
|
15
|
-
export function isStagingGatedPath(pathname: string, readerBasePath: string = ""): boolean {
|
|
15
|
+
export function isStagingGatedPath(pathname: string, readerBasePath: string = "", newsroomAtRoot: boolean = false): boolean {
|
|
16
|
+
if (newsroomAtRoot) return false;
|
|
16
17
|
if (isStaticOrApiPath(pathname)) return false;
|
|
17
18
|
if (pathname === "/robots.txt") return false;
|
|
18
19
|
if (pathname === "/newsroom" || pathname.startsWith("/newsroom/")) return false;
|
package/middleware.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { NextRequest } from "next/server";
|
|
2
2
|
import { NextResponse } from "next/server";
|
|
3
3
|
import { getSiteBrand } from "./lib/site-brand";
|
|
4
|
+
import { newsroomHref } from "./lib/newsroom-base-path";
|
|
4
5
|
import { getReaderBasePath } from "./lib/reader-base-path";
|
|
5
6
|
import { isStagingGatedPath, isStaticOrApiPath } from "./lib/staging-gated-path";
|
|
6
7
|
import { getSiteEnv, isIndexable } from "./lib/site-env";
|
|
@@ -18,7 +19,7 @@ function usesNewsroomRootPaths(): boolean {
|
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
function isStagingGatedPathForBrand(pathname: string): boolean {
|
|
21
|
-
return isStagingGatedPath(pathname, getReaderBasePath());
|
|
22
|
+
return isStagingGatedPath(pathname, getReaderBasePath(), usesNewsroomRootPaths());
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
function routeRequest(request: NextRequest): NextResponse {
|
|
@@ -60,12 +61,14 @@ function routeRequest(request: NextRequest): NextResponse {
|
|
|
60
61
|
export async function middleware(request: NextRequest): Promise<NextResponse> {
|
|
61
62
|
let sessionResponse: NextResponse | null = null;
|
|
62
63
|
const { pathname } = request.nextUrl;
|
|
63
|
-
const gated = isStaticPreviewEnabled()
|
|
64
|
+
const gated = isStaticPreviewEnabled() && !usesNewsroomRootPaths()
|
|
65
|
+
? isPreviewGatedPath(pathname)
|
|
66
|
+
: isStagingGatedPathForBrand(pathname);
|
|
64
67
|
if (getSiteEnv() === "staging" && gated) {
|
|
65
68
|
sessionResponse = NextResponse.next();
|
|
66
69
|
const access = await getStagingAccess(request, sessionResponse);
|
|
67
70
|
if (access === "anonymous") {
|
|
68
|
-
return withRobotsHeader(NextResponse.redirect(new URL(
|
|
71
|
+
return withRobotsHeader(NextResponse.redirect(new URL(newsroomHref(), request.url)));
|
|
69
72
|
}
|
|
70
73
|
if (access === "forbidden") {
|
|
71
74
|
return withRobotsHeader(new NextResponse("Staging is limited to editors and admins.", { status: 403 }));
|
package/package.json
CHANGED
package/routes.manifest.json
CHANGED