@anthusai/papyrus 2.0.0-next.1 → 2.0.0-next.100

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.
Files changed (252) hide show
  1. package/amplify/auth/resource.js +16 -1
  2. package/amplify/auth/resource.ts +19 -1
  3. package/amplify/data/function-handler.js +20 -0
  4. package/amplify/data/function-handler.ts +40 -0
  5. package/amplify/data/resource.js +158 -61
  6. package/amplify/data/resource.ts +165 -61
  7. package/amplify/data/schema.js +2103 -1979
  8. package/amplify/data/schema.ts +206 -68
  9. package/amplify/functions/assignment-action/data-access.js +90 -0
  10. package/amplify/functions/assignment-action/data-access.ts +89 -0
  11. package/amplify/functions/assignment-action/handler.ts +1 -1
  12. package/amplify/functions/automation-view/handler.py +17 -0
  13. package/amplify/functions/automation-view/resource.js +24 -0
  14. package/amplify/functions/automation-view/resource.ts +34 -0
  15. package/amplify/functions/automation-view/schema.js +26 -0
  16. package/amplify/functions/automation-view/schema.ts +28 -0
  17. package/amplify/functions/automation-view/wire.js +56 -0
  18. package/amplify/functions/automation-view/wire.ts +76 -0
  19. package/amplify/functions/content-actions/handler.py +70 -2
  20. package/amplify/functions/content-actions/requirements.txt +1 -0
  21. package/amplify/functions/content-actions/resource.js +1 -1
  22. package/amplify/functions/content-actions/resource.ts +1 -1
  23. package/amplify/functions/editorial-checks/handler.py +14 -0
  24. package/amplify/functions/editorial-checks/requirements.txt +1 -0
  25. package/amplify/functions/editorial-checks/resource.js +43 -0
  26. package/amplify/functions/editorial-checks/resource.ts +60 -0
  27. package/amplify/functions/editorial-checks/schema.js +122 -0
  28. package/amplify/functions/editorial-checks/schema.ts +124 -0
  29. package/amplify/functions/editorial-checks/wire.js +53 -0
  30. package/amplify/functions/editorial-checks/wire.ts +61 -0
  31. package/amplify/functions/model-attachment-upload/handler.ts +1 -0
  32. package/amplify/functions/monitoring-view/handler.py +11 -0
  33. package/amplify/functions/monitoring-view/resource.js +24 -0
  34. package/amplify/functions/monitoring-view/resource.ts +34 -0
  35. package/amplify/functions/monitoring-view/schema.js +29 -0
  36. package/amplify/functions/monitoring-view/schema.ts +31 -0
  37. package/amplify/functions/monitoring-view/wire.js +64 -0
  38. package/amplify/functions/monitoring-view/wire.ts +81 -0
  39. package/amplify/functions/public-forms/core.js +247 -0
  40. package/amplify/functions/public-forms/core.ts +310 -0
  41. package/amplify/functions/public-forms/handler.ts +41 -0
  42. package/amplify/functions/public-forms/origins.js +35 -0
  43. package/amplify/functions/public-forms/origins.ts +43 -0
  44. package/amplify/functions/public-forms/resource.js +9 -0
  45. package/amplify/functions/public-forms/resource.ts +10 -0
  46. package/amplify/functions/public-forms/wire.js +25 -0
  47. package/amplify/functions/public-forms/wire.ts +32 -0
  48. package/amplify/functions/shared/editorial-context.ts +63 -4
  49. package/amplify/functions/shared/python-bundle.js +20 -14
  50. package/amplify/functions/shared/python-bundle.ts +25 -18
  51. package/amplify/plugins/newsletter/config.js +245 -0
  52. package/amplify/plugins/newsletter/config.ts +305 -0
  53. package/amplify/plugins/newsletter/function/handler.py +6 -0
  54. package/amplify/plugins/newsletter/function/requirements.txt +5 -0
  55. package/amplify/plugins/newsletter/ops/handler.py +12 -0
  56. package/amplify/plugins/newsletter/ops/resource.js +27 -0
  57. package/amplify/plugins/newsletter/ops/resource.ts +37 -0
  58. package/amplify/plugins/newsletter/papyrus.plugin.js +263 -0
  59. package/amplify/plugins/newsletter/papyrus.plugin.ts +311 -0
  60. package/amplify/plugins/newsletter/schema.js +57 -0
  61. package/amplify/plugins/newsletter/schema.ts +62 -0
  62. package/amplify/plugins/newsletter/secure-string-parameter.js +107 -0
  63. package/amplify/plugins/newsletter/secure-string-parameter.ts +120 -0
  64. package/amplify/plugins/newsletter/sending.js +140 -0
  65. package/amplify/plugins/newsletter/sending.ts +186 -0
  66. package/amplify/plugins/reader-steering/config.js +182 -0
  67. package/amplify/plugins/reader-steering/config.ts +290 -0
  68. package/amplify/plugins/reader-steering/function/ai_moderation.py +246 -0
  69. package/amplify/plugins/reader-steering/function/handler.py +1567 -0
  70. package/amplify/plugins/reader-steering/function/moderation-prompt.md +27 -0
  71. package/amplify/plugins/reader-steering/function/moderation.py +316 -0
  72. package/amplify/plugins/reader-steering/function/proposals.py +458 -0
  73. package/amplify/plugins/reader-steering/function/resource.js +27 -0
  74. package/amplify/plugins/reader-steering/function/resource.ts +35 -0
  75. package/amplify/plugins/reader-steering/papyrus.plugin.js +186 -0
  76. package/amplify/plugins/reader-steering/papyrus.plugin.ts +212 -0
  77. package/amplify/plugins/reader-steering/schema.js +229 -0
  78. package/amplify/plugins/reader-steering/schema.ts +231 -0
  79. package/amplify/plugins/registry.js +4 -0
  80. package/amplify/plugins/registry.ts +4 -0
  81. package/amplify/plugins/signup/schema.js +2 -1
  82. package/amplify/plugins/signup/schema.ts +2 -1
  83. package/amplify/plugins/types.ts +5 -0
  84. package/amplify/plugins/wire.js +1 -0
  85. package/amplify/plugins/wire.ts +1 -0
  86. package/amplify/publication/projection-lease.js +30 -0
  87. package/amplify/publication/projection-lease.ts +39 -0
  88. package/amplify/publication/redirect-and-index.js +105 -0
  89. package/amplify/publication/redirect-rules.js +73 -0
  90. package/amplify/publication/redirect-rules.ts +93 -0
  91. package/amplify/publication/s3-projection.js +7 -1
  92. package/amplify/publication/s3-projection.ts +9 -1
  93. package/amplify/site-backend-config.js +19 -0
  94. package/amplify/site-backend-config.ts +45 -1
  95. package/amplify/site-backend-names.js +4 -2
  96. package/amplify/site-backend-names.ts +4 -2
  97. package/amplify/site-backend.js +51 -4
  98. package/amplify/site-backend.ts +60 -4
  99. package/app/api/auth/prospectus/sign-in/route.ts +4 -0
  100. package/app/api/newsletter/confirm/route.ts +13 -0
  101. package/app/api/newsletter/preferences/route.ts +13 -0
  102. package/app/api/newsletter/state/route.ts +9 -0
  103. package/app/api/newsletter/subscribe/route.ts +9 -0
  104. package/app/api/newsletter/unsubscribe/route.ts +13 -0
  105. package/app/api/newsroom/chat/[...path]/route.ts +17 -0
  106. package/app/api/newsroom/curation/context/route.ts +9 -0
  107. package/app/api/newsroom/curation/priming/route.ts +9 -0
  108. package/app/api/newsroom/curation/publication/route.ts +9 -0
  109. package/app/api/reader/comment/delete/route.ts +9 -0
  110. package/app/api/reader/comment/edit/route.ts +9 -0
  111. package/app/api/reader/comment/route.ts +9 -0
  112. package/app/api/reader/flag/route.ts +9 -0
  113. package/app/api/reader/handle/route.ts +9 -0
  114. package/app/api/reader/me/route.ts +9 -0
  115. package/app/api/reader/rating/route.ts +9 -0
  116. package/app/api/reader/report/route.ts +9 -0
  117. package/app/api/reader/retired/route.ts +9 -0
  118. package/app/api/reader/submit/route.ts +9 -0
  119. package/app/api/reader/vote/route.ts +9 -0
  120. package/app/layout.tsx +5 -1
  121. package/bin/papyrus-infra.mjs +20 -1
  122. package/components/automation-panel.tsx +49 -0
  123. package/components/automation-run-now.tsx +97 -0
  124. package/components/automation-view.tsx +195 -0
  125. package/components/editorial-checks-admin-panel.tsx +362 -0
  126. package/components/editorial-finding-card.tsx +162 -0
  127. package/components/editorial-findings-panel.tsx +91 -0
  128. package/components/editorial-preview-popover.tsx +103 -0
  129. package/components/markus-body-editor.tsx +213 -0
  130. package/components/markus-ir-preview.tsx +147 -6
  131. package/components/moderation-panel.tsx +248 -0
  132. package/components/monitoring-overview-view.tsx +414 -0
  133. package/components/monitoring-panel.tsx +60 -0
  134. package/components/news-desk-client-provider.tsx +18 -18
  135. package/components/news-desk-taxonomy-client.ts +28 -8
  136. package/components/newsletter-panel.tsx +474 -0
  137. package/components/newsletter-sections.tsx +163 -0
  138. package/components/newsroom-access-gate.tsx +16 -2
  139. package/components/newsroom-article-editor.tsx +145 -18
  140. package/components/newsroom-articles-view.tsx +6 -6
  141. package/components/newsroom-assignment-detail.tsx +6 -6
  142. package/components/newsroom-board-view.tsx +14 -10
  143. package/components/newsroom-curation-bootstrap.tsx +45 -0
  144. package/components/newsroom-ops-overview.tsx +26 -96
  145. package/components/newsroom-ops-shell.tsx +9 -5
  146. package/components/newsroom-organizer.css +90 -61
  147. package/components/newsroom-overview-skeleton.tsx +25 -0
  148. package/components/newsroom-references-view.tsx +192 -49
  149. package/components/newsroom-theme-fonts/broadsheet-green.css +10 -0
  150. package/components/newsroom-theme-fonts/broadsheet-green.tsx +6 -0
  151. package/components/newsroom-theme-fonts/newspaper-gothic.css +9 -0
  152. package/components/newsroom-theme-fonts/newspaper-gothic.tsx +6 -0
  153. package/components/newsroom-theme-fonts/night-desk.css +10 -0
  154. package/components/newsroom-theme-fonts/night-desk.tsx +6 -0
  155. package/components/newsroom-theme-fonts/refined-newsprint.css +11 -0
  156. package/components/newsroom-theme-fonts/refined-newsprint.tsx +6 -0
  157. package/components/newsroom-theme.css +39 -0
  158. package/components/newsroom-theme.tsx +33 -0
  159. package/components/notification-center.tsx +281 -0
  160. package/components/papyrus-console-conversation.css +14 -0
  161. package/components/papyrus-console-conversation.tsx +55 -0
  162. package/components/papyrus-console-shell.tsx +62 -420
  163. package/components/papyrus-private-chat-panel.tsx +134 -0
  164. package/components/publication-cyclotron-panel.tsx +15 -10
  165. package/components/reader-auth-state.ts +1 -1
  166. package/components/reference-add-entry.tsx +75 -0
  167. package/components/reference-curation-controls.tsx +31 -22
  168. package/components/reference-cyclotron-priming.tsx +63 -25
  169. package/components/reference-cyclotron-status.tsx +4 -4
  170. package/components/reference-cyclotron-suggestion.tsx +15 -11
  171. package/components/reference-live-agreement.tsx +10 -10
  172. package/components/reference-priming.tsx +14 -10
  173. package/components/reference-relevance-review.tsx +4 -4
  174. package/components/reference-section-suggestion.tsx +2 -2
  175. package/components/topic-steering-workspace.tsx +241 -144
  176. package/components/use-editorial-checks.ts +133 -0
  177. package/infra/amplify-app-shell.js +96 -16
  178. package/infra/amplify-app-shell.ts +108 -18
  179. package/infra/cloud-email-config.js +32 -0
  180. package/infra/cloud-email-config.ts +39 -0
  181. package/infra/cloud-email.js +57 -0
  182. package/infra/cloud-email.test.js +69 -0
  183. package/infra/cloud-email.test.ts +66 -0
  184. package/infra/cloud-email.ts +60 -0
  185. package/infra/index.js +1 -0
  186. package/infra/secure-string-parameter-handler.js +41 -0
  187. package/infra/secure-string-parameter-handler.ts +41 -0
  188. package/infra/secure-string-parameter.js +79 -0
  189. package/infra/secure-string-parameter.ts +91 -0
  190. package/infra/site-config.js +92 -6
  191. package/infra/site-config.ts +138 -6
  192. package/lib/automation-client.ts +54 -0
  193. package/lib/automation-fixture.ts +93 -0
  194. package/lib/automation-overview.ts +252 -0
  195. package/lib/category-repository.ts +14 -12
  196. package/lib/console-web-context.ts +1 -1
  197. package/lib/curation-routes.ts +345 -0
  198. package/lib/cyclotron-suggestions.ts +11 -11
  199. package/lib/editorial-checks-backend.ts +16 -0
  200. package/lib/editorial-checks-client.ts +212 -0
  201. package/lib/editorial-checks-demo.ts +147 -0
  202. package/lib/editorial-checks-settings.ts +27 -0
  203. package/lib/editorial-checks.ts +175 -0
  204. package/lib/editorial-preview.ts +228 -0
  205. package/lib/monitoring-client.ts +83 -0
  206. package/lib/monitoring-overview-fixture.ts +51 -0
  207. package/lib/monitoring-overview.ts +188 -0
  208. package/lib/news-desk-session.ts +12 -21
  209. package/lib/newsletter-api.ts +418 -0
  210. package/lib/newsletter-client.ts +46 -0
  211. package/lib/newsletter-fixture.ts +184 -0
  212. package/lib/newsletter-model.ts +202 -0
  213. package/lib/newsroom-board.ts +27 -2
  214. package/lib/newsroom-demo-dashboard.ts +1 -1
  215. package/lib/newsroom-nav.ts +1 -1
  216. package/lib/newsroom-organizer-nav.ts +2 -1
  217. package/lib/papyrus-chat-admission.ts +65 -0
  218. package/lib/papyrus-hosted-chat.ts +217 -0
  219. package/lib/papyrus-private-chat-client.ts +81 -0
  220. package/lib/prospectus-session.ts +30 -14
  221. package/lib/prospectus-sign-in-routes.ts +106 -31
  222. package/lib/prospectus-site-identity.ts +46 -6
  223. package/lib/reader-api.ts +145 -0
  224. package/lib/reader-moderation.ts +220 -0
  225. package/lib/reader-retirement-route.ts +89 -0
  226. package/lib/reader-subject.md +29 -0
  227. package/lib/reader-subject.ts +53 -0
  228. package/lib/reference-review-details.ts +71 -0
  229. package/lib/reference-review-request.ts +14 -0
  230. package/lib/relevance-decisions.ts +42 -10
  231. package/lib/relevance-status.ts +6 -6
  232. package/lib/review-client.ts +120 -0
  233. package/lib/review-fixture.ts +45 -0
  234. package/lib/review-requests.ts +246 -0
  235. package/lib/semantic-graph.ts +2 -0
  236. package/lib/shared-chat-admission.ts +182 -0
  237. package/lib/site-brand-tenant.ts +11 -6
  238. package/lib/site-brand.ts +23 -3
  239. package/lib/site-origin-value.ts +50 -0
  240. package/lib/site-origin.ts +8 -0
  241. package/lib/use-reference-review-data.ts +44 -0
  242. package/middleware.ts +14 -3
  243. package/package.json +98 -4
  244. package/routes.manifest.json +227 -2
  245. package/src/with-papyrus.mjs +1 -1
  246. package/components/newsroom-fonts/playfair-display-700.ttf +0 -0
  247. package/components/newsroom-fonts/playfair-display-900.ttf +0 -0
  248. package/components/newsroom-fonts/playfair-display-OFL.txt +0 -93
  249. package/components/newsroom-fonts/plus-jakarta-sans-400.ttf +0 -0
  250. package/components/newsroom-fonts/plus-jakarta-sans-600.ttf +0 -0
  251. package/components/newsroom-fonts/plus-jakarta-sans-OFL.txt +0 -93
  252. package/components/newsroom-newsprint-board.css +0 -7
package/lib/site-brand.ts CHANGED
@@ -3,6 +3,7 @@ import type { ComponentType } from "react";
3
3
  import type { EditionPresentationFormat } from "./content-types";
4
4
  import type { Article, ArticleVideoAsset } from "./articles";
5
5
  import type { BlogPageBackgroundProps } from "../components/blog-page-background";
6
+ import type { KanbusThemeId } from "@kanbus/ui";
6
7
  import type { SiteBrandFont } from "./brand-fonts";
7
8
  import type { PictogramFigureProps } from "../components/pictogram-figure";
8
9
  import papyrusSite from "papyrus-site";
@@ -118,6 +119,13 @@ export type SiteBrand = {
118
119
  defaultVideoCredit?: string;
119
120
  themePack: ThemePackId;
120
121
  themeTokens: ThemePackTokens;
122
+ /**
123
+ * The Kanbus editorial theme the whole newsroom (sidebar, toolbar, boards,
124
+ * detail panel) renders in. Hard-coded per publication: editors cannot
125
+ * change it. Per-publication tweaks are `--kb-theme-*` overrides in the
126
+ * publication's `theme.css`, scoped to `[data-kanbus-theme]`.
127
+ */
128
+ kanbusTheme: KanbusThemeId;
121
129
  renderer: RendererConfig;
122
130
  hosting: HostingConfig;
123
131
  /** Static reader app when it is not co-hosted with this Papyrus checkout. */
@@ -134,9 +142,12 @@ export type SiteBrand = {
134
142
  readerBasePath?: string;
135
143
  opsChrome: OpsChrome;
136
144
  corpusKey: string;
137
- steeringConfigPath: string;
138
- newsroomSectionsConfigPath: string;
139
- analysisProfilesPath: string;
145
+ /** Optional repo file for topic steering. Editorial and steering configuration is backend data; a data-driven site sets none and nothing is looked up. */
146
+ steeringConfigPath?: string;
147
+ /** Optional repo file for the local-preview demo sections only. Sections live in the backend. */
148
+ newsroomSectionsConfigPath?: string;
149
+ /** Optional repo file listing analysis profiles. */
150
+ analysisProfilesPath?: string;
140
151
  publicationName: string;
141
152
  components?: SiteBrandComponents;
142
153
  /**
@@ -182,6 +193,7 @@ const REFERENCE_SITE_BRANDS: Record<SiteBrandId, SiteBrand> = {
182
193
  sectionLinkStrategy: "route",
183
194
  themePack: "papyrus",
184
195
  themeTokens: DEFAULT_THEME_PACK_TOKENS,
196
+ kanbusTheme: "broadsheet-green",
185
197
  renderer: { kind: "pretext" },
186
198
  hosting: { kind: "amplify-ssr" },
187
199
  opsChrome: "app",
@@ -237,6 +249,14 @@ export function getSiteBrand(id: SiteBrandId = resolveSiteBrandId()): SiteBrand
237
249
 
238
250
  export const SITE_BRAND = getSiteBrand();
239
251
 
252
+ /** Mirrors `DEFAULT_KANBUS_THEME` from `@kanbus/ui` (a test keeps the two equal) without a runtime import. */
253
+ export const FALLBACK_KANBUS_THEME: KanbusThemeId = "newspaper-gothic";
254
+
255
+ /** The newsroom theme for a brand; a brand that predates the field falls back to the default theme. */
256
+ export function getKanbusTheme(brand: Pick<SiteBrand, "kanbusTheme"> = SITE_BRAND): KanbusThemeId {
257
+ return brand.kanbusTheme ?? FALLBACK_KANBUS_THEME;
258
+ }
259
+
240
260
  export function getContentItemName(brand: SiteBrand = SITE_BRAND): ContentItemName {
241
261
  return brand.contentItemName ?? DEFAULT_CONTENT_ITEM_NAME;
242
262
  }
@@ -0,0 +1,50 @@
1
+ import type { NextRequest } from "next/server";
2
+ import { getSiteEnv } from "./site-env";
3
+
4
+ type EnvironmentVariables = Record<string, string | undefined>;
5
+
6
+ export const SITE_ORIGIN_ENV = "PAPYRUS_SITE_ORIGIN";
7
+
8
+ export class SiteOriginNotConfiguredError extends Error {
9
+ readonly status = 503;
10
+ readonly code = "site_origin_not_configured";
11
+ }
12
+
13
+ function isLoopbackHostname(hostname: string): boolean {
14
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
15
+ }
16
+
17
+ function configuredOrigin(value: string): string {
18
+ const invalid = () => new SiteOriginNotConfiguredError(`${SITE_ORIGIN_ENV} must be an https origin such as https://example.com with no path.`);
19
+ let parsed: URL;
20
+ try {
21
+ parsed = new URL(value);
22
+ } catch {
23
+ throw invalid();
24
+ }
25
+ if (parsed.protocol !== "https:" || parsed.origin !== value) throw invalid();
26
+ return parsed.origin;
27
+ }
28
+
29
+ function siteEnvOrNull(environment: EnvironmentVariables): string | null {
30
+ try {
31
+ return getSiteEnv(environment);
32
+ } catch {
33
+ return null;
34
+ }
35
+ }
36
+
37
+ /** The site's public origin from trusted configuration, never Host or forwarded headers. */
38
+ export function publicSiteOrigin(request: Pick<NextRequest, "nextUrl">, environment: EnvironmentVariables = process.env): string {
39
+ const configured = (environment[SITE_ORIGIN_ENV] ?? "").trim();
40
+ if (configured) return configuredOrigin(configured);
41
+ const { hostname, origin } = request.nextUrl;
42
+ const developing = siteEnvOrNull(environment) === "development" && environment.NODE_ENV !== "production";
43
+ if (isLoopbackHostname(hostname) && developing) return origin;
44
+ throw new SiteOriginNotConfiguredError(`${SITE_ORIGIN_ENV} is not set; this site cannot tell its public origin.`);
45
+ }
46
+
47
+ /** An absolute URL on the site's trusted public origin. */
48
+ export function publicSiteUrl(path: string, request: Pick<NextRequest, "nextUrl">, environment: EnvironmentVariables = process.env): URL {
49
+ return new URL(path, publicSiteOrigin(request, environment));
50
+ }
@@ -0,0 +1,8 @@
1
+ import { NextResponse } from "next/server";
2
+ import { SiteOriginNotConfiguredError } from "./site-origin-value";
3
+
4
+ export { SITE_ORIGIN_ENV, SiteOriginNotConfiguredError, publicSiteOrigin, publicSiteUrl } from "./site-origin-value";
5
+
6
+ export function siteOriginNotConfiguredResponse(error: SiteOriginNotConfiguredError): NextResponse {
7
+ return NextResponse.json({ error: error.code, message: error.message }, { status: error.status, headers: { "cache-control": "no-store" } });
8
+ }
@@ -0,0 +1,44 @@
1
+ "use client";
2
+
3
+ import { useCallback, useEffect, useState } from "react";
4
+
5
+ /** Load persisted predictions and attributed review history without cancelling on a loading rerender. */
6
+ export function useReferenceReviewData<Relation, Message>({
7
+ enabled,
8
+ loadRelations,
9
+ loadMessages,
10
+ onRelations,
11
+ onMessages,
12
+ }: {
13
+ enabled: boolean;
14
+ loadRelations: () => Promise<Relation[]>;
15
+ loadMessages: () => Promise<Message[]>;
16
+ onRelations: (relations: Relation[]) => void;
17
+ onMessages: (messages: Message[]) => void;
18
+ }) {
19
+ const [state, setState] = useState<"loading" | "ready" | "error">(enabled ? "loading" : "ready");
20
+ const [error, setError] = useState<string | null>(null);
21
+ const [attempt, setAttempt] = useState(0);
22
+ const retry = useCallback(() => setAttempt((current) => current + 1), []);
23
+ useEffect(() => {
24
+ if (!enabled) return;
25
+ let active = true;
26
+ setState("loading");
27
+ setError(null);
28
+ void Promise.allSettled([loadRelations(), loadMessages()]).then(([relations, history]) => {
29
+ if (!active) return;
30
+ if (relations.status === "fulfilled") onRelations(relations.value);
31
+ if (history.status === "fulfilled") onMessages(history.value);
32
+ const failure = relations.status === "rejected" ? relations.reason : history.status === "rejected" ? history.reason : null;
33
+ if (failure) {
34
+ const subject = relations.status === "rejected" ? "Predictions" : "Review history";
35
+ setError(`${subject} could not be loaded. ${failure instanceof Error ? failure.message : "Try again."}`);
36
+ setState("error");
37
+ } else {
38
+ setState("ready");
39
+ }
40
+ });
41
+ return () => { active = false; };
42
+ }, [enabled, loadRelations, loadMessages, onRelations, onMessages, attempt]);
43
+ return { state, error, retry };
44
+ }
package/middleware.ts CHANGED
@@ -5,6 +5,7 @@ import { newsroomHref } from "./lib/newsroom-base-path";
5
5
  import { getReaderBasePath } from "./lib/reader-base-path";
6
6
  import { isStagingGatedPath, isStaticOrApiPath } from "./lib/staging-gated-path";
7
7
  import { getSiteEnv, isIndexable } from "./lib/site-env";
8
+ import { SiteOriginNotConfiguredError, publicSiteUrl, siteOriginNotConfiguredResponse } from "./lib/site-origin";
8
9
  import { getStagingAccess } from "./lib/staging-gate";
9
10
  import {
10
11
  isPreviewGatedPath,
@@ -38,11 +39,11 @@ function routeRequest(request: NextRequest): NextResponse {
38
39
  }
39
40
 
40
41
  if (pathname === "/newsroom" || pathname === "/newsroom/") {
41
- return NextResponse.redirect(new URL(`/${request.nextUrl.search}`, request.url));
42
+ return NextResponse.redirect(publicSiteUrl(`/${request.nextUrl.search}`, request));
42
43
  }
43
44
  if (pathname.startsWith("/newsroom/")) {
44
45
  const target = pathname.slice("/newsroom".length) || "/";
45
- return NextResponse.redirect(new URL(`${target}${request.nextUrl.search}`, request.url));
46
+ return NextResponse.redirect(publicSiteUrl(`${target}${request.nextUrl.search}`, request));
46
47
  }
47
48
 
48
49
  if (pathname === "/" || pathname === "") {
@@ -59,6 +60,16 @@ function routeRequest(request: NextRequest): NextResponse {
59
60
  }
60
61
 
61
62
  export async function middleware(request: NextRequest): Promise<NextResponse> {
63
+ try {
64
+ return await handleRequest(request);
65
+ } catch (error) {
66
+ // Redirects name the site's public origin (request.url is localhost on Amplify); without it, fail closed.
67
+ if (error instanceof SiteOriginNotConfiguredError) return withRobotsHeader(siteOriginNotConfiguredResponse(error));
68
+ throw error;
69
+ }
70
+ }
71
+
72
+ async function handleRequest(request: NextRequest): Promise<NextResponse> {
62
73
  let sessionResponse: NextResponse | null = null;
63
74
  const { pathname } = request.nextUrl;
64
75
  const gated = isStaticPreviewEnabled()
@@ -68,7 +79,7 @@ export async function middleware(request: NextRequest): Promise<NextResponse> {
68
79
  sessionResponse = NextResponse.next();
69
80
  const access = await getStagingAccess(request, sessionResponse);
70
81
  if (access === "anonymous") {
71
- return withRobotsHeader(NextResponse.redirect(new URL(newsroomHref(), request.url)));
82
+ return withRobotsHeader(NextResponse.redirect(publicSiteUrl(newsroomHref(), request)));
72
83
  }
73
84
  if (access === "forbidden") {
74
85
  return withRobotsHeader(new NextResponse("Staging is limited to editors and admins.", { status: 403 }));
package/package.json CHANGED
@@ -75,14 +75,27 @@
75
75
  "./components/archive-grid": "./components/archive-grid.tsx",
76
76
  "./components/archive-shell": "./components/archive-shell.tsx",
77
77
  "./components/article-video": "./components/article-video.tsx",
78
+ "./components/automation-panel": "./components/automation-panel.tsx",
79
+ "./components/automation-run-now": "./components/automation-run-now.tsx",
80
+ "./components/automation-view": "./components/automation-view.tsx",
78
81
  "./components/blog-page-background": "./components/blog-page-background.tsx",
79
82
  "./components/curation-delegation-client": "./components/curation-delegation-client.ts",
80
83
  "./components/dev-sandbox-editor-sign-in": "./components/dev-sandbox-editor-sign-in.tsx",
84
+ "./components/editorial-checks-admin-panel": "./components/editorial-checks-admin-panel.tsx",
85
+ "./components/editorial-finding-card": "./components/editorial-finding-card.tsx",
86
+ "./components/editorial-findings-panel": "./components/editorial-findings-panel.tsx",
87
+ "./components/editorial-preview-popover": "./components/editorial-preview-popover.tsx",
81
88
  "./components/item-stream-view": "./components/item-stream-view.tsx",
89
+ "./components/markus-body-editor": "./components/markus-body-editor.tsx",
82
90
  "./components/markus-ir-preview": "./components/markus-ir-preview.tsx",
91
+ "./components/moderation-panel": "./components/moderation-panel.tsx",
92
+ "./components/monitoring-overview-view": "./components/monitoring-overview-view.tsx",
93
+ "./components/monitoring-panel": "./components/monitoring-panel.tsx",
83
94
  "./components/news-desk-client-provider": "./components/news-desk-client-provider.tsx",
84
95
  "./components/news-desk-page": "./components/news-desk-page.tsx",
85
96
  "./components/news-desk-taxonomy-client": "./components/news-desk-taxonomy-client.ts",
97
+ "./components/newsletter-panel": "./components/newsletter-panel.tsx",
98
+ "./components/newsletter-sections": "./components/newsletter-sections.tsx",
86
99
  "./components/newspaper": "./components/newspaper.tsx",
87
100
  "./components/newsroom-access-gate": "./components/newsroom-access-gate.tsx",
88
101
  "./components/newsroom-article-editor": "./components/newsroom-article-editor.tsx",
@@ -91,12 +104,22 @@
91
104
  "./components/newsroom-assignments-view": "./components/newsroom-assignments-view.tsx",
92
105
  "./components/newsroom-board-view": "./components/newsroom-board-view.tsx",
93
106
  "./components/newsroom-client-shell": "./components/newsroom-client-shell.tsx",
107
+ "./components/newsroom-curation-bootstrap": "./components/newsroom-curation-bootstrap.tsx",
94
108
  "./components/newsroom-curation-provider": "./components/newsroom-curation-provider.tsx",
95
109
  "./components/newsroom-ops-overview": "./components/newsroom-ops-overview.tsx",
96
110
  "./components/newsroom-ops-shell": "./components/newsroom-ops-shell.tsx",
111
+ "./components/newsroom-overview-skeleton": "./components/newsroom-overview-skeleton.tsx",
97
112
  "./components/newsroom-references-view": "./components/newsroom-references-view.tsx",
113
+ "./components/newsroom-theme-fonts/broadsheet-green": "./components/newsroom-theme-fonts/broadsheet-green.tsx",
114
+ "./components/newsroom-theme-fonts/newspaper-gothic": "./components/newsroom-theme-fonts/newspaper-gothic.tsx",
115
+ "./components/newsroom-theme-fonts/night-desk": "./components/newsroom-theme-fonts/night-desk.tsx",
116
+ "./components/newsroom-theme-fonts/refined-newsprint": "./components/newsroom-theme-fonts/refined-newsprint.tsx",
117
+ "./components/newsroom-theme": "./components/newsroom-theme.tsx",
98
118
  "./components/newsroom-topics-view": "./components/newsroom-topics-view.tsx",
119
+ "./components/notification-center": "./components/notification-center.tsx",
120
+ "./components/papyrus-console-conversation": "./components/papyrus-console-conversation.tsx",
99
121
  "./components/papyrus-console-shell": "./components/papyrus-console-shell.tsx",
122
+ "./components/papyrus-private-chat-panel": "./components/papyrus-private-chat-panel.tsx",
100
123
  "./components/pictogram-figure": "./components/pictogram-figure.tsx",
101
124
  "./components/presentation-footer": "./components/presentation-footer.tsx",
102
125
  "./components/presentation-header": "./components/presentation-header.tsx",
@@ -108,6 +131,7 @@
108
131
  "./components/reader-auth-state": "./components/reader-auth-state.ts",
109
132
  "./components/reader-settings": "./components/reader-settings.ts",
110
133
  "./components/reader-theme-control": "./components/reader-theme-control.tsx",
134
+ "./components/reference-add-entry": "./components/reference-add-entry.tsx",
111
135
  "./components/reference-curation-controls": "./components/reference-curation-controls.tsx",
112
136
  "./components/reference-cyclotron-priming": "./components/reference-cyclotron-priming.tsx",
113
137
  "./components/reference-cyclotron-status": "./components/reference-cyclotron-status.tsx",
@@ -143,6 +167,7 @@
143
167
  "./components/ui/tooltip": "./components/ui/tooltip.tsx",
144
168
  "./components/use-blog-header-obstacles": "./components/use-blog-header-obstacles.ts",
145
169
  "./components/use-brand-fonts-ready": "./components/use-brand-fonts-ready.ts",
170
+ "./components/use-editorial-checks": "./components/use-editorial-checks.ts",
146
171
  "./components/use-near-viewport": "./components/use-near-viewport.ts",
147
172
  "./components/use-paged-content-item-versions": "./components/use-paged-content-item-versions.ts",
148
173
  "./components/use-resolved-papyrus-theme": "./components/use-resolved-papyrus-theme.ts",
@@ -158,6 +183,9 @@
158
183
  "./lib/article-flow": "./lib/article-flow.ts",
159
184
  "./lib/article-frame-solver": "./lib/article-frame-solver.ts",
160
185
  "./lib/articles": "./lib/articles.ts",
186
+ "./lib/automation-client": "./lib/automation-client.ts",
187
+ "./lib/automation-fixture": "./lib/automation-fixture.ts",
188
+ "./lib/automation-overview": "./lib/automation-overview.ts",
161
189
  "./lib/blog-feature-solver": "./lib/blog-feature-solver.ts",
162
190
  "./lib/blog-rhythm": "./lib/blog-rhythm.ts",
163
191
  "./lib/brand-fonts-watch": "./lib/brand-fonts-watch.ts",
@@ -177,6 +205,7 @@
177
205
  "./lib/content-types": "./lib/content-types.ts",
178
206
  "./lib/curation-client": "./lib/curation-client.ts",
179
207
  "./lib/curation-delegation-helpers": "./lib/curation-delegation-helpers.ts",
208
+ "./lib/curation-routes": "./lib/curation-routes.ts",
180
209
  "./lib/cyclotron-suggestions": "./lib/cyclotron-suggestions.ts",
181
210
  "./lib/define-site": "./lib/define-site.ts",
182
211
  "./lib/demo-amplify-outputs": "./lib/demo-amplify-outputs.ts",
@@ -184,6 +213,12 @@
184
213
  "./lib/doctrine": "./lib/doctrine.ts",
185
214
  "./lib/edition-routes": "./lib/edition-routes.ts",
186
215
  "./lib/edition-sections": "./lib/edition-sections.ts",
216
+ "./lib/editorial-checks-backend": "./lib/editorial-checks-backend.ts",
217
+ "./lib/editorial-checks-client": "./lib/editorial-checks-client.ts",
218
+ "./lib/editorial-checks-demo": "./lib/editorial-checks-demo.ts",
219
+ "./lib/editorial-checks-settings": "./lib/editorial-checks-settings.ts",
220
+ "./lib/editorial-checks": "./lib/editorial-checks.ts",
221
+ "./lib/editorial-preview": "./lib/editorial-preview.ts",
187
222
  "./lib/empty-edition-layout-plan": "./lib/empty-edition-layout-plan.ts",
188
223
  "./lib/excerpts": "./lib/excerpts.ts",
189
224
  "./lib/front-matter-fields": "./lib/front-matter-fields.ts",
@@ -207,7 +242,14 @@
207
242
  "./lib/markus-projection": "./lib/markus-projection.ts",
208
243
  "./lib/markus-to-article": "./lib/markus-to-article.ts",
209
244
  "./lib/media-route-response": "./lib/media-route-response.ts",
245
+ "./lib/monitoring-client": "./lib/monitoring-client.ts",
246
+ "./lib/monitoring-overview-fixture": "./lib/monitoring-overview-fixture.ts",
247
+ "./lib/monitoring-overview": "./lib/monitoring-overview.ts",
210
248
  "./lib/news-desk-session": "./lib/news-desk-session.ts",
249
+ "./lib/newsletter-api": "./lib/newsletter-api.ts",
250
+ "./lib/newsletter-client": "./lib/newsletter-client.ts",
251
+ "./lib/newsletter-fixture": "./lib/newsletter-fixture.ts",
252
+ "./lib/newsletter-model": "./lib/newsletter-model.ts",
211
253
  "./lib/newspaper-layout": "./lib/newspaper-layout.ts",
212
254
  "./lib/newsroom-articles": "./lib/newsroom-articles.ts",
213
255
  "./lib/newsroom-assignments": "./lib/newsroom-assignments.ts",
@@ -231,7 +273,10 @@
231
273
  "./lib/newsroom-sections": "./lib/newsroom-sections.ts",
232
274
  "./lib/newsroom-topics": "./lib/newsroom-topics.ts",
233
275
  "./lib/oauth-redirect-priority": "./lib/oauth-redirect-priority.ts",
276
+ "./lib/papyrus-chat-admission": "./lib/papyrus-chat-admission.ts",
277
+ "./lib/papyrus-hosted-chat": "./lib/papyrus-hosted-chat.ts",
234
278
  "./lib/papyrus-object-kinds": "./lib/papyrus-object-kinds.ts",
279
+ "./lib/papyrus-private-chat-client": "./lib/papyrus-private-chat-client.ts",
235
280
  "./lib/papyrus-web-locations": "./lib/papyrus-web-locations.ts",
236
281
  "./lib/pilobol-sample": "./lib/pilobol-sample.ts",
237
282
  "./lib/plugin-settings": "./lib/plugin-settings.ts",
@@ -248,13 +293,19 @@
248
293
  "./lib/publication-cyclotron": "./lib/publication-cyclotron.ts",
249
294
  "./lib/publication-items": "./lib/publication-items.ts",
250
295
  "./lib/rate-limit-retry": "./lib/rate-limit-retry.ts",
296
+ "./lib/reader-api": "./lib/reader-api.ts",
251
297
  "./lib/reader-base-path": "./lib/reader-base-path.ts",
252
298
  "./lib/reader-cache-lifetime": "./lib/reader-cache-lifetime.ts",
299
+ "./lib/reader-moderation": "./lib/reader-moderation.ts",
300
+ "./lib/reader-retirement-route": "./lib/reader-retirement-route.ts",
253
301
  "./lib/reader-route-config": "./lib/reader-route-config.ts",
254
302
  "./lib/reader-static-params": "./lib/reader-static-params.ts",
255
303
  "./lib/reader-storage-url": "./lib/reader-storage-url.ts",
304
+ "./lib/reader-subject": "./lib/reader-subject.ts",
256
305
  "./lib/reference-display": "./lib/reference-display.ts",
257
306
  "./lib/reference-policy": "./lib/reference-policy.ts",
307
+ "./lib/reference-review-details": "./lib/reference-review-details.ts",
308
+ "./lib/reference-review-request": "./lib/reference-review-request.ts",
258
309
  "./lib/reference-source-preview": "./lib/reference-source-preview.ts",
259
310
  "./lib/relevance-decisions": "./lib/relevance-decisions.ts",
260
311
  "./lib/relevance-status": "./lib/relevance-status.ts",
@@ -263,14 +314,20 @@
263
314
  "./lib/reporting-story-budget": "./lib/reporting-story-budget.ts",
264
315
  "./lib/revalidate-prewarm": "./lib/revalidate-prewarm.ts",
265
316
  "./lib/revalidate-secret": "./lib/revalidate-secret.ts",
317
+ "./lib/review-client": "./lib/review-client.ts",
318
+ "./lib/review-fixture": "./lib/review-fixture.ts",
319
+ "./lib/review-requests": "./lib/review-requests.ts",
266
320
  "./lib/robots-policy": "./lib/robots-policy.ts",
267
321
  "./lib/root-route-redirect": "./lib/root-route-redirect.ts",
268
322
  "./lib/semantic-graph": "./lib/semantic-graph.ts",
323
+ "./lib/shared-chat-admission": "./lib/shared-chat-admission.ts",
269
324
  "./lib/shared-credentials-provider": "./lib/shared-credentials-provider.ts",
270
325
  "./lib/signup-csv": "./lib/signup-csv.ts",
271
326
  "./lib/site-brand-tenant": "./lib/site-brand-tenant.ts",
272
327
  "./lib/site-brand": "./lib/site-brand.ts",
273
328
  "./lib/site-env": "./lib/site-env.ts",
329
+ "./lib/site-origin-value": "./lib/site-origin-value.ts",
330
+ "./lib/site-origin": "./lib/site-origin.ts",
274
331
  "./lib/site-renderer": "./lib/site-renderer.ts",
275
332
  "./lib/site-section-suggestions": "./lib/site-section-suggestions.ts",
276
333
  "./lib/site-stack": "./lib/site-stack.ts",
@@ -282,6 +339,7 @@
282
339
  "./lib/test-editor-override": "./lib/test-editor-override.ts",
283
340
  "./lib/text-columns": "./lib/text-columns.ts",
284
341
  "./lib/themed-image": "./lib/themed-image.ts",
342
+ "./lib/use-reference-review-data": "./lib/use-reference-review-data.ts",
285
343
  "./lib/utils": "./lib/utils.ts",
286
344
  "./lib/video-loading": "./lib/video-loading.ts",
287
345
  "./lib/video-mode": "./lib/video-mode.ts",
@@ -313,6 +371,26 @@
313
371
  "./app/api/local-preview/derive/route": "./app/api/local-preview/derive/route.ts",
314
372
  "./app/api/local-preview/media/route": "./app/api/local-preview/media/route.ts",
315
373
  "./app/api/media/[...path]/route": "./app/api/media/[...path]/route.ts",
374
+ "./app/api/newsletter/confirm/route": "./app/api/newsletter/confirm/route.ts",
375
+ "./app/api/newsletter/preferences/route": "./app/api/newsletter/preferences/route.ts",
376
+ "./app/api/newsletter/state/route": "./app/api/newsletter/state/route.ts",
377
+ "./app/api/newsletter/subscribe/route": "./app/api/newsletter/subscribe/route.ts",
378
+ "./app/api/newsletter/unsubscribe/route": "./app/api/newsletter/unsubscribe/route.ts",
379
+ "./app/api/newsroom/chat/[...path]/route": "./app/api/newsroom/chat/[...path]/route.ts",
380
+ "./app/api/newsroom/curation/context/route": "./app/api/newsroom/curation/context/route.ts",
381
+ "./app/api/newsroom/curation/priming/route": "./app/api/newsroom/curation/priming/route.ts",
382
+ "./app/api/newsroom/curation/publication/route": "./app/api/newsroom/curation/publication/route.ts",
383
+ "./app/api/reader/comment/delete/route": "./app/api/reader/comment/delete/route.ts",
384
+ "./app/api/reader/comment/edit/route": "./app/api/reader/comment/edit/route.ts",
385
+ "./app/api/reader/comment/route": "./app/api/reader/comment/route.ts",
386
+ "./app/api/reader/flag/route": "./app/api/reader/flag/route.ts",
387
+ "./app/api/reader/handle/route": "./app/api/reader/handle/route.ts",
388
+ "./app/api/reader/me/route": "./app/api/reader/me/route.ts",
389
+ "./app/api/reader/rating/route": "./app/api/reader/rating/route.ts",
390
+ "./app/api/reader/report/route": "./app/api/reader/report/route.ts",
391
+ "./app/api/reader/retired/route": "./app/api/reader/retired/route.ts",
392
+ "./app/api/reader/submit/route": "./app/api/reader/submit/route.ts",
393
+ "./app/api/reader/vote/route": "./app/api/reader/vote/route.ts",
316
394
  "./app/api/revalidate/route": "./app/api/revalidate/route.ts",
317
395
  "./app/archive/page": "./app/archive/page.tsx",
318
396
  "./app/articles/[slug]/page": "./app/articles/[slug]/page.tsx",
@@ -378,20 +456,35 @@
378
456
  "optional": true
379
457
  }
380
458
  },
381
- "version": "2.0.0-next.1",
459
+ "version": "2.0.0-next.100",
382
460
  "dependencies": {
383
461
  "@aws-amplify/adapter-nextjs": "^1.7.3",
384
462
  "@aws-crypto/sha256-js": "5.2.0",
385
463
  "@aws-sdk/client-cognito-identity-provider": "3.1045.0",
464
+ "@aws-sdk/client-dynamodb": "^3.1045.0",
386
465
  "@aws-sdk/client-lambda": "^3.1045.0",
387
466
  "@aws-sdk/client-s3": "^3.1045.0",
388
- "@aws-sdk/client-secrets-manager": "3.1045.0",
389
467
  "@aws-sdk/client-ssm": "^3.1045.0",
390
468
  "@aws-sdk/credential-provider-node": "3.972.84",
391
469
  "@aws-sdk/s3-request-presigner": "^3.1045.0",
392
470
  "@base-ui/react": "^1.5.0",
393
471
  "@chenglou/pretext": "^0.0.7",
394
- "@kanbus/ui": "https://github.com/AnthusAI/Kanbus/releases/download/ui-v0.3.0/kanbus-ui-0.3.0.tgz",
472
+ "@codemirror/commands": "^6.11.1",
473
+ "@codemirror/lang-markdown": "^6.5.2",
474
+ "@codemirror/language": "^6.13.1",
475
+ "@codemirror/state": "^6.7.6",
476
+ "@codemirror/view": "^6.43.15",
477
+ "@fontsource-variable/hanken-grotesk": "5.3.0",
478
+ "@fontsource-variable/jetbrains-mono": "5.3.0",
479
+ "@fontsource-variable/libre-franklin": "5.3.0",
480
+ "@fontsource-variable/literata": "5.3.0",
481
+ "@fontsource-variable/newsreader": "5.3.0",
482
+ "@fontsource-variable/public-sans": "5.3.0",
483
+ "@fontsource-variable/source-serif-4": "5.3.1",
484
+ "@fontsource/ibm-plex-mono": "5.3.0",
485
+ "@fontsource/ibm-plex-sans": "5.3.0",
486
+ "@kanbus/ui": "https://github.com/AnthusAI/Kanbus/releases/download/ui-v0.4.1/kanbus-ui-0.4.1.tgz",
487
+ "@lezer/highlight": "^1.2.5",
395
488
  "@radix-ui/colors": "3.0.0",
396
489
  "@smithy/protocol-http": "5.4.1",
397
490
  "@smithy/signature-v4": "5.7.4",
@@ -400,10 +493,11 @@
400
493
  "anthus-vultus": "github:AnthusAI/Vultus#af98d57",
401
494
  "aws-amplify": "^6.17.0",
402
495
  "aws-jwt-verify": "4.0.1",
496
+ "chatticus": "https://github.com/AnthusAI/Chatticus/archive/db862e386119f97922cf303fd00ef0505d86a08a.tar.gz",
403
497
  "class-variance-authority": "^0.7.1",
404
498
  "clsx": "^2.1.1",
405
499
  "cmdk": "^1.1.1",
406
- "cyclotron": "https://github.com/AnthusAI/Cyclotron/releases/download/ui-v0.2.2/cyclotron-0.2.2.tgz",
500
+ "cyclotron": "https://github.com/AnthusAI/Cyclotron/releases/download/ui-v0.2.3/cyclotron-0.2.3.tgz",
407
501
  "d3": "^7.9.0",
408
502
  "esbuild": "^0.28.2",
409
503
  "framer-motion": "^14.3.0",