@anthusai/papyrus 1.19.1 → 2.0.0-next.10

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 (80) hide show
  1. package/amplify/data/resource.js +7 -0
  2. package/amplify/data/resource.ts +8 -0
  3. package/amplify/data/schema.js +8 -0
  4. package/amplify/data/schema.ts +9 -0
  5. package/amplify/functions/assignment-action/data-access.js +88 -0
  6. package/amplify/functions/assignment-action/data-access.ts +87 -0
  7. package/amplify/functions/content-actions/handler.py +7 -0
  8. package/amplify/functions/model-attachment-upload/handler.ts +1 -0
  9. package/amplify/plugins/editorial-checks/function/handler.py +14 -0
  10. package/amplify/plugins/editorial-checks/function/requirements.txt +1 -0
  11. package/amplify/plugins/editorial-checks/function/resource.js +43 -0
  12. package/amplify/plugins/editorial-checks/function/resource.ts +60 -0
  13. package/amplify/plugins/editorial-checks/papyrus.plugin.js +71 -0
  14. package/amplify/plugins/editorial-checks/papyrus.plugin.ts +87 -0
  15. package/amplify/plugins/editorial-checks/schema.js +94 -0
  16. package/amplify/plugins/editorial-checks/schema.ts +96 -0
  17. package/amplify/plugins/registry.js +2 -0
  18. package/amplify/plugins/registry.ts +2 -0
  19. package/amplify/site-backend.js +5 -0
  20. package/amplify/site-backend.ts +11 -0
  21. package/app/globals.css +0 -175
  22. package/app/newsroom/[section]/[...selection]/page.tsx +0 -6
  23. package/app/newsroom/[section]/page.tsx +2 -4
  24. package/app/newsroom/articles/page.tsx +1 -2
  25. package/app/newsroom/sections/[sectionId]/page.tsx +2 -6
  26. package/bin/papyrus-infra.mjs +11 -2
  27. package/components/editorial-checks-admin-panel.tsx +337 -0
  28. package/components/editorial-finding-card.tsx +162 -0
  29. package/components/editorial-findings-panel.tsx +91 -0
  30. package/components/editorial-preview-popover.tsx +103 -0
  31. package/components/markus-body-editor.tsx +213 -0
  32. package/components/markus-ir-preview.tsx +147 -6
  33. package/components/news-desk-page.tsx +3 -4
  34. package/components/newsroom-article-editor.tsx +138 -11
  35. package/components/newsroom-board-view.tsx +6 -7
  36. package/components/newsroom-ops-shell.tsx +146 -234
  37. package/components/newsroom-organizer.css +57 -61
  38. package/components/newsroom-theme-fonts/broadsheet-green.css +10 -0
  39. package/components/newsroom-theme-fonts/broadsheet-green.tsx +6 -0
  40. package/components/newsroom-theme-fonts/newspaper-gothic.css +9 -0
  41. package/components/newsroom-theme-fonts/newspaper-gothic.tsx +6 -0
  42. package/components/newsroom-theme-fonts/night-desk.css +10 -0
  43. package/components/newsroom-theme-fonts/night-desk.tsx +6 -0
  44. package/components/newsroom-theme-fonts/refined-newsprint.css +11 -0
  45. package/components/newsroom-theme-fonts/refined-newsprint.tsx +6 -0
  46. package/components/newsroom-theme.css +39 -0
  47. package/components/newsroom-theme.tsx +33 -0
  48. package/components/reference-cyclotron-priming.tsx +12 -13
  49. package/components/reference-cyclotron-status.tsx +4 -4
  50. package/components/reference-cyclotron-suggestion.tsx +6 -6
  51. package/components/reference-live-agreement.tsx +10 -10
  52. package/components/reference-priming.tsx +1 -1
  53. package/components/reference-relevance-review.tsx +1 -1
  54. package/components/reference-section-suggestion.tsx +1 -1
  55. package/components/topic-steering-workspace.tsx +36 -511
  56. package/components/use-editorial-checks.ts +131 -0
  57. package/lib/cyclotron-suggestions.ts +9 -9
  58. package/lib/editorial-checks-backend.ts +16 -0
  59. package/lib/editorial-checks-client.ts +194 -0
  60. package/lib/editorial-checks-demo.ts +147 -0
  61. package/lib/editorial-checks-settings.ts +24 -0
  62. package/lib/editorial-checks.ts +178 -0
  63. package/lib/editorial-preview.ts +228 -0
  64. package/lib/newsroom-board.ts +27 -2
  65. package/lib/newsroom-list-selection.ts +0 -3
  66. package/lib/newsroom-nav.ts +5 -8
  67. package/lib/newsroom-section-routing.ts +2 -4
  68. package/lib/relevance-status.ts +4 -4
  69. package/lib/site-brand.ts +18 -8
  70. package/package.json +34 -3
  71. package/routes.manifest.json +1 -1
  72. package/src/cdk-environment.mjs +44 -0
  73. package/components/newsroom-fonts/playfair-display-700.ttf +0 -0
  74. package/components/newsroom-fonts/playfair-display-900.ttf +0 -0
  75. package/components/newsroom-fonts/playfair-display-OFL.txt +0 -93
  76. package/components/newsroom-fonts/plus-jakarta-sans-400.ttf +0 -0
  77. package/components/newsroom-fonts/plus-jakarta-sans-600.ttf +0 -0
  78. package/components/newsroom-fonts/plus-jakarta-sans-OFL.txt +0 -93
  79. package/components/newsroom-newsprint-board.css +0 -7
  80. package/components/newsroom-organizer-shell.tsx +0 -153
@@ -0,0 +1,94 @@
1
+ import { a } from "@aws-amplify/backend";
2
+ import { editorialChecks } from "./function/resource.js";
3
+ const editors = ["editor", "admin"];
4
+ /**
5
+ * Policies, settings and editors' decisions live in Papyrus; Limatus checks
6
+ * content against them. Editors read policies and record decisions; admins
7
+ * manage policies and settings. Only the function (IAM) calls Limatus.
8
+ */
9
+ export function editorialChecksSchemaDefinitions() {
10
+ return {
11
+ EditorialPolicy: a
12
+ .model({
13
+ id: a.id().required(),
14
+ policyKey: a.string().required(),
15
+ scope: a.string().required(),
16
+ version: a.integer().required(),
17
+ title: a.string().required(),
18
+ guidance: a.string().required(),
19
+ severity: a.string().required(),
20
+ enabled: a.boolean().required(),
21
+ detectors: a.json().required(),
22
+ examples: a.json(),
23
+ rewriteGuidance: a.string(),
24
+ source: a.string().required(),
25
+ })
26
+ .disableOperations(["subscriptions"])
27
+ .authorization((allow) => [allow.group("editor").to(["read"]), allow.group("admin")]),
28
+ EditorialCheckSettings: a
29
+ .model({
30
+ id: a.id().required(),
31
+ settings: a.json().required(),
32
+ })
33
+ .disableOperations(["subscriptions"])
34
+ .authorization((allow) => [allow.group("editor").to(["read"]), allow.group("admin")]),
35
+ EditorialFeedback: a
36
+ .model({
37
+ id: a.id().required(),
38
+ itemId: a.string().required(),
39
+ findingId: a.string().required(),
40
+ policyId: a.string().required(),
41
+ detectorId: a.string().required(),
42
+ lane: a.string().required(),
43
+ probability: a.float(),
44
+ decision: a.string().required(),
45
+ reason: a.string(),
46
+ text: a.string(),
47
+ })
48
+ .disableOperations(["subscriptions"])
49
+ .secondaryIndexes((index) => [index("itemId").queryField("listEditorialFeedbackByItem")])
50
+ .authorization((allow) => [allow.group("editor").to(["create", "read"]), allow.group("admin")]),
51
+ checkEditorial: a
52
+ .query()
53
+ .arguments({ body: a.string().required(), format: a.string(), section: a.string() })
54
+ .returns(a.json())
55
+ .authorization((allow) => [allow.groups(editors)])
56
+ .handler(a.handler.function(editorialChecks)),
57
+ suggestEditorialRewrite: a
58
+ .query()
59
+ .arguments({
60
+ body: a.string().required(),
61
+ format: a.string(),
62
+ section: a.string(),
63
+ finding: a.json(),
64
+ selection: a.json(),
65
+ note: a.string(),
66
+ })
67
+ .returns(a.json())
68
+ .authorization((allow) => [allow.groups(editors)])
69
+ .handler(a.handler.function(editorialChecks)),
70
+ draftEditorialQuestions: a
71
+ .query()
72
+ .arguments({ title: a.string().required(), guidance: a.string().required(), examples: a.json() })
73
+ .returns(a.json())
74
+ .authorization((allow) => [allow.group("admin")])
75
+ .handler(a.handler.function(editorialChecks)),
76
+ tryEditorialPolicy: a
77
+ .query()
78
+ .arguments({ policy: a.json().required(), text: a.string().required(), format: a.string() })
79
+ .returns(a.json())
80
+ .authorization((allow) => [allow.group("admin")])
81
+ .handler(a.handler.function(editorialChecks)),
82
+ importEditorialStarterPack: a
83
+ .mutation()
84
+ .arguments({ name: a.string().required() })
85
+ .returns(a.json())
86
+ .authorization((allow) => [allow.group("admin")])
87
+ .handler(a.handler.function(editorialChecks)),
88
+ recalibrateEditorialPolicies: a
89
+ .mutation()
90
+ .returns(a.json())
91
+ .authorization((allow) => [allow.group("admin")])
92
+ .handler(a.handler.function(editorialChecks)),
93
+ };
94
+ }
@@ -0,0 +1,96 @@
1
+ import { a } from "@aws-amplify/backend";
2
+ import { editorialChecks } from "./function/resource";
3
+
4
+ const editors = ["editor", "admin"];
5
+
6
+ /**
7
+ * Policies, settings and editors' decisions live in Papyrus; Limatus checks
8
+ * content against them. Editors read policies and record decisions; admins
9
+ * manage policies and settings. Only the function (IAM) calls Limatus.
10
+ */
11
+ export function editorialChecksSchemaDefinitions() {
12
+ return {
13
+ EditorialPolicy: a
14
+ .model({
15
+ id: a.id().required(),
16
+ policyKey: a.string().required(),
17
+ scope: a.string().required(),
18
+ version: a.integer().required(),
19
+ title: a.string().required(),
20
+ guidance: a.string().required(),
21
+ severity: a.string().required(),
22
+ enabled: a.boolean().required(),
23
+ detectors: a.json().required(),
24
+ examples: a.json(),
25
+ rewriteGuidance: a.string(),
26
+ source: a.string().required(),
27
+ })
28
+ .disableOperations(["subscriptions"])
29
+ .authorization((allow) => [allow.group("editor").to(["read"]), allow.group("admin")]),
30
+ EditorialCheckSettings: a
31
+ .model({
32
+ id: a.id().required(),
33
+ settings: a.json().required(),
34
+ })
35
+ .disableOperations(["subscriptions"])
36
+ .authorization((allow) => [allow.group("editor").to(["read"]), allow.group("admin")]),
37
+ EditorialFeedback: a
38
+ .model({
39
+ id: a.id().required(),
40
+ itemId: a.string().required(),
41
+ findingId: a.string().required(),
42
+ policyId: a.string().required(),
43
+ detectorId: a.string().required(),
44
+ lane: a.string().required(),
45
+ probability: a.float(),
46
+ decision: a.string().required(),
47
+ reason: a.string(),
48
+ text: a.string(),
49
+ })
50
+ .disableOperations(["subscriptions"])
51
+ .secondaryIndexes((index) => [index("itemId").queryField("listEditorialFeedbackByItem")])
52
+ .authorization((allow) => [allow.group("editor").to(["create", "read"]), allow.group("admin")]),
53
+ checkEditorial: a
54
+ .query()
55
+ .arguments({ body: a.string().required(), format: a.string(), section: a.string() })
56
+ .returns(a.json())
57
+ .authorization((allow) => [allow.groups(editors)])
58
+ .handler(a.handler.function(editorialChecks)),
59
+ suggestEditorialRewrite: a
60
+ .query()
61
+ .arguments({
62
+ body: a.string().required(),
63
+ format: a.string(),
64
+ section: a.string(),
65
+ finding: a.json(),
66
+ selection: a.json(),
67
+ note: a.string(),
68
+ })
69
+ .returns(a.json())
70
+ .authorization((allow) => [allow.groups(editors)])
71
+ .handler(a.handler.function(editorialChecks)),
72
+ draftEditorialQuestions: a
73
+ .query()
74
+ .arguments({ title: a.string().required(), guidance: a.string().required(), examples: a.json() })
75
+ .returns(a.json())
76
+ .authorization((allow) => [allow.group("admin")])
77
+ .handler(a.handler.function(editorialChecks)),
78
+ tryEditorialPolicy: a
79
+ .query()
80
+ .arguments({ policy: a.json().required(), text: a.string().required(), format: a.string() })
81
+ .returns(a.json())
82
+ .authorization((allow) => [allow.group("admin")])
83
+ .handler(a.handler.function(editorialChecks)),
84
+ importEditorialStarterPack: a
85
+ .mutation()
86
+ .arguments({ name: a.string().required() })
87
+ .returns(a.json())
88
+ .authorization((allow) => [allow.group("admin")])
89
+ .handler(a.handler.function(editorialChecks)),
90
+ recalibrateEditorialPolicies: a
91
+ .mutation()
92
+ .returns(a.json())
93
+ .authorization((allow) => [allow.group("admin")])
94
+ .handler(a.handler.function(editorialChecks)),
95
+ };
96
+ }
@@ -1,6 +1,8 @@
1
+ import { editorialChecksPlugin } from "./editorial-checks/papyrus.plugin.js";
1
2
  import { signupPlugin } from "./signup/papyrus.plugin.js";
2
3
  /** Plugins are packaged with Papyrus and pinned by its version: there is no registry to fetch from. */
3
4
  export const KNOWN_PLUGINS = {
5
+ "editorial-checks": editorialChecksPlugin,
4
6
  signup: signupPlugin,
5
7
  };
6
8
  export function resolvePlugins(requests) {
@@ -1,8 +1,10 @@
1
1
  import type { PapyrusPlugin, PluginRequest } from "./types";
2
+ import { editorialChecksPlugin } from "./editorial-checks/papyrus.plugin";
2
3
  import { signupPlugin } from "./signup/papyrus.plugin";
3
4
 
4
5
  /** Plugins are packaged with Papyrus and pinned by its version: there is no registry to fetch from. */
5
6
  export const KNOWN_PLUGINS: Record<string, PapyrusPlugin<any, any>> = {
7
+ "editorial-checks": editorialChecksPlugin,
6
8
  signup: signupPlugin,
7
9
  };
8
10
 
@@ -23,6 +23,7 @@ import { defineSiteData } from "./data/resource.js";
23
23
  import { resolvePlugins } from "./plugins/registry.js";
24
24
  import { wirePlugins } from "./plugins/wire.js";
25
25
  import { assignmentAction } from "./functions/assignment-action/resource.js";
26
+ import { scopeAssignmentDataAccess } from "./functions/assignment-action/data-access.js";
26
27
  import { categoryAction } from "./functions/category-action/resource.js";
27
28
  import { ConsoleChatResponderStack } from "./functions/console-chat-responder/resource.js";
28
29
  import { contentActions, setSiteFilesForContentActionsBundle } from "./functions/content-actions/resource.js";
@@ -304,10 +305,14 @@ export function defineSiteBackend(papyrusSite) {
304
305
  }
305
306
  grantCorporaRead(backend.knowledgeQuery.resources.lambda);
306
307
  grantNewsroomReadWrite(backend.assignmentAction.resources.lambda);
308
+ scopeAssignmentDataAccess(backend.assignmentAction.resources.lambda, backend.data.resources.graphqlApi.arn);
307
309
  grantNewsroomReadWrite(backend.categoryAction.resources.lambda);
308
310
  grantNewsroomReadWrite(backend.newsroomSummary.resources.lambda);
309
311
  const contentActionsLambda = backend.contentActions.resources.lambda;
310
312
  grantNewsroomReadWriteDelete(contentActionsLambda);
313
+ // AppSync validates the token; pending intake additionally binds its actor
314
+ // and publication to this deployment's pool and existing API endpoint.
315
+ contentActionsLambda.addEnvironment("PAPYRUS_USER_POOL_ISSUER", `https://cognito-idp.${Stack.of(contentActionsLambda).region}.amazonaws.com/${backend.auth.resources.userPool.userPoolId}`);
311
316
  contentActionsLambda.addEnvironment("PAPYRUS_GRAPHQL_ENDPOINT", backend.data.resources.cfnResources.cfnGraphqlApi.attrGraphQlUrl);
312
317
  contentActionsLambda.addToRolePolicy(new PolicyStatement({
313
318
  actions: ["appsync:GraphQL"],
@@ -30,6 +30,7 @@ import { defineSiteData } from "./data/resource";
30
30
  import { resolvePlugins } from "./plugins/registry";
31
31
  import { wirePlugins } from "./plugins/wire";
32
32
  import { assignmentAction } from "./functions/assignment-action/resource";
33
+ import { scopeAssignmentDataAccess } from "./functions/assignment-action/data-access";
33
34
  import { categoryAction } from "./functions/category-action/resource";
34
35
  import { ConsoleChatResponderStack } from "./functions/console-chat-responder/resource";
35
36
  import { contentActions, setSiteFilesForContentActionsBundle } from "./functions/content-actions/resource";
@@ -387,10 +388,20 @@ export function defineSiteBackend(papyrusSite: PapyrusSite) {
387
388
  }
388
389
  grantCorporaRead(backend.knowledgeQuery.resources.lambda as LambdaFunction);
389
390
  grantNewsroomReadWrite(backend.assignmentAction.resources.lambda as LambdaFunction);
391
+ scopeAssignmentDataAccess(
392
+ backend.assignmentAction.resources.lambda as LambdaFunction,
393
+ backend.data.resources.graphqlApi.arn,
394
+ );
390
395
  grantNewsroomReadWrite(backend.categoryAction.resources.lambda as LambdaFunction);
391
396
  grantNewsroomReadWrite(backend.newsroomSummary.resources.lambda as LambdaFunction);
392
397
  const contentActionsLambda = backend.contentActions.resources.lambda as LambdaFunction;
393
398
  grantNewsroomReadWriteDelete(contentActionsLambda);
399
+ // AppSync validates the token; pending intake additionally binds its actor
400
+ // and publication to this deployment's pool and existing API endpoint.
401
+ contentActionsLambda.addEnvironment(
402
+ "PAPYRUS_USER_POOL_ISSUER",
403
+ `https://cognito-idp.${Stack.of(contentActionsLambda).region}.amazonaws.com/${backend.auth.resources.userPool.userPoolId}`,
404
+ );
394
405
  contentActionsLambda.addEnvironment(
395
406
  "PAPYRUS_GRAPHQL_ENDPOINT",
396
407
  backend.data.resources.cfnResources.cfnGraphqlApi.attrGraphQlUrl,
package/app/globals.css CHANGED
@@ -3749,95 +3749,6 @@ img {
3749
3749
  gap: 0;
3750
3750
  }
3751
3751
 
3752
- .newsroom-deep-section {
3753
- border-top: 2px solid var(--rule);
3754
- display: grid;
3755
- grid-template-columns: repeat(var(--news-desk-page-columns), minmax(0, 1fr));
3756
- margin-top: calc(var(--paper-rhythm) * 2);
3757
- min-width: 0;
3758
- row-gap: calc(var(--paper-rhythm) * 1.5);
3759
- }
3760
-
3761
- .newsroom-deep-section__header {
3762
- border-bottom: 1px solid rgb(var(--rule-rgb) / 0.52);
3763
- display: grid;
3764
- grid-column: 1 / -1;
3765
- gap: calc(var(--paper-rhythm) * 0.5);
3766
- padding: calc(var(--paper-rhythm) * 0.75) 0;
3767
- }
3768
-
3769
- .newsroom-deep-section__header h2,
3770
- .newsroom-deep-section > h2 {
3771
- color: rgb(var(--ink-solid-rgb) / var(--ink-display-alpha));
3772
- font-size: 3rem;
3773
- font-weight: 900;
3774
- letter-spacing: 0;
3775
- line-height: 0.92;
3776
- margin: 0;
3777
- }
3778
-
3779
- .newsroom-deep-section__header a {
3780
- color: var(--muted);
3781
- font-family: Arial, Helvetica, sans-serif;
3782
- font-size: 0.66rem;
3783
- font-weight: 800;
3784
- letter-spacing: 0.08em;
3785
- text-transform: uppercase;
3786
- }
3787
-
3788
- .newsroom-deep-section__header-actions {
3789
- align-items: center;
3790
- display: flex;
3791
- flex-wrap: wrap;
3792
- gap: var(--paper-rhythm);
3793
- }
3794
-
3795
- .newsroom-deep-section__header-actions button {
3796
- background: transparent;
3797
- border: 1px solid rgb(var(--rule-rgb) / 0.62);
3798
- color: rgb(var(--ink-solid-rgb) / var(--ink-display-alpha));
3799
- cursor: pointer;
3800
- font-family: Arial, Helvetica, sans-serif;
3801
- font-size: 0.66rem;
3802
- font-weight: 800;
3803
- letter-spacing: 0.08em;
3804
- min-height: var(--paper-rhythm);
3805
- padding: 0 calc(var(--paper-rhythm) * 0.5);
3806
- text-transform: uppercase;
3807
- }
3808
-
3809
- .newsroom-deep-section__header-actions button:disabled {
3810
- color: var(--muted);
3811
- cursor: not-allowed;
3812
- }
3813
-
3814
- .newsroom-deep-section__body {
3815
- column-gap: var(--news-desk-column-gap);
3816
- display: grid;
3817
- grid-column: 1 / -1;
3818
- grid-template-columns: repeat(var(--news-desk-page-columns), minmax(0, 1fr));
3819
- row-gap: calc(var(--paper-rhythm) * 1.5);
3820
- }
3821
-
3822
- .newsroom-deep-section__field {
3823
- border-top: 1px solid rgb(var(--rule-rgb) / 0.42);
3824
- grid-column: span 2;
3825
- min-width: 0;
3826
- padding-top: calc(var(--paper-rhythm) * 0.5);
3827
- }
3828
-
3829
- .newsroom-deep-section__field--lead {
3830
- grid-column: span 3;
3831
- }
3832
-
3833
- .newsroom-deep-section__field p:not(.story-label),
3834
- .newsroom-deep-section > p:not(.story-label) {
3835
- color: var(--muted-strong);
3836
- font-size: 1.05rem;
3837
- line-height: var(--news-desk-text-leading, var(--paper-rhythm));
3838
- margin: calc(var(--paper-rhythm) * 0.5) 0 0;
3839
- }
3840
-
3841
3752
  .newsroom-recent-panel__header {
3842
3753
  border-bottom: 1px solid rgb(var(--rule-rgb) / 0.42);
3843
3754
  min-height: calc(var(--paper-rhythm, 19px) * 3);
@@ -8825,10 +8736,6 @@ img {
8825
8736
  grid-template-columns: repeat(3, minmax(0, 1fr));
8826
8737
  }
8827
8738
 
8828
- .newsroom-deep-section__field,
8829
- .newsroom-deep-section__field--lead {
8830
- grid-column: 1 / -1;
8831
- }
8832
8739
  }
8833
8740
 
8834
8741
  @media (max-width: 785px) {
@@ -10263,85 +10170,3 @@ img {
10263
10170
  }
10264
10171
  }
10265
10172
 
10266
- /* Ops app chrome: sans-only content surfaces; moss primary on navigation/actions */
10267
- [data-newsroom-chrome="app"][data-newsroom-ops-shell="true"] {
10268
- font-family: var(--font-sans), ui-sans-serif, system-ui, sans-serif;
10269
- }
10270
-
10271
- [data-newsroom-chrome="app"][data-newsroom-ops-shell="true"] h1,
10272
- [data-newsroom-chrome="app"][data-newsroom-ops-shell="true"] h2,
10273
- [data-newsroom-chrome="app"][data-newsroom-ops-shell="true"] h3,
10274
- [data-newsroom-chrome="app"][data-newsroom-ops-shell="true"] .story-label {
10275
- font-family: var(--font-sans), ui-sans-serif, system-ui, sans-serif;
10276
- }
10277
-
10278
- [data-newsroom-chrome="app"] [data-category-steering] {
10279
- font-family: var(--font-sans), ui-sans-serif, system-ui, sans-serif;
10280
- }
10281
-
10282
- [data-theme-pack="pilobol-us"] [data-newsroom-ops-shell="true"] a:focus-visible,
10283
- [data-theme-pack="pilobol-us"] [data-newsroom-ops-shell="true"] button:focus-visible {
10284
- --tw-ring-color: var(--theme-moss);
10285
- }
10286
-
10287
- /* List-row selection in ops chrome: tint wash + foreground copy; never invert to primary-foreground. */
10288
- [data-newsroom-chrome="app"] [data-newsroom-list-row][data-selected="true"],
10289
- [data-newsroom-chrome="app"] [data-newsroom-list-row][aria-current="true"],
10290
- [data-newsroom-chrome="app"] .newsroom-card[data-active="true"],
10291
- [data-newsroom-chrome="app"] .news-desk-data-grid__row[data-active="true"],
10292
- [data-newsroom-chrome="app"] .news-desk-topic-root-button[data-selected="true"],
10293
- [data-newsroom-chrome="app"] .news-desk-topic-focus-row[data-selected="true"],
10294
- [data-newsroom-chrome="app"] .news-desk-topic-focus-button[data-selected="true"],
10295
- [data-newsroom-chrome="app"] .news-desk-desk-card[data-selected="true"] {
10296
- background: color-mix(in srgb, var(--primary) 10%, transparent);
10297
- color: var(--foreground);
10298
- }
10299
-
10300
- [data-newsroom-chrome="app"] .newsroom-card[data-active="true"] .newsroom-card__title,
10301
- [data-newsroom-chrome="app"] .newsroom-card[data-active="true"] .newsroom-card__body,
10302
- [data-newsroom-chrome="app"] .newsroom-card[data-active="true"] .newsroom-card__kicker,
10303
- [data-newsroom-chrome="app"] .newsroom-card[data-active="true"] .newsroom-card__meta,
10304
- [data-newsroom-chrome="app"] .newsroom-card[data-active="true"] .newsroom-card__stamp,
10305
- [data-newsroom-chrome="app"] .news-desk-data-grid__row[data-active="true"] strong,
10306
- [data-newsroom-chrome="app"] .news-desk-topic-root-button[data-selected="true"] strong,
10307
- [data-newsroom-chrome="app"] .news-desk-topic-focus-button[data-selected="true"] strong {
10308
- color: var(--foreground);
10309
- }
10310
-
10311
- [data-newsroom-chrome="app"] [role="tab"][aria-selected="true"] {
10312
- background: color-mix(in srgb, var(--primary) 10%, transparent);
10313
- color: var(--foreground);
10314
- }
10315
-
10316
- @media (prefers-color-scheme: dark) {
10317
- :root:not([data-papyrus-theme="light"]):not(.light-theme) [data-newsroom-chrome="app"] [data-newsroom-list-row][data-selected="true"],
10318
- :root:not([data-papyrus-theme="light"]):not(.light-theme) [data-newsroom-chrome="app"] [data-newsroom-list-row][aria-current="true"],
10319
- :root:not([data-papyrus-theme="light"]):not(.light-theme) [data-newsroom-chrome="app"] .newsroom-card[data-active="true"],
10320
- :root:not([data-papyrus-theme="light"]):not(.light-theme) [data-newsroom-chrome="app"] .news-desk-data-grid__row[data-active="true"],
10321
- :root:not([data-papyrus-theme="light"]):not(.light-theme) [data-newsroom-chrome="app"] .news-desk-topic-root-button[data-selected="true"],
10322
- :root:not([data-papyrus-theme="light"]):not(.light-theme) [data-newsroom-chrome="app"] .news-desk-topic-focus-row[data-selected="true"],
10323
- :root:not([data-papyrus-theme="light"]):not(.light-theme) [data-newsroom-chrome="app"] .news-desk-topic-focus-button[data-selected="true"],
10324
- :root:not([data-papyrus-theme="light"]):not(.light-theme) [data-newsroom-chrome="app"] .news-desk-desk-card[data-selected="true"] {
10325
- background: color-mix(in srgb, var(--foreground) 8%, transparent);
10326
- }
10327
- }
10328
-
10329
- :root.dark-theme [data-newsroom-chrome="app"] [data-newsroom-list-row][data-selected="true"],
10330
- :root[data-papyrus-theme="dark"] [data-newsroom-chrome="app"] [data-newsroom-list-row][data-selected="true"],
10331
- :root.dark-theme [data-newsroom-chrome="app"] [data-newsroom-list-row][aria-current="true"],
10332
- :root[data-papyrus-theme="dark"] [data-newsroom-chrome="app"] [data-newsroom-list-row][aria-current="true"],
10333
- :root.dark-theme [data-newsroom-chrome="app"] .newsroom-card[data-active="true"],
10334
- :root[data-papyrus-theme="dark"] [data-newsroom-chrome="app"] .newsroom-card[data-active="true"],
10335
- :root.dark-theme [data-newsroom-chrome="app"] .news-desk-data-grid__row[data-active="true"],
10336
- :root[data-papyrus-theme="dark"] [data-newsroom-chrome="app"] .news-desk-data-grid__row[data-active="true"],
10337
- :root.dark-theme [data-newsroom-chrome="app"] .news-desk-topic-root-button[data-selected="true"],
10338
- :root[data-papyrus-theme="dark"] [data-newsroom-chrome="app"] .news-desk-topic-root-button[data-selected="true"],
10339
- :root.dark-theme [data-newsroom-chrome="app"] .news-desk-topic-focus-row[data-selected="true"],
10340
- :root[data-papyrus-theme="dark"] [data-newsroom-chrome="app"] .news-desk-topic-focus-row[data-selected="true"],
10341
- :root.dark-theme [data-newsroom-chrome="app"] .news-desk-topic-focus-button[data-selected="true"],
10342
- :root[data-papyrus-theme="dark"] [data-newsroom-chrome="app"] .news-desk-topic-focus-button[data-selected="true"],
10343
- :root.dark-theme [data-newsroom-chrome="app"] .news-desk-desk-card[data-selected="true"],
10344
- :root[data-papyrus-theme="dark"] [data-newsroom-chrome="app"] .news-desk-desk-card[data-selected="true"] {
10345
- background: color-mix(in srgb, var(--foreground) 8%, transparent);
10346
- }
10347
-
@@ -1,4 +1,3 @@
1
- import { resolveActiveSiteBrand } from "../../../../lib/site-brand-tenant";
2
1
  import { notFound, redirect } from "next/navigation";
3
2
  import { toPublicNewsroomPath } from "../../../../lib/newsroom-base-path";
4
3
  import { NewsDeskPage } from "../../../../components/news-desk-page";
@@ -42,11 +41,6 @@ export default async function NewsDeskNestedSectionPage({ params, searchParams }
42
41
  if (section === "users") redirect(toPublicNewsroomPath("/newsroom/administration/users"));
43
42
  if (section === "doctrine") redirect(toPublicNewsroomPath("/newsroom/administration/policies"));
44
43
  if (section === "administration" && selection[0] === "analysis") redirect(toPublicNewsroomPath("/newsroom/assignments"));
45
- if (section === "desks" && resolveActiveSiteBrand().newsroomLayout !== "organizer") {
46
- const category = selection[0] ? decodeURIComponent(selection[0]) : null;
47
- if (category) redirect(toPublicNewsroomPath(`/newsroom/topics?category=${encodeURIComponent(category)}`));
48
- redirect(toPublicNewsroomPath("/newsroom/topics"));
49
- }
50
44
  if (!NEWS_DESK_ROUTE_SECTIONS.has(section as NewsDeskTab)) notFound();
51
45
  return <NewsDeskPage section={section} selectionPath={selection} searchParams={searchParams} />;
52
46
  }
@@ -1,4 +1,3 @@
1
- import { resolveActiveSiteBrand } from "../../../lib/site-brand-tenant";
2
1
  import { notFound, redirect } from "next/navigation";
3
2
  import { toPublicNewsroomPath } from "../../../lib/newsroom-base-path";
4
3
  import { contentItemBoardPathSegment } from "../../../lib/newsroom-board";
@@ -46,10 +45,9 @@ export default async function NewsDeskSectionPage({ params, searchParams }: News
46
45
  if (section === "work") redirect(toPublicNewsroomPath(`/newsroom/${contentItemBoardPathSegment()}`));
47
46
  if (section === "users") redirect(toPublicNewsroomPath("/newsroom/administration/users"));
48
47
  if (section === "doctrine") redirect(toPublicNewsroomPath("/newsroom/administration/policies"));
49
- if (section === "desks" && resolveActiveSiteBrand().newsroomLayout !== "organizer") redirect(toPublicNewsroomPath("/newsroom/topics"));
50
- if (section === contentItemBoardPathSegment() && resolveActiveSiteBrand().newsroomLayout === "organizer") return <NewsroomBoardView subject="contentItem" />;
48
+ if (section === contentItemBoardPathSegment()) return <NewsroomBoardView subject="contentItem" />;
51
49
  if (!NEWS_DESK_ROUTE_SECTIONS.has(section as NewsDeskTab)) notFound();
52
- if (section === "assignments" && resolveActiveSiteBrand().newsroomLayout === "organizer") {
50
+ if (section === "assignments") {
53
51
  const resolved = await searchParams;
54
52
  if (!resolved?.assignment && resolved?.demo !== "1") return <NewsroomBoardView subject="assignment" />;
55
53
  }
@@ -2,7 +2,6 @@ import { redirect } from "next/navigation";
2
2
  import { contentItemBoardPathSegment } from "../../../lib/newsroom-board";
3
3
  import { toPublicNewsroomPath } from "../../../lib/newsroom-base-path";
4
4
  import { NewsroomBoardView } from "../../../components/newsroom-board-view";
5
- import { resolveActiveSiteBrand } from "../../../lib/site-brand-tenant";
6
5
  import { NewsroomArticlesView } from "../../../components/newsroom-articles-view";
7
6
 
8
7
  export const dynamic = "force-dynamic";
@@ -14,7 +13,7 @@ type NewsroomArticlesPageProps = {
14
13
  export default async function NewsroomArticlesPage({ searchParams }: NewsroomArticlesPageProps) {
15
14
  const resolved = await searchParams;
16
15
  const demoValue = Array.isArray(resolved?.demo) ? resolved?.demo[0] : resolved?.demo;
17
- if (resolveActiveSiteBrand().newsroomLayout === "organizer" && demoValue !== "1") {
16
+ if (demoValue !== "1") {
18
17
  const boardPathSegment = contentItemBoardPathSegment();
19
18
  if (boardPathSegment !== "articles") redirect(toPublicNewsroomPath(`/newsroom/${boardPathSegment}`));
20
19
  return <NewsroomBoardView subject="contentItem" />;
@@ -1,20 +1,16 @@
1
1
  import { notFound } from "next/navigation";
2
- import { resolveActiveSiteBrand } from "../../../../lib/site-brand-tenant";
3
2
  import { NewsroomBoardView } from "../../../../components/newsroom-board-view";
4
- import { NewsDeskPage } from "../../../../components/news-desk-page";
5
3
 
6
4
  export const dynamic = "force-dynamic";
7
5
 
8
6
  type NewsroomDeepSectionPageProps = {
9
7
  params: Promise<{ sectionId: string }>;
10
- searchParams?: Promise<Record<string, string | string[] | undefined>>;
11
8
  };
12
9
 
13
- export default async function NewsroomDeepSectionPage({ params, searchParams }: NewsroomDeepSectionPageProps) {
10
+ export default async function NewsroomDeepSectionPage({ params }: NewsroomDeepSectionPageProps) {
14
11
  const { sectionId } = await params;
15
12
  const normalizedSectionId = decodeURIComponent(sectionId ?? "").trim();
16
13
  if (!normalizedSectionId) notFound();
17
14
 
18
- if (resolveActiveSiteBrand().newsroomLayout === "organizer") return <NewsroomBoardView subject="desk" deskId={normalizedSectionId} />;
19
- return <NewsDeskPage sectionPageId={normalizedSectionId} searchParams={searchParams} />;
15
+ return <NewsroomBoardView subject="desk" deskId={normalizedSectionId} />;
20
16
  }
@@ -12,6 +12,7 @@ import fs from "node:fs";
12
12
  import { spawnSync } from "node:child_process";
13
13
  import path from "node:path";
14
14
  import { createRequire } from "node:module";
15
+ import { resolveCdkEnvironment } from "../src/cdk-environment.mjs";
15
16
 
16
17
  const USAGE = [
17
18
  "Usage: papyrus-infra synth --site infra/site.json [--out cdk.out] [--account A] [--region R]",
@@ -26,6 +27,14 @@ const opt = (name, fallback) => {
26
27
  const i = args.indexOf(`--${name}`);
27
28
  return i >= 0 ? args[i + 1] : fallback;
28
29
  };
30
+ const resolveEnvironmentOrExit = () => {
31
+ try {
32
+ return resolveCdkEnvironment({ explicitAccount: opt("account"), explicitRegion: opt("region") });
33
+ } catch (error) {
34
+ console.error(`papyrus-infra: ${error instanceof Error ? error.message : error}`);
35
+ process.exit(1);
36
+ }
37
+ };
29
38
  const command = args[0];
30
39
  if (command !== "synth" && command !== "print-buildspec" && command !== "deploy" && command !== "deploy-edge") {
31
40
  console.error(USAGE);
@@ -85,7 +94,7 @@ if (accountStack !== undefined) {
85
94
  const { App } = createRequire(path.join(process.cwd(), "noop.js"))("aws-cdk-lib");
86
95
  const app = new App({ outdir: path.resolve(opt("out", "cdk.out")) });
87
96
  new GithubOidcProviderStack(app, "GithubOidcProviderStack", {
88
- env: { account: opt("account", process.env.CDK_DEFAULT_ACCOUNT ?? "335163751677"), region: opt("region", process.env.CDK_DEFAULT_REGION ?? "us-east-1") },
97
+ env: resolveEnvironmentOrExit(),
89
98
  stackName: "github-oidc-provider",
90
99
  });
91
100
  app.synth();
@@ -168,7 +177,7 @@ try {
168
177
  const { App } = createRequire(path.join(process.cwd(), "noop.js"))("aws-cdk-lib");
169
178
  const app = new App({ outdir: path.resolve(opt("out", "cdk.out")) });
170
179
  new AmplifyAppShellStack(app, `AmplifyAppShell-${config.siteId}`, config, {
171
- env: { account: opt("account", process.env.CDK_DEFAULT_ACCOUNT ?? "335163751677"), region: opt("region", process.env.CDK_DEFAULT_REGION ?? "us-east-1") },
180
+ env: resolveEnvironmentOrExit(),
172
181
  stackName: resolveStackName(config),
173
182
  });
174
183
  app.synth();