@anthusai/papyrus 2.0.0-next.8 → 2.0.0-next.80

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 (211) hide show
  1. package/amplify/data/function-handler.js +20 -0
  2. package/amplify/data/function-handler.ts +40 -0
  3. package/amplify/data/resource.js +151 -61
  4. package/amplify/data/resource.ts +157 -61
  5. package/amplify/data/schema.js +2096 -1980
  6. package/amplify/data/schema.ts +198 -69
  7. package/amplify/functions/assignment-action/data-access.js +14 -15
  8. package/amplify/functions/assignment-action/data-access.ts +13 -14
  9. package/amplify/functions/assignment-action/handler.ts +1 -1
  10. package/amplify/functions/automation-view/handler.py +17 -0
  11. package/amplify/functions/automation-view/resource.js +24 -0
  12. package/amplify/functions/automation-view/resource.ts +34 -0
  13. package/amplify/functions/automation-view/schema.js +26 -0
  14. package/amplify/functions/automation-view/schema.ts +28 -0
  15. package/amplify/functions/automation-view/wire.js +56 -0
  16. package/amplify/functions/automation-view/wire.ts +76 -0
  17. package/amplify/functions/content-actions/handler.py +61 -2
  18. package/amplify/functions/content-actions/requirements.txt +1 -0
  19. package/amplify/functions/content-actions/resource.js +1 -1
  20. package/amplify/functions/content-actions/resource.ts +1 -1
  21. package/amplify/{plugins/editorial-checks/function → functions/editorial-checks}/handler.py +3 -3
  22. package/amplify/functions/editorial-checks/requirements.txt +1 -0
  23. package/amplify/{plugins/editorial-checks/function → functions/editorial-checks}/resource.js +7 -7
  24. package/amplify/{plugins/editorial-checks/function → functions/editorial-checks}/resource.ts +7 -7
  25. package/amplify/functions/editorial-checks/schema.js +122 -0
  26. package/amplify/{plugins → functions}/editorial-checks/schema.ts +40 -12
  27. package/amplify/functions/editorial-checks/wire.js +53 -0
  28. package/amplify/functions/editorial-checks/wire.ts +61 -0
  29. package/amplify/functions/monitoring-view/handler.py +11 -0
  30. package/amplify/functions/monitoring-view/resource.js +24 -0
  31. package/amplify/functions/monitoring-view/resource.ts +34 -0
  32. package/amplify/functions/monitoring-view/schema.js +17 -0
  33. package/amplify/functions/monitoring-view/schema.ts +19 -0
  34. package/amplify/functions/monitoring-view/wire.js +37 -0
  35. package/amplify/functions/monitoring-view/wire.ts +47 -0
  36. package/amplify/functions/public-forms/core.js +247 -0
  37. package/amplify/functions/public-forms/core.ts +310 -0
  38. package/amplify/functions/public-forms/handler.ts +41 -0
  39. package/amplify/functions/public-forms/origins.js +35 -0
  40. package/amplify/functions/public-forms/origins.ts +43 -0
  41. package/amplify/functions/public-forms/resource.js +9 -0
  42. package/amplify/functions/public-forms/resource.ts +10 -0
  43. package/amplify/functions/public-forms/wire.js +25 -0
  44. package/amplify/functions/public-forms/wire.ts +32 -0
  45. package/amplify/functions/shared/editorial-context.ts +63 -4
  46. package/amplify/functions/shared/python-bundle.js +20 -14
  47. package/amplify/functions/shared/python-bundle.ts +25 -18
  48. package/amplify/plugins/newsletter/config.js +245 -0
  49. package/amplify/plugins/newsletter/config.ts +305 -0
  50. package/amplify/plugins/newsletter/function/handler.py +6 -0
  51. package/amplify/plugins/newsletter/function/requirements.txt +5 -0
  52. package/amplify/plugins/newsletter/ops/handler.py +12 -0
  53. package/amplify/plugins/newsletter/ops/resource.js +27 -0
  54. package/amplify/plugins/newsletter/ops/resource.ts +37 -0
  55. package/amplify/plugins/newsletter/papyrus.plugin.js +263 -0
  56. package/amplify/plugins/newsletter/papyrus.plugin.ts +311 -0
  57. package/amplify/plugins/newsletter/schema.js +57 -0
  58. package/amplify/plugins/newsletter/schema.ts +62 -0
  59. package/amplify/plugins/newsletter/secure-string-parameter.js +107 -0
  60. package/amplify/plugins/newsletter/secure-string-parameter.ts +120 -0
  61. package/amplify/plugins/newsletter/sending.js +140 -0
  62. package/amplify/plugins/newsletter/sending.ts +186 -0
  63. package/amplify/plugins/reader-steering/config.js +182 -0
  64. package/amplify/plugins/reader-steering/config.ts +290 -0
  65. package/amplify/plugins/reader-steering/function/ai_moderation.py +246 -0
  66. package/amplify/plugins/reader-steering/function/handler.py +1554 -0
  67. package/amplify/plugins/reader-steering/function/moderation-prompt.md +27 -0
  68. package/amplify/plugins/reader-steering/function/moderation.py +316 -0
  69. package/amplify/plugins/reader-steering/function/proposals.py +255 -0
  70. package/amplify/plugins/reader-steering/function/resource.js +27 -0
  71. package/amplify/plugins/reader-steering/function/resource.ts +35 -0
  72. package/amplify/plugins/reader-steering/papyrus.plugin.js +186 -0
  73. package/amplify/plugins/reader-steering/papyrus.plugin.ts +212 -0
  74. package/amplify/plugins/reader-steering/schema.js +205 -0
  75. package/amplify/plugins/reader-steering/schema.ts +207 -0
  76. package/amplify/plugins/registry.js +4 -2
  77. package/amplify/plugins/registry.ts +4 -2
  78. package/amplify/plugins/signup/schema.js +2 -1
  79. package/amplify/plugins/signup/schema.ts +2 -1
  80. package/amplify/plugins/types.ts +5 -0
  81. package/amplify/plugins/wire.js +1 -0
  82. package/amplify/plugins/wire.ts +1 -0
  83. package/amplify/publication/projection-lease.js +30 -0
  84. package/amplify/publication/projection-lease.ts +39 -0
  85. package/amplify/publication/redirect-and-index.js +105 -0
  86. package/amplify/publication/redirect-rules.js +73 -0
  87. package/amplify/publication/redirect-rules.ts +93 -0
  88. package/amplify/publication/s3-projection.js +7 -1
  89. package/amplify/publication/s3-projection.ts +9 -1
  90. package/amplify/site-backend-config.ts +18 -1
  91. package/amplify/site-backend-names.js +4 -2
  92. package/amplify/site-backend-names.ts +4 -2
  93. package/amplify/site-backend.js +41 -2
  94. package/amplify/site-backend.ts +46 -2
  95. package/app/api/auth/prospectus/sign-in/route.ts +4 -0
  96. package/app/api/newsletter/confirm/route.ts +13 -0
  97. package/app/api/newsletter/preferences/route.ts +13 -0
  98. package/app/api/newsletter/state/route.ts +9 -0
  99. package/app/api/newsletter/subscribe/route.ts +9 -0
  100. package/app/api/newsletter/unsubscribe/route.ts +13 -0
  101. package/app/api/newsroom/curation/context/route.ts +9 -0
  102. package/app/api/newsroom/curation/priming/route.ts +9 -0
  103. package/app/api/newsroom/curation/publication/route.ts +9 -0
  104. package/app/api/reader/comment/delete/route.ts +9 -0
  105. package/app/api/reader/comment/edit/route.ts +9 -0
  106. package/app/api/reader/comment/route.ts +9 -0
  107. package/app/api/reader/flag/route.ts +9 -0
  108. package/app/api/reader/handle/route.ts +9 -0
  109. package/app/api/reader/me/route.ts +9 -0
  110. package/app/api/reader/rating/route.ts +9 -0
  111. package/app/api/reader/report/route.ts +9 -0
  112. package/app/api/reader/retired/route.ts +9 -0
  113. package/app/api/reader/submit/route.ts +9 -0
  114. package/app/api/reader/vote/route.ts +9 -0
  115. package/bin/papyrus-infra.mjs +20 -1
  116. package/components/automation-panel.tsx +49 -0
  117. package/components/automation-run-now.tsx +97 -0
  118. package/components/automation-view.tsx +192 -0
  119. package/components/editorial-checks-admin-panel.tsx +36 -11
  120. package/components/moderation-panel.tsx +248 -0
  121. package/components/monitoring-overview-view.tsx +241 -0
  122. package/components/monitoring-panel.tsx +40 -0
  123. package/components/news-desk-client-provider.tsx +18 -18
  124. package/components/news-desk-taxonomy-client.ts +28 -8
  125. package/components/newsletter-panel.tsx +474 -0
  126. package/components/newsletter-sections.tsx +163 -0
  127. package/components/newsroom-access-gate.tsx +15 -1
  128. package/components/newsroom-article-editor.tsx +6 -6
  129. package/components/newsroom-articles-view.tsx +6 -6
  130. package/components/newsroom-board-view.tsx +8 -3
  131. package/components/newsroom-curation-bootstrap.tsx +45 -0
  132. package/components/newsroom-ops-overview.tsx +22 -92
  133. package/components/newsroom-ops-shell.tsx +2 -2
  134. package/components/newsroom-organizer.css +33 -0
  135. package/components/newsroom-overview-skeleton.tsx +25 -0
  136. package/components/newsroom-references-view.tsx +192 -49
  137. package/components/notification-center.tsx +273 -0
  138. package/components/publication-cyclotron-panel.tsx +15 -10
  139. package/components/reader-auth-state.ts +1 -1
  140. package/components/reference-add-entry.tsx +75 -0
  141. package/components/reference-curation-controls.tsx +31 -22
  142. package/components/reference-cyclotron-priming.tsx +58 -19
  143. package/components/reference-cyclotron-suggestion.tsx +10 -6
  144. package/components/reference-priming.tsx +14 -10
  145. package/components/reference-relevance-review.tsx +3 -3
  146. package/components/reference-section-suggestion.tsx +1 -1
  147. package/components/topic-steering-workspace.tsx +223 -144
  148. package/components/use-editorial-checks.ts +12 -10
  149. package/infra/amplify-app-shell.js +94 -16
  150. package/infra/amplify-app-shell.ts +106 -18
  151. package/infra/cloud-email-config.js +32 -0
  152. package/infra/cloud-email-config.ts +39 -0
  153. package/infra/cloud-email.js +57 -0
  154. package/infra/cloud-email.test.js +69 -0
  155. package/infra/cloud-email.test.ts +66 -0
  156. package/infra/cloud-email.ts +60 -0
  157. package/infra/index.js +1 -0
  158. package/infra/secure-string-parameter-handler.js +41 -0
  159. package/infra/secure-string-parameter-handler.ts +41 -0
  160. package/infra/secure-string-parameter.js +79 -0
  161. package/infra/secure-string-parameter.ts +91 -0
  162. package/infra/site-config.js +88 -6
  163. package/infra/site-config.ts +134 -6
  164. package/lib/automation-client.ts +54 -0
  165. package/lib/automation-fixture.ts +93 -0
  166. package/lib/automation-overview.ts +232 -0
  167. package/lib/category-repository.ts +11 -9
  168. package/lib/curation-routes.ts +345 -0
  169. package/lib/cyclotron-suggestions.ts +4 -4
  170. package/lib/editorial-checks-backend.ts +1 -1
  171. package/lib/editorial-checks-client.ts +19 -1
  172. package/lib/editorial-checks-demo.ts +2 -2
  173. package/lib/editorial-checks-settings.ts +3 -0
  174. package/lib/editorial-checks.ts +8 -11
  175. package/lib/editorial-preview.ts +5 -5
  176. package/lib/monitoring-client.ts +29 -0
  177. package/lib/monitoring-overview-fixture.ts +51 -0
  178. package/lib/monitoring-overview.ts +145 -0
  179. package/lib/news-desk-session.ts +12 -21
  180. package/lib/newsletter-api.ts +418 -0
  181. package/lib/newsletter-client.ts +46 -0
  182. package/lib/newsletter-fixture.ts +184 -0
  183. package/lib/newsletter-model.ts +202 -0
  184. package/lib/newsroom-organizer-nav.ts +2 -1
  185. package/lib/prospectus-session.ts +15 -14
  186. package/lib/prospectus-sign-in-routes.ts +84 -19
  187. package/lib/prospectus-site-identity.ts +24 -1
  188. package/lib/reader-api.ts +145 -0
  189. package/lib/reader-moderation.ts +220 -0
  190. package/lib/reader-retirement-route.ts +89 -0
  191. package/lib/reader-subject.md +29 -0
  192. package/lib/reader-subject.ts +53 -0
  193. package/lib/reference-review-details.ts +71 -0
  194. package/lib/reference-review-request.ts +14 -0
  195. package/lib/relevance-decisions.ts +42 -10
  196. package/lib/relevance-status.ts +2 -2
  197. package/lib/review-client.ts +99 -0
  198. package/lib/review-fixture.ts +45 -0
  199. package/lib/review-requests.ts +238 -0
  200. package/lib/semantic-graph.ts +2 -0
  201. package/lib/site-brand-tenant.ts +11 -6
  202. package/lib/site-brand.ts +6 -3
  203. package/lib/site-origin.ts +67 -0
  204. package/lib/use-reference-review-data.ts +44 -0
  205. package/middleware.ts +14 -3
  206. package/package.json +56 -3
  207. package/routes.manifest.json +215 -2
  208. package/amplify/plugins/editorial-checks/function/requirements.txt +0 -1
  209. package/amplify/plugins/editorial-checks/papyrus.plugin.js +0 -71
  210. package/amplify/plugins/editorial-checks/papyrus.plugin.ts +0 -87
  211. package/amplify/plugins/editorial-checks/schema.js +0 -94
@@ -1,13 +1,18 @@
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 { automationViewSchemaDefinitions } from "../functions/automation-view/schema";
6
+ import { monitoringViewSchemaDefinitions } from "../functions/monitoring-view/schema";
4
7
  import { contentActions } from "../functions/content-actions/resource";
5
8
  import { knowledgeQuery } from "../functions/knowledge-query/resource";
6
9
  import { manageUserRole } from "../functions/manage-user-role/resource";
7
10
  import { modelAttachmentUpload } from "../functions/model-attachment-upload/resource";
8
11
  import { newsroomSummary } from "../functions/newsroom-summary/resource";
12
+ import { publicForms } from "../functions/public-forms/resource";
9
13
  import { procedureAction } from "../functions/procedure-action/resource";
10
14
  import { readerSettings } from "../functions/reader-settings/resource";
15
+ import { functionHandler } from "./function-handler";
11
16
 
12
17
  const authoringOperations: ("read" | "create" | "update" | "delete")[] = [
13
18
  "read",
@@ -23,7 +28,27 @@ const modelWithoutSubscriptions = <Fields extends Parameters<typeof a.model>[0]>
23
28
  a.model(fields).disableOperations(["subscriptions"]);
24
29
  const realtimeModel = <Fields extends Parameters<typeof a.model>[0]>(fields: Fields) => a.model(fields);
25
30
 
26
- const baseDefinitions = {
31
+ /**
32
+ * Model groups a site may leave out of its data API. CloudFormation creates at most 2,500 resources in one stack
33
+ * operation, nested stacks included, and the full model set exceeds that on a fresh create. A first deploy that
34
+ * excludes a group fits; a second deploy without the exclusion adds the models as an ordinary update.
35
+ */
36
+ export const OPTIONAL_MODEL_GROUPS = {
37
+ editions: ["Edition", "EditionItem", "PublishedEdition", "PublishedEditionItem"],
38
+ } as const;
39
+
40
+ export type OptionalModelGroup = keyof typeof OPTIONAL_MODEL_GROUPS;
41
+
42
+ export function assertKnownModelGroups(groups: readonly string[]): asserts groups is readonly OptionalModelGroup[] {
43
+ for (const group of groups) {
44
+ if (!(group in OPTIONAL_MODEL_GROUPS)) {
45
+ throw new Error(`Unknown model group "${group}"; known groups: ${Object.keys(OPTIONAL_MODEL_GROUPS).join(", ")}`);
46
+ }
47
+ }
48
+ }
49
+
50
+ function buildBaseDefinitions(includeEditions: boolean) {
51
+ const definitions = {
27
52
  UserProfile: modelWithoutSubscriptions({
28
53
  id: a.id().required(),
29
54
  email: a.email(),
@@ -138,7 +163,7 @@ const baseDefinitions = {
138
163
  .query()
139
164
  .returns(a.ref("UserDirectoryResult"))
140
165
  .authorization((allow) => [allow.group(adminGroup)])
141
- .handler(a.handler.function(manageUserRole)),
166
+ .handler(functionHandler("manageUserRole", manageUserRole)),
142
167
 
143
168
  grantUserRole: a
144
169
  .mutation()
@@ -150,7 +175,7 @@ const baseDefinitions = {
150
175
  })
151
176
  .returns(a.ref("UserRoleMutationResult"))
152
177
  .authorization((allow) => [allow.group(adminGroup)])
153
- .handler(a.handler.function(manageUserRole)),
178
+ .handler(functionHandler("manageUserRole", manageUserRole)),
154
179
 
155
180
  revokeUserRole: a
156
181
  .mutation()
@@ -162,7 +187,7 @@ const baseDefinitions = {
162
187
  })
163
188
  .returns(a.ref("UserRoleMutationResult"))
164
189
  .authorization((allow) => [allow.group(adminGroup)])
165
- .handler(a.handler.function(manageUserRole)),
190
+ .handler(functionHandler("manageUserRole", manageUserRole)),
166
191
 
167
192
  mergeUserProfiles: a
168
193
  .mutation()
@@ -175,13 +200,13 @@ const baseDefinitions = {
175
200
  })
176
201
  .returns(a.ref("UserDirectoryEntry"))
177
202
  .authorization((allow) => [allow.group(adminGroup)])
178
- .handler(a.handler.function(manageUserRole)),
203
+ .handler(functionHandler("manageUserRole", manageUserRole)),
179
204
 
180
205
  getReaderSettings: a
181
206
  .query()
182
207
  .returns(a.ref("ReaderSettingsResult"))
183
208
  .authorization((allow) => [allow.authenticated()])
184
- .handler(a.handler.function(readerSettings)),
209
+ .handler(functionHandler("readerSettings", readerSettings)),
185
210
 
186
211
  updateReaderSettings: a
187
212
  .mutation()
@@ -190,7 +215,7 @@ const baseDefinitions = {
190
215
  })
191
216
  .returns(a.ref("ReaderSettingsResult"))
192
217
  .authorization((allow) => [allow.authenticated()])
193
- .handler(a.handler.function(readerSettings)),
218
+ .handler(functionHandler("readerSettings", readerSettings)),
194
219
 
195
220
  SteeringActionResult: a.customType({
196
221
  ok: a.boolean().required(),
@@ -220,7 +245,7 @@ const baseDefinitions = {
220
245
  })
221
246
  .returns(a.ref("SteeringActionResult"))
222
247
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
223
- .handler(a.handler.function(categoryAction)),
248
+ .handler(functionHandler("categoryAction", categoryAction)),
224
249
 
225
250
  CurationDelegationResult: a.customType({
226
251
  ok: a.boolean().required(),
@@ -307,7 +332,7 @@ const baseDefinitions = {
307
332
  .authorization((allow) => [
308
333
  allow.groups(categoryWriteGroups),
309
334
  ])
310
- .handler(a.handler.function(categoryAction)),
335
+ .handler(functionHandler("categoryAction", categoryAction)),
311
336
 
312
337
  createCurationDelegation: a
313
338
  .mutation()
@@ -319,7 +344,7 @@ const baseDefinitions = {
319
344
  .authorization((allow) => [
320
345
  allow.groups(categoryWriteGroups),
321
346
  ])
322
- .handler(a.handler.function(categoryAction)),
347
+ .handler(functionHandler("categoryAction", categoryAction)),
323
348
 
324
349
  revokeCurationDelegation: a
325
350
  .mutation()
@@ -330,7 +355,7 @@ const baseDefinitions = {
330
355
  .authorization((allow) => [
331
356
  allow.groups(categoryWriteGroups),
332
357
  ])
333
- .handler(a.handler.function(categoryAction)),
358
+ .handler(functionHandler("categoryAction", categoryAction)),
334
359
 
335
360
  listCurationDelegations: a
336
361
  .query()
@@ -338,7 +363,7 @@ const baseDefinitions = {
338
363
  .authorization((allow) => [
339
364
  allow.groups(categoryWriteGroups),
340
365
  ])
341
- .handler(a.handler.function(categoryAction)),
366
+ .handler(functionHandler("categoryAction", categoryAction)),
342
367
 
343
368
  requestCurationDelegation: a
344
369
  .mutation()
@@ -352,7 +377,7 @@ const baseDefinitions = {
352
377
  .authorization((allow) => [
353
378
  allow.authenticated("identityPool"),
354
379
  ])
355
- .handler(a.handler.function(categoryAction)),
380
+ .handler(functionHandler("categoryAction", categoryAction)),
356
381
 
357
382
  approveCurationDelegation: a
358
383
  .mutation()
@@ -363,7 +388,7 @@ const baseDefinitions = {
363
388
  .authorization((allow) => [
364
389
  allow.groups(categoryWriteGroups),
365
390
  ])
366
- .handler(a.handler.function(categoryAction)),
391
+ .handler(functionHandler("categoryAction", categoryAction)),
367
392
 
368
393
  denyCurationDelegation: a
369
394
  .mutation()
@@ -374,7 +399,7 @@ const baseDefinitions = {
374
399
  .authorization((allow) => [
375
400
  allow.groups(categoryWriteGroups),
376
401
  ])
377
- .handler(a.handler.function(categoryAction)),
402
+ .handler(functionHandler("categoryAction", categoryAction)),
378
403
 
379
404
  getCurationDelegationStatus: a
380
405
  .query()
@@ -385,7 +410,7 @@ const baseDefinitions = {
385
410
  .authorization((allow) => [
386
411
  allow.authenticated("identityPool"),
387
412
  ])
388
- .handler(a.handler.function(categoryAction)),
413
+ .handler(functionHandler("categoryAction", categoryAction)),
389
414
 
390
415
  recordDelegatedCuration: a
391
416
  .mutation()
@@ -407,7 +432,7 @@ const baseDefinitions = {
407
432
  .authorization((allow) => [
408
433
  allow.authenticated("identityPool"),
409
434
  ])
410
- .handler(a.handler.function(categoryAction)),
435
+ .handler(functionHandler("categoryAction", categoryAction)),
411
436
 
412
437
  setReferenceQualityRating: a
413
438
  .mutation()
@@ -422,7 +447,7 @@ const baseDefinitions = {
422
447
  .authorization((allow) => [
423
448
  allow.groups(categoryWriteGroups),
424
449
  ])
425
- .handler(a.handler.function(categoryAction)),
450
+ .handler(functionHandler("categoryAction", categoryAction)),
426
451
 
427
452
  createCategorySetDraft: a
428
453
  .mutation()
@@ -434,7 +459,7 @@ const baseDefinitions = {
434
459
  })
435
460
  .returns(a.ref("CategorySetDraftActionResult"))
436
461
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
437
- .handler(a.handler.function(categoryAction)),
462
+ .handler(functionHandler("categoryAction", categoryAction)),
438
463
 
439
464
  promoteCategorySetDraft: a
440
465
  .mutation()
@@ -445,7 +470,7 @@ const baseDefinitions = {
445
470
  })
446
471
  .returns(a.ref("CategorySetDraftActionResult"))
447
472
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
448
- .handler(a.handler.function(categoryAction)),
473
+ .handler(functionHandler("categoryAction", categoryAction)),
449
474
 
450
475
  discardCategorySetDraft: a
451
476
  .mutation()
@@ -456,7 +481,7 @@ const baseDefinitions = {
456
481
  })
457
482
  .returns(a.ref("CategorySetDraftActionResult"))
458
483
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
459
- .handler(a.handler.function(categoryAction)),
484
+ .handler(functionHandler("categoryAction", categoryAction)),
460
485
 
461
486
  createDraftCategory: a
462
487
  .mutation()
@@ -472,7 +497,7 @@ const baseDefinitions = {
472
497
  })
473
498
  .returns(a.ref("SteeringActionResult"))
474
499
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
475
- .handler(a.handler.function(categoryAction)),
500
+ .handler(functionHandler("categoryAction", categoryAction)),
476
501
 
477
502
  updateDraftCategory: a
478
503
  .mutation()
@@ -488,7 +513,7 @@ const baseDefinitions = {
488
513
  })
489
514
  .returns(a.ref("SteeringActionResult"))
490
515
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
491
- .handler(a.handler.function(categoryAction)),
516
+ .handler(functionHandler("categoryAction", categoryAction)),
492
517
 
493
518
  archiveDraftCategory: a
494
519
  .mutation()
@@ -499,7 +524,7 @@ const baseDefinitions = {
499
524
  })
500
525
  .returns(a.ref("SteeringActionResult"))
501
526
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
502
- .handler(a.handler.function(categoryAction)),
527
+ .handler(functionHandler("categoryAction", categoryAction)),
503
528
 
504
529
  reviewReferenceTopicLabel: a
505
530
  .mutation()
@@ -513,7 +538,7 @@ const baseDefinitions = {
513
538
  })
514
539
  .returns(a.ref("TopicLabelActionResult"))
515
540
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
516
- .handler(a.handler.function(categoryAction)),
541
+ .handler(functionHandler("categoryAction", categoryAction)),
517
542
 
518
543
  NewsroomSummary: a.customType({
519
544
  generatedAt: a.datetime().required(),
@@ -533,42 +558,56 @@ const baseDefinitions = {
533
558
  .query()
534
559
  .returns(a.ref("NewsroomSummary"))
535
560
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
536
- .handler(a.handler.function(newsroomSummary)),
561
+ .handler(functionHandler("newsroomSummary", newsroomSummary)),
537
562
 
538
563
  deriveMarkus: a
539
564
  .query()
540
565
  .arguments({ input: a.json().required() })
541
566
  .returns(a.json())
542
567
  .authorization((allow) => [allow.groups(contentWriteGroups)])
543
- .handler(a.handler.function(contentActions)),
568
+ .handler(functionHandler("contentActions", contentActions)),
569
+
570
+ intakePendingReferences: a
571
+ .mutation()
572
+ .arguments({ input: a.json().required() })
573
+ .returns(a.json())
574
+ .authorization((allow) => [allow.groups(contentWriteGroups)])
575
+ .handler(functionHandler("contentActions", contentActions)),
544
576
 
545
577
  saveItemDraft: a
546
578
  .mutation()
547
579
  .arguments({ input: a.json().required() })
548
580
  .returns(a.json())
549
581
  .authorization((allow) => [allow.groups(contentWriteGroups)])
550
- .handler(a.handler.function(contentActions)),
582
+ .handler(functionHandler("contentActions", contentActions)),
551
583
 
552
584
  publishItem: a
553
585
  .mutation()
554
586
  .arguments({ input: a.json().required() })
555
587
  .returns(a.json())
556
588
  .authorization((allow) => [allow.groups(contentWriteGroups)])
557
- .handler(a.handler.function(contentActions)),
589
+ .handler(functionHandler("contentActions", contentActions)),
590
+
591
+ moveStoryStage: a
592
+ .mutation()
593
+ .arguments({ input: a.json().required() })
594
+ .returns(a.json())
595
+ .authorization((allow) => [allow.groups(contentWriteGroups)])
596
+ .handler(functionHandler("contentActions", contentActions)),
558
597
 
559
598
  unpublishItem: a
560
599
  .mutation()
561
600
  .arguments({ input: a.json().required() })
562
601
  .returns(a.json())
563
602
  .authorization((allow) => [allow.groups(contentWriteGroups)])
564
- .handler(a.handler.function(contentActions)),
603
+ .handler(functionHandler("contentActions", contentActions)),
565
604
 
566
605
  requestStagingBuild: a
567
606
  .mutation()
568
607
  .arguments({ input: a.json().required() })
569
608
  .returns(a.json())
570
609
  .authorization((allow) => [allow.groups(contentWriteGroups)])
571
- .handler(a.handler.function(contentActions)),
610
+ .handler(functionHandler("contentActions", contentActions)),
572
611
 
573
612
  knowledgeQuery: a
574
613
  .query()
@@ -577,7 +616,7 @@ const baseDefinitions = {
577
616
  })
578
617
  .returns(a.json())
579
618
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
580
- .handler(a.handler.function(knowledgeQuery)),
619
+ .handler(functionHandler("knowledgeQuery", knowledgeQuery)),
581
620
 
582
621
  updateNewsroomSummary: a
583
622
  .mutation()
@@ -588,7 +627,7 @@ const baseDefinitions = {
588
627
  })
589
628
  .returns(a.ref("NewsroomSummary"))
590
629
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
591
- .handler(a.handler.function(newsroomSummary)),
630
+ .handler(functionHandler("newsroomSummary", newsroomSummary)),
592
631
 
593
632
  ModelAttachmentUploadSlot: a.customType({
594
633
  ok: a.boolean().required(),
@@ -648,7 +687,7 @@ const baseDefinitions = {
648
687
  })
649
688
  .returns(a.ref("ModelAttachmentUploadSlot"))
650
689
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
651
- .handler(a.handler.function(modelAttachmentUpload)),
690
+ .handler(functionHandler("modelAttachmentUpload", modelAttachmentUpload)),
652
691
 
653
692
  completeModelAttachmentUpload: a
654
693
  .mutation()
@@ -670,7 +709,7 @@ const baseDefinitions = {
670
709
  })
671
710
  .returns(a.ref("ModelAttachment"))
672
711
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
673
- .handler(a.handler.function(modelAttachmentUpload)),
712
+ .handler(functionHandler("modelAttachmentUpload", modelAttachmentUpload)),
674
713
 
675
714
  abortModelAttachmentUpload: a
676
715
  .mutation()
@@ -692,7 +731,7 @@ const baseDefinitions = {
692
731
  })
693
732
  .returns(a.ref("ModelAttachmentUploadAbortResult"))
694
733
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
695
- .handler(a.handler.function(modelAttachmentUpload)),
734
+ .handler(functionHandler("modelAttachmentUpload", modelAttachmentUpload)),
696
735
 
697
736
  createModelAttachmentDownload: a
698
737
  .mutation()
@@ -701,7 +740,7 @@ const baseDefinitions = {
701
740
  })
702
741
  .returns(a.ref("ModelAttachmentDownloadSlot"))
703
742
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
704
- .handler(a.handler.function(modelAttachmentUpload)),
743
+ .handler(functionHandler("modelAttachmentUpload", modelAttachmentUpload)),
705
744
 
706
745
  AssignmentActionResult: a.customType({
707
746
  ok: a.boolean().required(),
@@ -796,7 +835,7 @@ const baseDefinitions = {
796
835
  })
797
836
  .returns(a.ref("AssignmentContext").array().required())
798
837
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
799
- .handler(a.handler.function(assignmentAction)),
838
+ .handler(functionHandler("assignmentAction", assignmentAction)),
800
839
 
801
840
  listAssignmentQueue: a
802
841
  .query()
@@ -807,7 +846,7 @@ const baseDefinitions = {
807
846
  })
808
847
  .returns(a.ref("AssignmentContext").array().required())
809
848
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
810
- .handler(a.handler.function(assignmentAction)),
849
+ .handler(functionHandler("assignmentAction", assignmentAction)),
811
850
 
812
851
  getEditorialContext: a
813
852
  .query()
@@ -817,10 +856,11 @@ const baseDefinitions = {
817
856
  storyLineageId: a.id(),
818
857
  assignmentId: a.id(),
819
858
  maxCharacters: a.integer(),
859
+ optionalPublicationDoctrine: a.boolean(),
820
860
  })
821
861
  .returns(a.json().required())
822
862
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
823
- .handler(a.handler.function(assignmentAction)),
863
+ .handler(functionHandler("assignmentAction", assignmentAction)),
824
864
 
825
865
  getAssignmentContext: a
826
866
  .query()
@@ -829,7 +869,7 @@ const baseDefinitions = {
829
869
  })
830
870
  .returns(a.ref("AssignmentContext"))
831
871
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
832
- .handler(a.handler.function(assignmentAction)),
872
+ .handler(functionHandler("assignmentAction", assignmentAction)),
833
873
 
834
874
  claimAssignment: a
835
875
  .mutation()
@@ -846,7 +886,7 @@ const baseDefinitions = {
846
886
  })
847
887
  .returns(a.ref("AssignmentActionResult"))
848
888
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
849
- .handler(a.handler.function(assignmentAction)),
889
+ .handler(functionHandler("assignmentAction", assignmentAction)),
850
890
 
851
891
  releaseAssignment: a
852
892
  .mutation()
@@ -858,7 +898,7 @@ const baseDefinitions = {
858
898
  })
859
899
  .returns(a.ref("AssignmentActionResult"))
860
900
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
861
- .handler(a.handler.function(assignmentAction)),
901
+ .handler(functionHandler("assignmentAction", assignmentAction)),
862
902
 
863
903
  completeAssignment: a
864
904
  .mutation()
@@ -870,7 +910,7 @@ const baseDefinitions = {
870
910
  })
871
911
  .returns(a.ref("AssignmentActionResult"))
872
912
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
873
- .handler(a.handler.function(assignmentAction)),
913
+ .handler(functionHandler("assignmentAction", assignmentAction)),
874
914
 
875
915
  cancelAssignment: a
876
916
  .mutation()
@@ -882,7 +922,7 @@ const baseDefinitions = {
882
922
  })
883
923
  .returns(a.ref("AssignmentActionResult"))
884
924
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
885
- .handler(a.handler.function(assignmentAction)),
925
+ .handler(functionHandler("assignmentAction", assignmentAction)),
886
926
 
887
927
  reopenAssignment: a
888
928
  .mutation()
@@ -894,7 +934,7 @@ const baseDefinitions = {
894
934
  })
895
935
  .returns(a.ref("AssignmentActionResult"))
896
936
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
897
- .handler(a.handler.function(assignmentAction)),
937
+ .handler(functionHandler("assignmentAction", assignmentAction)),
898
938
 
899
939
  retryImmediateAssignment: a
900
940
  .mutation()
@@ -906,13 +946,13 @@ const baseDefinitions = {
906
946
  })
907
947
  .returns(a.ref("AssignmentActionResult"))
908
948
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
909
- .handler(a.handler.function(assignmentAction)),
949
+ .handler(functionHandler("assignmentAction", assignmentAction)),
910
950
 
911
951
  listNewsroomProcedureDefinitions: a
912
952
  .query()
913
953
  .returns(a.json())
914
954
  .authorization((allow) => [allow.group(adminGroup)])
915
- .handler(a.handler.function(procedureAction)),
955
+ .handler(functionHandler("procedureAction", procedureAction)),
916
956
 
917
957
  getNewsroomProcedureDefinition: a
918
958
  .query()
@@ -922,7 +962,7 @@ const baseDefinitions = {
922
962
  })
923
963
  .returns(a.json())
924
964
  .authorization((allow) => [allow.group(adminGroup)])
925
- .handler(a.handler.function(procedureAction)),
965
+ .handler(functionHandler("procedureAction", procedureAction)),
926
966
 
927
967
  saveNewsroomProcedureDefinition: a
928
968
  .mutation()
@@ -931,7 +971,7 @@ const baseDefinitions = {
931
971
  })
932
972
  .returns(a.json())
933
973
  .authorization((allow) => [allow.group(adminGroup)])
934
- .handler(a.handler.function(procedureAction)),
974
+ .handler(functionHandler("procedureAction", procedureAction)),
935
975
 
936
976
  saveNewsroomProcedureVersionDraft: a
937
977
  .mutation()
@@ -940,7 +980,7 @@ const baseDefinitions = {
940
980
  })
941
981
  .returns(a.json())
942
982
  .authorization((allow) => [allow.group(adminGroup)])
943
- .handler(a.handler.function(procedureAction)),
983
+ .handler(functionHandler("procedureAction", procedureAction)),
944
984
 
945
985
  publishNewsroomProcedureVersion: a
946
986
  .mutation()
@@ -949,7 +989,7 @@ const baseDefinitions = {
949
989
  })
950
990
  .returns(a.json())
951
991
  .authorization((allow) => [allow.group(adminGroup)])
952
- .handler(a.handler.function(procedureAction)),
992
+ .handler(functionHandler("procedureAction", procedureAction)),
953
993
 
954
994
  startNewsroomProcedureRun: a
955
995
  .mutation()
@@ -964,7 +1004,7 @@ const baseDefinitions = {
964
1004
  })
965
1005
  .returns(a.json())
966
1006
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
967
- .handler(a.handler.function(procedureAction)),
1007
+ .handler(functionHandler("procedureAction", procedureAction)),
968
1008
 
969
1009
  getNewsroomProcedureRun: a
970
1010
  .query()
@@ -973,7 +1013,7 @@ const baseDefinitions = {
973
1013
  })
974
1014
  .returns(a.json())
975
1015
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
976
- .handler(a.handler.function(procedureAction)),
1016
+ .handler(functionHandler("procedureAction", procedureAction)),
977
1017
 
978
1018
  listNewsroomProcedureRunsByProcedure: a
979
1019
  .query()
@@ -982,7 +1022,7 @@ const baseDefinitions = {
982
1022
  })
983
1023
  .returns(a.json())
984
1024
  .authorization((allow) => [allow.groups(categoryWriteGroups)])
985
- .handler(a.handler.function(procedureAction)),
1025
+ .handler(functionHandler("procedureAction", procedureAction)),
986
1026
 
987
1027
  Assignment: modelWithoutSubscriptions({
988
1028
  id: a.id().required(),
@@ -1126,6 +1166,8 @@ const baseDefinitions = {
1126
1166
  error: a.json(),
1127
1167
  attempt: a.integer(),
1128
1168
  newsroomFeedKey: a.string(),
1169
+ usage: a.json(),
1170
+ costUsd: a.float(),
1129
1171
  })
1130
1172
  .secondaryIndexes((index) => [
1131
1173
  index("procedureId").sortKeys(["requestedAt"]).queryField("listProcedureRunsByProcedureAndRequestedAt"),
@@ -1138,6 +1180,74 @@ const baseDefinitions = {
1138
1180
  allow.group(adminGroup).to(authoringOperations),
1139
1181
  ]),
1140
1182
 
1183
+ /** A named "when X happens, run procedure Y" (PPY-9ff95b). Step 1 mirrors the monitoring router's procedureTriggers and starts nothing itself. */
1184
+ Automation: modelWithoutSubscriptions({
1185
+ id: a.id().required(),
1186
+ title: a.string().required(),
1187
+ description: a.string(),
1188
+ enabled: a.boolean().required(),
1189
+ trigger: a.json().required(),
1190
+ procedureKey: a.string().required(),
1191
+ inputTemplate: a.json(),
1192
+ limits: a.json(),
1193
+ createdBy: a.string(),
1194
+ createdAt: a.datetime().required(),
1195
+ updatedBy: a.string(),
1196
+ updatedAt: a.datetime().required(),
1197
+ })
1198
+ .authorization((allow) => [
1199
+ allow.group("editor").to(["read", "create", "update"]),
1200
+ allow.group(adminGroup).to(authoringOperations),
1201
+ ]),
1202
+
1203
+ /** A human review point raised by a step on any item (PPY-ab6a50). Review is not a story state. */
1204
+ ReviewRequest: modelWithoutSubscriptions({
1205
+ id: a.id().required(),
1206
+ subject: a.json().required(),
1207
+ mode: a.string().required(),
1208
+ reason: a.string().required(),
1209
+ ask: a.string(),
1210
+ raisedBy: a.string().required(),
1211
+ raisedAt: a.datetime().required(),
1212
+ deadline: a.datetime(),
1213
+ state: a.string().required(),
1214
+ answer: a.json(),
1215
+ links: a.json(),
1216
+ history: a.json(),
1217
+ appliedIn: a.json(),
1218
+ updatedAt: a.datetime().required(),
1219
+ })
1220
+ .authorization((allow) => [
1221
+ allow.group("editor").to(["read", "create", "update"]),
1222
+ allow.group(adminGroup).to(authoringOperations),
1223
+ ]),
1224
+
1225
+ /** One user's read mark on one review request; id is "<userKey>#<requestId>". */
1226
+ ReviewReadMark: modelWithoutSubscriptions({
1227
+ id: a.id().required(),
1228
+ requestId: a.string().required(),
1229
+ userKey: a.string().required(),
1230
+ readAt: a.datetime().required(),
1231
+ })
1232
+ .authorization((allow) => [
1233
+ allow.groups(["editor", adminGroup]).to(["read", "create", "update"]),
1234
+ ]),
1235
+
1236
+ /** Who is told about review requests: scope default, mode or automation. Changed by data, not code. */
1237
+ ReviewRecipientRule: modelWithoutSubscriptions({
1238
+ id: a.id().required(),
1239
+ scope: a.string().required(),
1240
+ key: a.string(),
1241
+ roles: a.string().array(),
1242
+ emails: a.string().array(),
1243
+ updatedBy: a.string(),
1244
+ updatedAt: a.datetime().required(),
1245
+ })
1246
+ .authorization((allow) => [
1247
+ allow.group("editor").to(["read"]),
1248
+ allow.group(adminGroup).to(authoringOperations),
1249
+ ]),
1250
+
1141
1251
  NewsroomSection: modelWithoutSubscriptions({
1142
1252
  id: a.id().required(),
1143
1253
  tenantId: a.string(),
@@ -1782,7 +1892,7 @@ const baseDefinitions = {
1782
1892
  updatedAt: a.datetime(),
1783
1893
  tags: a.hasMany("ItemTag", "itemId"),
1784
1894
  mediaAssets: a.hasMany("MediaAsset", "itemId"),
1785
- editionItems: a.hasMany("EditionItem", "itemId"),
1895
+ ...(includeEditions ? { editionItems: a.hasMany("EditionItem", "itemId") } : {}),
1786
1896
  })
1787
1897
  .secondaryIndexes((index) => [
1788
1898
  index("lineageId").sortKeys(["versionNumber"]).queryField("listItemsByLineageAndVersion"),
@@ -2105,21 +2215,26 @@ const baseDefinitions = {
2105
2215
  allow.guest().to(["read"]),
2106
2216
  allow.groups(contentWriteGroups),
2107
2217
  ]),
2218
+ ...editorialChecksSchemaDefinitions,
2219
+ ...monitoringViewSchemaDefinitions,
2220
+ ...automationViewSchemaDefinitions,
2108
2221
  };
2222
+ if (!includeEditions) {
2223
+ const mutableDefinitions = definitions as Record<string, unknown>;
2224
+ for (const modelName of OPTIONAL_MODEL_GROUPS.editions) delete mutableDefinitions[modelName];
2225
+ }
2226
+ return definitions;
2227
+ }
2109
2228
 
2110
- export const schema = a.schema(baseDefinitions).authorization((allow) => [
2111
- allow.resource(assignmentAction).to(["query", "mutate"]),
2112
- allow.resource(categoryAction),
2113
- allow.resource(contentActions),
2114
- allow.resource(manageUserRole),
2115
- allow.resource(modelAttachmentUpload),
2116
- allow.resource(newsroomSummary),
2117
- allow.resource(procedureAction),
2118
- ]);
2229
+ export function baseModelNames(excludedGroups: readonly OptionalModelGroup[] = []): string[] {
2230
+ return Object.keys(buildBaseDefinitions(!excludedGroups.includes("editions")));
2231
+ }
2119
2232
 
2120
- /** The deployed schema of a site that enables plugins: the base definitions plus what each plugin contributes (docs/plugins.md). */
2121
- export function schemaWithPlugins(pluginDefinitions: Record<string, any>) {
2122
- return a.schema({ ...baseDefinitions, ...pluginDefinitions } as typeof baseDefinitions).authorization((allow) => [
2233
+ const baseDefinitions = buildBaseDefinitions(true);
2234
+
2235
+ /** Schema-level function grants shared by every deployed schema, with or without plugins, so none can drop one. */
2236
+ function functionGrants(allow: any) {
2237
+ return [
2123
2238
  allow.resource(assignmentAction).to(["query", "mutate"]),
2124
2239
  allow.resource(categoryAction),
2125
2240
  allow.resource(contentActions),
@@ -2127,7 +2242,21 @@ export function schemaWithPlugins(pluginDefinitions: Record<string, any>) {
2127
2242
  allow.resource(modelAttachmentUpload),
2128
2243
  allow.resource(newsroomSummary),
2129
2244
  allow.resource(procedureAction),
2130
- ]);
2245
+ allow.resource(publicForms).to(["mutate"]),
2246
+ ];
2247
+ }
2248
+
2249
+ export const schema = a.schema(baseDefinitions).authorization(functionGrants);
2250
+
2251
+ /** The deployed schema of a site that enables plugins: the base definitions plus what each plugin contributes (docs/plugins.md). */
2252
+ export function schemaWithPlugins(pluginDefinitions: Record<string, any>) {
2253
+ return a.schema({ ...baseDefinitions, ...pluginDefinitions } as typeof baseDefinitions).authorization(functionGrants);
2254
+ }
2255
+
2256
+ /** The schema of a site that leaves optional model groups out of its first deploy. */
2257
+ export function schemaExcludingGroups(excludedGroups: readonly OptionalModelGroup[], pluginDefinitions: Record<string, any> = {}) {
2258
+ const definitions = buildBaseDefinitions(!excludedGroups.includes("editions")) as unknown as typeof baseDefinitions;
2259
+ return a.schema({ ...definitions, ...pluginDefinitions } as typeof baseDefinitions).authorization(functionGrants);
2131
2260
  }
2132
2261
 
2133
2262
  export type Schema = ClientSchema<typeof schema>;