@anthusai/papyrus 2.0.0-next.2 → 2.0.0-next.21

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 (103) hide show
  1. package/amplify/data/resource.js +15 -0
  2. package/amplify/data/resource.ts +17 -0
  3. package/amplify/data/schema.js +20 -0
  4. package/amplify/data/schema.ts +22 -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 +22 -0
  8. package/amplify/functions/editorial-checks/handler.py +14 -0
  9. package/amplify/functions/editorial-checks/requirements.txt +1 -0
  10. package/amplify/functions/editorial-checks/resource.js +43 -0
  11. package/amplify/functions/editorial-checks/resource.ts +60 -0
  12. package/amplify/functions/editorial-checks/schema.js +92 -0
  13. package/amplify/functions/editorial-checks/schema.ts +94 -0
  14. package/amplify/functions/editorial-checks/wire.js +49 -0
  15. package/amplify/functions/editorial-checks/wire.ts +57 -0
  16. package/amplify/functions/model-attachment-upload/handler.ts +1 -0
  17. package/amplify/functions/monitoring-view/handler.py +11 -0
  18. package/amplify/functions/monitoring-view/resource.js +24 -0
  19. package/amplify/functions/monitoring-view/resource.ts +34 -0
  20. package/amplify/functions/monitoring-view/schema.js +16 -0
  21. package/amplify/functions/monitoring-view/schema.ts +18 -0
  22. package/amplify/functions/monitoring-view/wire.js +37 -0
  23. package/amplify/functions/monitoring-view/wire.ts +47 -0
  24. package/amplify/functions/public-forms/core.js +247 -0
  25. package/amplify/functions/public-forms/core.ts +310 -0
  26. package/amplify/functions/public-forms/handler.ts +41 -0
  27. package/amplify/functions/public-forms/origins.js +35 -0
  28. package/amplify/functions/public-forms/origins.ts +43 -0
  29. package/amplify/functions/public-forms/resource.js +9 -0
  30. package/amplify/functions/public-forms/resource.ts +10 -0
  31. package/amplify/functions/public-forms/wire.js +25 -0
  32. package/amplify/functions/public-forms/wire.ts +32 -0
  33. package/amplify/functions/shared/python-bundle.js +20 -14
  34. package/amplify/functions/shared/python-bundle.ts +25 -18
  35. package/amplify/publication/redirect-and-index.js +83 -0
  36. package/amplify/publication/redirect-rules.js +61 -0
  37. package/amplify/publication/redirect-rules.ts +79 -0
  38. package/amplify/publication/s3-projection.js +5 -1
  39. package/amplify/publication/s3-projection.ts +7 -1
  40. package/amplify/site-backend-config.ts +10 -0
  41. package/amplify/site-backend.js +31 -0
  42. package/amplify/site-backend.ts +38 -0
  43. package/app/api/newsroom/curation/context/route.ts +9 -0
  44. package/app/api/newsroom/curation/priming/route.ts +9 -0
  45. package/app/api/newsroom/curation/publication/route.ts +9 -0
  46. package/bin/papyrus-infra.mjs +20 -1
  47. package/components/editorial-checks-admin-panel.tsx +347 -0
  48. package/components/editorial-finding-card.tsx +162 -0
  49. package/components/editorial-findings-panel.tsx +91 -0
  50. package/components/editorial-preview-popover.tsx +103 -0
  51. package/components/markus-body-editor.tsx +213 -0
  52. package/components/markus-ir-preview.tsx +147 -6
  53. package/components/monitoring-overview-view.tsx +240 -0
  54. package/components/monitoring-panel.tsx +40 -0
  55. package/components/newsroom-article-editor.tsx +136 -11
  56. package/components/newsroom-board-view.tsx +6 -7
  57. package/components/newsroom-curation-bootstrap.tsx +45 -0
  58. package/components/newsroom-ops-shell.tsx +7 -3
  59. package/components/newsroom-organizer.css +74 -61
  60. package/components/newsroom-references-view.tsx +14 -14
  61. package/components/newsroom-theme-fonts/broadsheet-green.css +10 -0
  62. package/components/newsroom-theme-fonts/broadsheet-green.tsx +6 -0
  63. package/components/newsroom-theme-fonts/newspaper-gothic.css +9 -0
  64. package/components/newsroom-theme-fonts/newspaper-gothic.tsx +6 -0
  65. package/components/newsroom-theme-fonts/night-desk.css +10 -0
  66. package/components/newsroom-theme-fonts/night-desk.tsx +6 -0
  67. package/components/newsroom-theme-fonts/refined-newsprint.css +11 -0
  68. package/components/newsroom-theme-fonts/refined-newsprint.tsx +6 -0
  69. package/components/newsroom-theme.css +39 -0
  70. package/components/newsroom-theme.tsx +33 -0
  71. package/components/publication-cyclotron-panel.tsx +10 -10
  72. package/components/reference-add-entry.tsx +75 -0
  73. package/components/reference-curation-controls.tsx +30 -21
  74. package/components/reference-cyclotron-priming.tsx +4 -4
  75. package/components/reference-cyclotron-suggestion.tsx +1 -1
  76. package/components/reference-priming.tsx +14 -10
  77. package/components/reference-section-suggestion.tsx +1 -1
  78. package/components/topic-steering-workspace.tsx +27 -2
  79. package/components/use-editorial-checks.ts +133 -0
  80. package/lib/category-repository.ts +11 -9
  81. package/lib/curation-routes.ts +342 -0
  82. package/lib/editorial-checks-backend.ts +16 -0
  83. package/lib/editorial-checks-client.ts +194 -0
  84. package/lib/editorial-checks-demo.ts +147 -0
  85. package/lib/editorial-checks-settings.ts +27 -0
  86. package/lib/editorial-checks.ts +171 -0
  87. package/lib/editorial-preview.ts +228 -0
  88. package/lib/monitoring-client.ts +29 -0
  89. package/lib/monitoring-overview-fixture.ts +51 -0
  90. package/lib/monitoring-overview.ts +144 -0
  91. package/lib/newsroom-board.ts +27 -2
  92. package/lib/relevance-status.ts +2 -2
  93. package/lib/site-brand-tenant.ts +11 -6
  94. package/lib/site-brand.ts +23 -3
  95. package/package.json +47 -3
  96. package/routes.manifest.json +34 -1
  97. package/components/newsroom-fonts/playfair-display-700.ttf +0 -0
  98. package/components/newsroom-fonts/playfair-display-900.ttf +0 -0
  99. package/components/newsroom-fonts/playfair-display-OFL.txt +0 -93
  100. package/components/newsroom-fonts/plus-jakarta-sans-400.ttf +0 -0
  101. package/components/newsroom-fonts/plus-jakarta-sans-600.ttf +0 -0
  102. package/components/newsroom-fonts/plus-jakarta-sans-OFL.txt +0 -93
  103. package/components/newsroom-newsprint-board.css +0 -7
@@ -6,6 +6,7 @@ import { knowledgeQuery } from "../functions/knowledge-query/resource.js";
6
6
  import { manageUserRole } from "../functions/manage-user-role/resource.js";
7
7
  import { modelAttachmentUpload } from "../functions/model-attachment-upload/resource.js";
8
8
  import { newsroomSummary } from "../functions/newsroom-summary/resource.js";
9
+ import { publicForms } from "../functions/public-forms/resource.js";
9
10
  import { procedureAction } from "../functions/procedure-action/resource.js";
10
11
  import { readerSettings } from "../functions/reader-settings/resource.js";
11
12
  import { emailSubmissionProcessor } from "../functions/email-submission-processor/resource.js";
@@ -589,6 +590,12 @@ const schema = a.schema({
589
590
  .returns(a.json())
590
591
  .authorization((allow) => [allow.groups(contentWriteGroups)])
591
592
  .handler(a.handler.function(contentActions)),
593
+ intakePendingReferences: a
594
+ .mutation()
595
+ .arguments({ input: a.json().required() })
596
+ .returns(a.json())
597
+ .authorization((allow) => [allow.groups(contentWriteGroups)])
598
+ .handler(a.handler.function(contentActions)),
592
599
  saveItemDraft: a
593
600
  .mutation()
594
601
  .arguments({ input: a.json().required() })
@@ -601,6 +608,12 @@ const schema = a.schema({
601
608
  .returns(a.json())
602
609
  .authorization((allow) => [allow.groups(contentWriteGroups)])
603
610
  .handler(a.handler.function(contentActions)),
611
+ moveStoryStage: a
612
+ .mutation()
613
+ .arguments({ input: a.json().required() })
614
+ .returns(a.json())
615
+ .authorization((allow) => [allow.groups(contentWriteGroups)])
616
+ .handler(a.handler.function(contentActions)),
604
617
  unpublishItem: a
605
618
  .mutation()
606
619
  .arguments({ input: a.json().required() })
@@ -2146,12 +2159,14 @@ const schema = a.schema({
2146
2159
  allow.groups(contentWriteGroups),
2147
2160
  ]),
2148
2161
  }).authorization((allow) => [
2162
+ allow.resource(assignmentAction).to(["query", "mutate"]),
2149
2163
  allow.resource(categoryAction),
2150
2164
  allow.resource(contentActions),
2151
2165
  allow.resource(manageUserRole),
2152
2166
  allow.resource(modelAttachmentUpload),
2153
2167
  allow.resource(newsroomSummary),
2154
2168
  allow.resource(procedureAction),
2169
+ allow.resource(publicForms).to(["mutate"]),
2155
2170
  allow.resource(sesInboundReceive),
2156
2171
  allow.resource(emailSubmissionProcessor),
2157
2172
  allow.resource(slackEvents),
@@ -6,6 +6,7 @@ import { knowledgeQuery } from "../functions/knowledge-query/resource";
6
6
  import { manageUserRole } from "../functions/manage-user-role/resource";
7
7
  import { modelAttachmentUpload } from "../functions/model-attachment-upload/resource";
8
8
  import { newsroomSummary } from "../functions/newsroom-summary/resource";
9
+ import { publicForms } from "../functions/public-forms/resource";
9
10
  import { procedureAction } from "../functions/procedure-action/resource";
10
11
  import { readerSettings } from "../functions/reader-settings/resource";
11
12
  import { emailSubmissionProcessor } from "../functions/email-submission-processor/resource";
@@ -641,6 +642,13 @@ const schema = a.schema({
641
642
  .authorization((allow) => [allow.groups(contentWriteGroups)])
642
643
  .handler(a.handler.function(contentActions)),
643
644
 
645
+ intakePendingReferences: a
646
+ .mutation()
647
+ .arguments({ input: a.json().required() })
648
+ .returns(a.json())
649
+ .authorization((allow) => [allow.groups(contentWriteGroups)])
650
+ .handler(a.handler.function(contentActions)),
651
+
644
652
  saveItemDraft: a
645
653
  .mutation()
646
654
  .arguments({ input: a.json().required() })
@@ -655,6 +663,13 @@ const schema = a.schema({
655
663
  .authorization((allow) => [allow.groups(contentWriteGroups)])
656
664
  .handler(a.handler.function(contentActions)),
657
665
 
666
+ moveStoryStage: a
667
+ .mutation()
668
+ .arguments({ input: a.json().required() })
669
+ .returns(a.json())
670
+ .authorization((allow) => [allow.groups(contentWriteGroups)])
671
+ .handler(a.handler.function(contentActions)),
672
+
658
673
  unpublishItem: a
659
674
  .mutation()
660
675
  .arguments({ input: a.json().required() })
@@ -2271,12 +2286,14 @@ const schema = a.schema({
2271
2286
  allow.groups(contentWriteGroups),
2272
2287
  ]),
2273
2288
  }).authorization((allow) => [
2289
+ allow.resource(assignmentAction).to(["query", "mutate"]),
2274
2290
  allow.resource(categoryAction),
2275
2291
  allow.resource(contentActions),
2276
2292
  allow.resource(manageUserRole),
2277
2293
  allow.resource(modelAttachmentUpload),
2278
2294
  allow.resource(newsroomSummary),
2279
2295
  allow.resource(procedureAction),
2296
+ allow.resource(publicForms).to(["mutate"]),
2280
2297
  allow.resource(sesInboundReceive),
2281
2298
  allow.resource(emailSubmissionProcessor),
2282
2299
  allow.resource(slackEvents),
@@ -1,11 +1,14 @@
1
1
  import { a } from "@aws-amplify/backend";
2
2
  import { assignmentAction } from "../functions/assignment-action/resource.js";
3
3
  import { categoryAction } from "../functions/category-action/resource.js";
4
+ import { editorialChecksSchemaDefinitions } from "../functions/editorial-checks/schema.js";
5
+ import { monitoringViewSchemaDefinitions } from "../functions/monitoring-view/schema.js";
4
6
  import { contentActions } from "../functions/content-actions/resource.js";
5
7
  import { knowledgeQuery } from "../functions/knowledge-query/resource.js";
6
8
  import { manageUserRole } from "../functions/manage-user-role/resource.js";
7
9
  import { modelAttachmentUpload } from "../functions/model-attachment-upload/resource.js";
8
10
  import { newsroomSummary } from "../functions/newsroom-summary/resource.js";
11
+ import { publicForms } from "../functions/public-forms/resource.js";
9
12
  import { procedureAction } from "../functions/procedure-action/resource.js";
10
13
  import { readerSettings } from "../functions/reader-settings/resource.js";
11
14
  const authoringOperations = [
@@ -496,6 +499,12 @@ const baseDefinitions = {
496
499
  .returns(a.json())
497
500
  .authorization((allow) => [allow.groups(contentWriteGroups)])
498
501
  .handler(a.handler.function(contentActions)),
502
+ intakePendingReferences: a
503
+ .mutation()
504
+ .arguments({ input: a.json().required() })
505
+ .returns(a.json())
506
+ .authorization((allow) => [allow.groups(contentWriteGroups)])
507
+ .handler(a.handler.function(contentActions)),
499
508
  saveItemDraft: a
500
509
  .mutation()
501
510
  .arguments({ input: a.json().required() })
@@ -508,6 +517,12 @@ const baseDefinitions = {
508
517
  .returns(a.json())
509
518
  .authorization((allow) => [allow.groups(contentWriteGroups)])
510
519
  .handler(a.handler.function(contentActions)),
520
+ moveStoryStage: a
521
+ .mutation()
522
+ .arguments({ input: a.json().required() })
523
+ .returns(a.json())
524
+ .authorization((allow) => [allow.groups(contentWriteGroups)])
525
+ .handler(a.handler.function(contentActions)),
511
526
  unpublishItem: a
512
527
  .mutation()
513
528
  .arguments({ input: a.json().required() })
@@ -1987,18 +2002,23 @@ const baseDefinitions = {
1987
2002
  allow.guest().to(["read"]),
1988
2003
  allow.groups(contentWriteGroups),
1989
2004
  ]),
2005
+ ...editorialChecksSchemaDefinitions,
2006
+ ...monitoringViewSchemaDefinitions,
1990
2007
  };
1991
2008
  export const schema = a.schema(baseDefinitions).authorization((allow) => [
2009
+ allow.resource(assignmentAction).to(["query", "mutate"]),
1992
2010
  allow.resource(categoryAction),
1993
2011
  allow.resource(contentActions),
1994
2012
  allow.resource(manageUserRole),
1995
2013
  allow.resource(modelAttachmentUpload),
1996
2014
  allow.resource(newsroomSummary),
1997
2015
  allow.resource(procedureAction),
2016
+ allow.resource(publicForms).to(["mutate"]),
1998
2017
  ]);
1999
2018
  /** The deployed schema of a site that enables plugins: the base definitions plus what each plugin contributes (docs/plugins.md). */
2000
2019
  export function schemaWithPlugins(pluginDefinitions) {
2001
2020
  return a.schema({ ...baseDefinitions, ...pluginDefinitions }).authorization((allow) => [
2021
+ allow.resource(assignmentAction).to(["query", "mutate"]),
2002
2022
  allow.resource(categoryAction),
2003
2023
  allow.resource(contentActions),
2004
2024
  allow.resource(manageUserRole),
@@ -1,11 +1,14 @@
1
1
  import { type ClientSchema, a } from "@aws-amplify/backend";
2
2
  import { assignmentAction } from "../functions/assignment-action/resource";
3
3
  import { categoryAction } from "../functions/category-action/resource";
4
+ import { editorialChecksSchemaDefinitions } from "../functions/editorial-checks/schema";
5
+ import { monitoringViewSchemaDefinitions } from "../functions/monitoring-view/schema";
4
6
  import { contentActions } from "../functions/content-actions/resource";
5
7
  import { knowledgeQuery } from "../functions/knowledge-query/resource";
6
8
  import { manageUserRole } from "../functions/manage-user-role/resource";
7
9
  import { modelAttachmentUpload } from "../functions/model-attachment-upload/resource";
8
10
  import { newsroomSummary } from "../functions/newsroom-summary/resource";
11
+ import { publicForms } from "../functions/public-forms/resource";
9
12
  import { procedureAction } from "../functions/procedure-action/resource";
10
13
  import { readerSettings } from "../functions/reader-settings/resource";
11
14
 
@@ -542,6 +545,13 @@ const baseDefinitions = {
542
545
  .authorization((allow) => [allow.groups(contentWriteGroups)])
543
546
  .handler(a.handler.function(contentActions)),
544
547
 
548
+ intakePendingReferences: a
549
+ .mutation()
550
+ .arguments({ input: a.json().required() })
551
+ .returns(a.json())
552
+ .authorization((allow) => [allow.groups(contentWriteGroups)])
553
+ .handler(a.handler.function(contentActions)),
554
+
545
555
  saveItemDraft: a
546
556
  .mutation()
547
557
  .arguments({ input: a.json().required() })
@@ -556,6 +566,13 @@ const baseDefinitions = {
556
566
  .authorization((allow) => [allow.groups(contentWriteGroups)])
557
567
  .handler(a.handler.function(contentActions)),
558
568
 
569
+ moveStoryStage: a
570
+ .mutation()
571
+ .arguments({ input: a.json().required() })
572
+ .returns(a.json())
573
+ .authorization((allow) => [allow.groups(contentWriteGroups)])
574
+ .handler(a.handler.function(contentActions)),
575
+
559
576
  unpublishItem: a
560
577
  .mutation()
561
578
  .arguments({ input: a.json().required() })
@@ -2105,20 +2122,25 @@ const baseDefinitions = {
2105
2122
  allow.guest().to(["read"]),
2106
2123
  allow.groups(contentWriteGroups),
2107
2124
  ]),
2125
+ ...editorialChecksSchemaDefinitions,
2126
+ ...monitoringViewSchemaDefinitions,
2108
2127
  };
2109
2128
 
2110
2129
  export const schema = a.schema(baseDefinitions).authorization((allow) => [
2130
+ allow.resource(assignmentAction).to(["query", "mutate"]),
2111
2131
  allow.resource(categoryAction),
2112
2132
  allow.resource(contentActions),
2113
2133
  allow.resource(manageUserRole),
2114
2134
  allow.resource(modelAttachmentUpload),
2115
2135
  allow.resource(newsroomSummary),
2116
2136
  allow.resource(procedureAction),
2137
+ allow.resource(publicForms).to(["mutate"]),
2117
2138
  ]);
2118
2139
 
2119
2140
  /** The deployed schema of a site that enables plugins: the base definitions plus what each plugin contributes (docs/plugins.md). */
2120
2141
  export function schemaWithPlugins(pluginDefinitions: Record<string, any>) {
2121
2142
  return a.schema({ ...baseDefinitions, ...pluginDefinitions } as typeof baseDefinitions).authorization((allow) => [
2143
+ allow.resource(assignmentAction).to(["query", "mutate"]),
2122
2144
  allow.resource(categoryAction),
2123
2145
  allow.resource(contentActions),
2124
2146
  allow.resource(manageUserRole),
@@ -0,0 +1,88 @@
1
+ import { Aspects, Stack } from "aws-cdk-lib";
2
+ import { CfnPolicy } from "aws-cdk-lib/aws-iam";
3
+ /** Lifecycle/context calls, including the fixed reference registration CLI's provenance operations. */
4
+ export const ASSIGNMENT_DATA_FIELDS = [
5
+ "Query/fields/getAssignment",
6
+ "Query/fields/getKnowledgeRawPayload",
7
+ "Query/fields/getProcedureRun",
8
+ "Query/fields/getProcedureVersion",
9
+ "Query/fields/getProcedureDefinition",
10
+ "Query/fields/getModelAttachment",
11
+ "Query/fields/getNewsroomSection",
12
+ "Query/fields/getKnowledgeCorpus",
13
+ "Query/fields/getKnowledgeImportRun",
14
+ "Query/fields/getReference",
15
+ "Query/fields/getReferenceAttachment",
16
+ "Query/fields/getMessage",
17
+ "Query/fields/getSemanticRelation",
18
+ "Query/fields/getSemanticNode",
19
+ "Query/fields/listReferences",
20
+ "Query/fields/listReferenceAttachments",
21
+ "Query/fields/listSemanticRelations",
22
+ "Query/fields/listKnowledgeCorporaByRoleAndName",
23
+ "Query/fields/listItemsByLineageAndVersion",
24
+ "Query/fields/itemBySlug",
25
+ "Query/fields/itemByTenantSlug",
26
+ "Query/fields/listModelAttachmentsByOwnerRoleAndSortKey",
27
+ "Query/fields/listAssignmentsByQueueStatusAndPriority",
28
+ "Query/fields/listSemanticRelationsByObjectState",
29
+ "Query/fields/listSemanticRelationsBySubjectState",
30
+ "Query/fields/listAssignmentEventsByAssignmentAndCreatedAt",
31
+ "Mutation/fields/createAssignment",
32
+ "Mutation/fields/updateAssignment",
33
+ "Mutation/fields/createAssignmentEvent",
34
+ "Mutation/fields/createProcedureRun",
35
+ "Mutation/fields/updateProcedureRun",
36
+ "Mutation/fields/createKnowledgeCorpus",
37
+ "Mutation/fields/updateKnowledgeCorpus",
38
+ "Mutation/fields/createKnowledgeImportRun",
39
+ "Mutation/fields/updateKnowledgeImportRun",
40
+ "Mutation/fields/createKnowledgeRawPayload",
41
+ "Mutation/fields/updateKnowledgeRawPayload",
42
+ "Mutation/fields/createReference",
43
+ "Mutation/fields/updateReference",
44
+ "Mutation/fields/createReferenceAttachment",
45
+ "Mutation/fields/updateReferenceAttachment",
46
+ "Mutation/fields/createMessage",
47
+ "Mutation/fields/updateMessage",
48
+ "Mutation/fields/createSemanticRelation",
49
+ "Mutation/fields/updateSemanticRelation",
50
+ "Mutation/fields/createSemanticNode",
51
+ "Mutation/fields/updateSemanticNode",
52
+ "Mutation/fields/createModelAttachment",
53
+ "Mutation/fields/updateModelAttachment",
54
+ "Mutation/fields/createModelAttachmentUpload",
55
+ "Mutation/fields/completeModelAttachmentUpload",
56
+ "Mutation/fields/createModelAttachmentDownload",
57
+ "Mutation/fields/updateNewsroomSummary",
58
+ ];
59
+ /** Keep the SDK's generated configuration, replacing only this role's GraphQL grants at synthesis. */
60
+ export function scopeAssignmentDataAccess(lambda, graphqlApiArn) {
61
+ if (!lambda.role)
62
+ throw new Error("Assignment function needs an execution role.");
63
+ const roleName = lambda.role.roleName;
64
+ const resources = ASSIGNMENT_DATA_FIELDS.map((field) => `${graphqlApiArn}/types/${field}`);
65
+ Aspects.of(Stack.of(lambda)).add({
66
+ visit(node) {
67
+ if (!(node instanceof CfnPolicy))
68
+ return;
69
+ const stack = Stack.of(node);
70
+ const roles = stack.resolve(node.roles);
71
+ if (!roles?.some((role) => JSON.stringify(role) === JSON.stringify(stack.resolve(roleName))))
72
+ return;
73
+ const document = stack.resolve(node.policyDocument);
74
+ document.Statement.forEach((statement, index) => {
75
+ const actions = Array.isArray(statement.Action) ? statement.Action : [statement.Action];
76
+ if (actions.includes("*") || actions.includes("appsync:*")) {
77
+ throw new Error("Unexpected wildcard assignment action; review permissions before synthesis.");
78
+ }
79
+ if (!actions.includes("appsync:GraphQL"))
80
+ return;
81
+ if (statement.Effect !== "Allow" || actions.length !== 1 || statement.NotResource) {
82
+ throw new Error("Unexpected assignment GraphQL policy; review field scoping before synthesis.");
83
+ }
84
+ node.addPropertyOverride(`PolicyDocument.Statement.${index}.Resource`, resources);
85
+ });
86
+ },
87
+ });
88
+ }
@@ -0,0 +1,87 @@
1
+ import { Aspects, Stack } from "aws-cdk-lib";
2
+ import { CfnPolicy } from "aws-cdk-lib/aws-iam";
3
+ import type { IFunction } from "aws-cdk-lib/aws-lambda";
4
+
5
+ /** Lifecycle/context calls, including the fixed reference registration CLI's provenance operations. */
6
+ export const ASSIGNMENT_DATA_FIELDS = [
7
+ "Query/fields/getAssignment",
8
+ "Query/fields/getKnowledgeRawPayload",
9
+ "Query/fields/getProcedureRun",
10
+ "Query/fields/getProcedureVersion",
11
+ "Query/fields/getProcedureDefinition",
12
+ "Query/fields/getModelAttachment",
13
+ "Query/fields/getNewsroomSection",
14
+ "Query/fields/getKnowledgeCorpus",
15
+ "Query/fields/getKnowledgeImportRun",
16
+ "Query/fields/getReference",
17
+ "Query/fields/getReferenceAttachment",
18
+ "Query/fields/getMessage",
19
+ "Query/fields/getSemanticRelation",
20
+ "Query/fields/getSemanticNode",
21
+ "Query/fields/listReferences",
22
+ "Query/fields/listReferenceAttachments",
23
+ "Query/fields/listSemanticRelations",
24
+ "Query/fields/listKnowledgeCorporaByRoleAndName",
25
+ "Query/fields/listItemsByLineageAndVersion",
26
+ "Query/fields/itemBySlug",
27
+ "Query/fields/itemByTenantSlug",
28
+ "Query/fields/listModelAttachmentsByOwnerRoleAndSortKey",
29
+ "Query/fields/listAssignmentsByQueueStatusAndPriority",
30
+ "Query/fields/listSemanticRelationsByObjectState",
31
+ "Query/fields/listSemanticRelationsBySubjectState",
32
+ "Query/fields/listAssignmentEventsByAssignmentAndCreatedAt",
33
+ "Mutation/fields/createAssignment",
34
+ "Mutation/fields/updateAssignment",
35
+ "Mutation/fields/createAssignmentEvent",
36
+ "Mutation/fields/createProcedureRun",
37
+ "Mutation/fields/updateProcedureRun",
38
+ "Mutation/fields/createKnowledgeCorpus",
39
+ "Mutation/fields/updateKnowledgeCorpus",
40
+ "Mutation/fields/createKnowledgeImportRun",
41
+ "Mutation/fields/updateKnowledgeImportRun",
42
+ "Mutation/fields/createKnowledgeRawPayload",
43
+ "Mutation/fields/updateKnowledgeRawPayload",
44
+ "Mutation/fields/createReference",
45
+ "Mutation/fields/updateReference",
46
+ "Mutation/fields/createReferenceAttachment",
47
+ "Mutation/fields/updateReferenceAttachment",
48
+ "Mutation/fields/createMessage",
49
+ "Mutation/fields/updateMessage",
50
+ "Mutation/fields/createSemanticRelation",
51
+ "Mutation/fields/updateSemanticRelation",
52
+ "Mutation/fields/createSemanticNode",
53
+ "Mutation/fields/updateSemanticNode",
54
+ "Mutation/fields/createModelAttachment",
55
+ "Mutation/fields/updateModelAttachment",
56
+ "Mutation/fields/createModelAttachmentUpload",
57
+ "Mutation/fields/completeModelAttachmentUpload",
58
+ "Mutation/fields/createModelAttachmentDownload",
59
+ "Mutation/fields/updateNewsroomSummary",
60
+ ] as const;
61
+
62
+ /** Keep the SDK's generated configuration, replacing only this role's GraphQL grants at synthesis. */
63
+ export function scopeAssignmentDataAccess(lambda: IFunction, graphqlApiArn: string): void {
64
+ if (!lambda.role) throw new Error("Assignment function needs an execution role.");
65
+ const roleName = lambda.role.roleName;
66
+ const resources = ASSIGNMENT_DATA_FIELDS.map((field) => `${graphqlApiArn}/types/${field}`);
67
+ Aspects.of(Stack.of(lambda)).add({
68
+ visit(node) {
69
+ if (!(node instanceof CfnPolicy)) return;
70
+ const stack = Stack.of(node);
71
+ const roles = stack.resolve(node.roles) as unknown[] | undefined;
72
+ if (!roles?.some((role) => JSON.stringify(role) === JSON.stringify(stack.resolve(roleName)))) return;
73
+ const document = stack.resolve(node.policyDocument) as { Statement: Array<Record<string, unknown>> };
74
+ document.Statement.forEach((statement, index) => {
75
+ const actions = Array.isArray(statement.Action) ? statement.Action : [statement.Action];
76
+ if (actions.includes("*") || actions.includes("appsync:*")) {
77
+ throw new Error("Unexpected wildcard assignment action; review permissions before synthesis.");
78
+ }
79
+ if (!actions.includes("appsync:GraphQL")) return;
80
+ if (statement.Effect !== "Allow" || actions.length !== 1 || statement.NotResource) {
81
+ throw new Error("Unexpected assignment GraphQL policy; review field scoping before synthesis.");
82
+ }
83
+ node.addPropertyOverride(`PolicyDocument.Statement.${index}.Resource`, resources);
84
+ });
85
+ },
86
+ });
87
+ }
@@ -23,6 +23,8 @@ from papyrus_content.rebuild_trigger import (
23
23
  trigger_staging_build,
24
24
  )
25
25
  from papyrus_content.story_reporting import save_story_version
26
+ from papyrus_content.publication import ensure_publication_from_environment
27
+ from papyrus_content.reference_intake import IntakeError, intake_references
26
28
  from papyrus_content.publishing import (
27
29
  ItemFields,
28
30
  PublishError,
@@ -150,6 +152,7 @@ def schedule_unpurged_invalidation(keys: list[str]) -> None:
150
152
 
151
153
  def run_deploy_render_task(client) -> dict:
152
154
  """Render every published page after a backend deploy, then report drift (a dry run: nothing is deleted)."""
155
+ ensure_publication_from_environment(client)
153
156
  context = projection_context(client)
154
157
  report = deploy_render(context)
155
158
  print(drift_metric_line(report))
@@ -283,6 +286,17 @@ def unpublish_item_action(arguments: dict, actor: str) -> dict:
283
286
  return response
284
287
 
285
288
 
289
+ def move_story_stage_action(arguments: dict, actor: str) -> dict:
290
+ from papyrus_content.story_reporting import move_story_stage
291
+
292
+ client, _claims = create_authoring_client()
293
+ try:
294
+ result = move_story_stage(client, arguments["lineageId"], arguments["stage"], actor=actor, reason=arguments.get("reason"))
295
+ except ValueError as error:
296
+ return {"ok": False, "errors": [{"code": "invalid-stage", "message": str(error), "line": None}]}
297
+ return {"ok": True, **result}
298
+
299
+
286
300
  def request_staging_build_action() -> dict:
287
301
  cms_app_id = (os.environ.get("PAPYRUS_CMS_AMPLIFY_APP_ID") or "").strip()
288
302
  if not cms_app_id:
@@ -299,12 +313,20 @@ def handler(event, context):
299
313
  arguments = parse_input(event["arguments"]["input"])
300
314
  actor = actor_from_event(event)
301
315
  try:
316
+ if field == "intakePendingReferences":
317
+ client, _claims = create_authoring_client()
318
+ try:
319
+ return intake_references(client, arguments, event.get("identity") or {})
320
+ except IntakeError as error:
321
+ return {"ok": False, "errors": [{"code": "intake-rejected", "message": str(error)}]}
302
322
  if field == "deriveMarkus":
303
323
  return derive_markus_action(arguments)
304
324
  if field == "saveItemDraft":
305
325
  return save_item_draft_action(arguments, actor)
306
326
  if field == "publishItem":
307
327
  return publish_item_action(arguments, actor)
328
+ if field == "moveStoryStage":
329
+ return move_story_stage_action(arguments, actor)
308
330
  if field == "unpublishItem":
309
331
  return unpublish_item_action(arguments, actor)
310
332
  if field == "requestStagingBuild":
@@ -0,0 +1,14 @@
1
+ """The editorial-checks function: routes its GraphQL fields to papyrus_content.editorial_checks."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from papyrus_content.editorial_checks import GraphQLEditorialStore, Services, handle, load_provider_keys
8
+
9
+ # Amplify passes secrets to Python functions as placeholders; resolve them once per cold start.
10
+ load_provider_keys()
11
+
12
+
13
+ def handler(event: dict[str, Any], _context: Any = None) -> dict[str, Any]:
14
+ return handle(event["info"]["fieldName"], event.get("arguments") or {}, Services(store=GraphQLEditorialStore()))
@@ -0,0 +1 @@
1
+ humanus[jev]>=0.33,<0.34
@@ -0,0 +1,43 @@
1
+ import { defineFunction } from "@aws-amplify/backend";
2
+ import { Duration } from "aws-cdk-lib";
3
+ import { Architecture, Function, Runtime } from "aws-cdk-lib/aws-lambda";
4
+ import { execFileSync } from "node:child_process";
5
+ import path from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ import { pythonLambdaCode } from "../shared/python-bundle.js";
8
+ const functionDirectory = path.dirname(fileURLToPath(import.meta.url));
9
+ /** AppSync gives a resolver 30 seconds; Humanus's classifier deadline (settings, default 20 s) keeps a check inside this. */
10
+ export const EDITORIAL_CHECKS_TIMEOUT_SECONDS = 28;
11
+ /** Humanus with the Jev classifier lane; papyrus_content.editorial_checks does the work. */
12
+ export const editorialChecksRequirements = ["humanus[jev]>=0.33,<0.34"];
13
+ function installRequirements(outputDir) {
14
+ execFileSync("python3", [
15
+ "-m", "pip", "install", "-r", path.join(functionDirectory, "requirements.txt"), "-t", outputDir, "--no-cache-dir",
16
+ "--platform", "manylinux2014_aarch64", "--implementation", "cp", "--python-version", "3.12",
17
+ "--only-binary=:all:", "--ignore-requires-python",
18
+ ], { stdio: "inherit" });
19
+ }
20
+ export const editorialChecks = defineFunction((scope) => new Function(scope, "papyrus-editorial-checks", {
21
+ runtime: Runtime.PYTHON_3_12,
22
+ architecture: Architecture.ARM_64,
23
+ handler: "handler.handler",
24
+ timeout: Duration.seconds(EDITORIAL_CHECKS_TIMEOUT_SECONDS),
25
+ memorySize: 1024,
26
+ code: pythonLambdaCode({
27
+ functionDir: "editorial-checks",
28
+ modules: ["papyrus_content"],
29
+ requirements: editorialChecksRequirements,
30
+ noDeps: true,
31
+ checkoutExtras: installRequirements,
32
+ }, [
33
+ "bash",
34
+ "-c",
35
+ [
36
+ "set -euo pipefail",
37
+ "mkdir -p /asset-output/papyrus_content",
38
+ "cp amplify/functions/editorial-checks/handler.py /asset-output/handler.py",
39
+ "cp -R src/papyrus_content/. /asset-output/papyrus_content/",
40
+ "python3 -m pip install -r amplify/functions/editorial-checks/requirements.txt -t /asset-output --no-cache-dir",
41
+ ].join(" && "),
42
+ ]),
43
+ }), { resourceGroupName: "data" });
@@ -0,0 +1,60 @@
1
+ import { defineFunction } from "@aws-amplify/backend";
2
+ import { Duration } from "aws-cdk-lib";
3
+ import { Architecture, Function, Runtime } from "aws-cdk-lib/aws-lambda";
4
+ import type { Construct } from "constructs";
5
+ import { execFileSync } from "node:child_process";
6
+ import path from "node:path";
7
+ import { fileURLToPath } from "node:url";
8
+ import { pythonLambdaCode } from "../shared/python-bundle";
9
+
10
+ const functionDirectory = path.dirname(fileURLToPath(import.meta.url));
11
+
12
+ /** AppSync gives a resolver 30 seconds; Humanus's classifier deadline (settings, default 20 s) keeps a check inside this. */
13
+ export const EDITORIAL_CHECKS_TIMEOUT_SECONDS = 28;
14
+
15
+ /** Humanus with the Jev classifier lane; papyrus_content.editorial_checks does the work. */
16
+ export const editorialChecksRequirements = ["humanus[jev]>=0.33,<0.34"];
17
+
18
+ function installRequirements(outputDir: string): void {
19
+ execFileSync(
20
+ "python3",
21
+ [
22
+ "-m", "pip", "install", "-r", path.join(functionDirectory, "requirements.txt"), "-t", outputDir, "--no-cache-dir",
23
+ "--platform", "manylinux2014_aarch64", "--implementation", "cp", "--python-version", "3.12",
24
+ "--only-binary=:all:", "--ignore-requires-python",
25
+ ],
26
+ { stdio: "inherit" },
27
+ );
28
+ }
29
+
30
+ export const editorialChecks = defineFunction(
31
+ (scope: Construct) =>
32
+ new Function(scope, "papyrus-editorial-checks", {
33
+ runtime: Runtime.PYTHON_3_12,
34
+ architecture: Architecture.ARM_64,
35
+ handler: "handler.handler",
36
+ timeout: Duration.seconds(EDITORIAL_CHECKS_TIMEOUT_SECONDS),
37
+ memorySize: 1024,
38
+ code: pythonLambdaCode(
39
+ {
40
+ functionDir: "editorial-checks",
41
+ modules: ["papyrus_content"],
42
+ requirements: editorialChecksRequirements,
43
+ noDeps: true,
44
+ checkoutExtras: installRequirements,
45
+ },
46
+ [
47
+ "bash",
48
+ "-c",
49
+ [
50
+ "set -euo pipefail",
51
+ "mkdir -p /asset-output/papyrus_content",
52
+ "cp amplify/functions/editorial-checks/handler.py /asset-output/handler.py",
53
+ "cp -R src/papyrus_content/. /asset-output/papyrus_content/",
54
+ "python3 -m pip install -r amplify/functions/editorial-checks/requirements.txt -t /asset-output --no-cache-dir",
55
+ ].join(" && "),
56
+ ],
57
+ ),
58
+ }),
59
+ { resourceGroupName: "data" },
60
+ );