@anthusai/papyrus 5.43.0-next.5 → 5.43.0-next.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/amplify/data/message-actions.js +68 -0
- package/amplify/data/message-actions.ts +70 -0
- package/amplify/data/resolvers/delete-own-message.js +30 -0
- package/amplify/data/resolvers/edit-message.js +33 -0
- package/amplify/data/resolvers/moderate-message.js +32 -0
- package/amplify/data/resolvers/post-message.js +68 -0
- package/amplify/data/resolvers/rename-thread.js +28 -0
- package/amplify/data/resource.js +34 -3
- package/amplify/data/resource.ts +35 -3
- package/amplify/data/schema.js +40 -5
- package/amplify/data/schema.ts +41 -5
- package/amplify/functions/category-action/handler.ts +53 -126
- package/amplify/functions/content-actions/handler.py +8 -0
- package/amplify/functions/content-actions/requirements.txt +2 -0
- package/amplify/functions/content-actions/resource.js +1 -1
- package/amplify/functions/content-actions/resource.ts +1 -1
- package/amplify/functions/model-attachment-upload/handler.ts +1 -0
- package/amplify/functions/monitoring-view/schema.js +16 -0
- package/amplify/functions/monitoring-view/schema.ts +16 -0
- package/amplify/functions/procedure-action/handler.ts +2 -10
- package/amplify/functions/proposal-actions/proposals.py +20 -3
- package/amplify/functions/shared/reference-curation-metadata.ts +21 -29
- package/amplify/plugins/reader-steering/function/handler.py +1 -3
- package/amplify/plugins/reader-steering/function/moderation.py +19 -0
- package/app/api/newsroom/source-frameable/route.ts +12 -0
- package/app/api/newsroom/source-icon/route.ts +20 -0
- package/app/newsroom/[section]/[...selection]/page.tsx +2 -0
- package/app/newsroom/[section]/page.tsx +1 -0
- package/bin/papyrus-app.mjs +12 -1
- package/bin/papyrus-infra.mjs +21 -1
- package/components/auto-accepted-badge.tsx +21 -0
- package/components/conversation-context.tsx +79 -0
- package/components/conversation-provider.tsx +24 -0
- package/components/conversation-thread.tsx +302 -0
- package/components/conversations-memory-source.ts +83 -0
- package/components/conversations-network-source.ts +52 -0
- package/components/conversations-page.tsx +14 -0
- package/components/conversations-source.ts +36 -0
- package/components/conversations-view.tsx +680 -0
- package/components/decision-control.tsx +307 -0
- package/components/dev-sandbox-editor-sign-in.tsx +2 -2
- package/components/list-detail-layout.tsx +44 -0
- package/components/markdown-context.tsx +412 -0
- package/components/monitoring-overview-view.tsx +143 -21
- package/components/monitoring-panel.tsx +64 -4
- package/components/needs-me-bodies.tsx +302 -0
- package/components/needs-me-detail.tsx +24 -0
- package/components/needs-me-feed.tsx +584 -0
- package/components/needs-me-reference-detail.tsx +79 -0
- package/components/needs-me-shared.tsx +48 -0
- package/components/news-desk-client-provider.tsx +24 -3
- package/components/news-desk-page.tsx +2 -1
- package/components/news-desk-taxonomy-client.ts +457 -81
- package/components/newsroom-access-gate.tsx +13 -20
- package/components/newsroom-article-editor.tsx +10 -4
- package/components/newsroom-board-skeleton.tsx +20 -0
- package/components/newsroom-board-view.tsx +2 -6
- package/components/newsroom-client-shell.tsx +2 -1
- package/components/newsroom-ops-overview.tsx +88 -73
- package/components/newsroom-ops-shell.tsx +8 -28
- package/components/newsroom-organizer.css +137 -4
- package/components/newsroom-references-view.tsx +328 -211
- package/components/notification-cards.tsx +370 -0
- package/components/notification-center.tsx +374 -213
- package/components/papyrus-console-shell.tsx +2 -1
- package/components/proposals-panel.tsx +21 -24
- package/components/proposals-view.tsx +8 -6
- package/components/reader-auth-control.tsx +3 -1
- package/components/reference-capture-client.ts +138 -0
- package/components/reference-capture-panel.tsx +268 -0
- package/components/reference-conversation.tsx +48 -0
- package/components/reference-feed.tsx +525 -0
- package/components/reference-review-card.tsx +62 -197
- package/components/reference-source-preview.tsx +27 -5
- package/components/reference-stories.tsx +34 -0
- package/components/references-page-loading.tsx +67 -0
- package/components/references-prefetch.ts +52 -0
- package/components/story-reporting-trail-client.ts +48 -10
- package/components/story-reporting-trail.tsx +32 -13
- package/components/topic-steering-workspace.tsx +94 -1225
- package/components/ui/auto-grow-textarea.tsx +18 -0
- package/components/use-conversation.ts +118 -0
- package/components/use-feed-preferences.ts +33 -0
- package/components/use-media-query.ts +16 -0
- package/components/use-reference-preview-attachments.ts +101 -0
- package/components/use-reference-ratings.ts +192 -0
- package/infra/amplify-app-shell.js +18 -2
- package/infra/amplify-app-shell.ts +18 -2
- package/infra/chat-stack.js +222 -0
- package/infra/chat-stack.ts +250 -0
- package/infra/chat.test.js +142 -0
- package/infra/chat.test.ts +151 -0
- package/infra/index.js +1 -0
- package/infra/site-config.js +58 -1
- package/infra/site-config.ts +78 -1
- package/lib/category-repository.ts +20 -39
- package/lib/console-chat-client.ts +8 -178
- package/lib/content-actions-client.ts +20 -0
- package/lib/conversation-feed.ts +96 -0
- package/lib/conversation.ts +225 -0
- package/lib/cyclotron-suggestions.ts +18 -36
- package/lib/local-preview-feed-fixture.ts +63 -0
- package/lib/local-preview-seed.ts +40 -29
- package/lib/local-preview-synthetic-rejects.ts +41 -0
- package/lib/monitoring-client.ts +29 -2
- package/lib/monitoring-overview.ts +52 -1
- package/lib/monitoring-paging.ts +58 -0
- package/lib/needs-me-items.ts +289 -0
- package/lib/needs-me-ranking.ts +302 -0
- package/lib/newsroom-all-pages.ts +21 -0
- package/lib/newsroom-board.ts +10 -1
- package/lib/newsroom-chat-identity.ts +2 -1
- package/lib/newsroom-demo-dashboard.ts +0 -7
- package/lib/newsroom-index-filters.ts +18 -0
- package/lib/newsroom-nav.ts +1 -1
- package/lib/newsroom-organizer-nav.ts +2 -1
- package/lib/newsroom-references.ts +25 -1
- package/lib/notification-feed.ts +212 -0
- package/lib/post-message.ts +54 -0
- package/lib/proposals-admin.ts +2 -2
- package/lib/proposals-client.ts +29 -0
- package/lib/reader-subject.ts +3 -2
- package/lib/reference-capture.ts +294 -0
- package/lib/reference-feed-cache.ts +170 -0
- package/lib/reference-feed-keys.ts +69 -0
- package/lib/reference-feed-ranking.ts +153 -0
- package/lib/reference-policy.ts +95 -11
- package/lib/reference-preview.ts +112 -0
- package/lib/reference-review-details.ts +21 -57
- package/lib/relevance-decisions.ts +6 -2
- package/lib/review-client.ts +71 -5
- package/lib/review-drafts.ts +277 -0
- package/lib/review-fixture.ts +57 -3
- package/lib/review-requests.ts +89 -24
- package/lib/semantic-graph.ts +1 -1
- package/lib/site-brand.ts +2 -0
- package/lib/source-frameable.ts +77 -0
- package/lib/source-icon.ts +104 -0
- package/lib/staff-groups.ts +23 -0
- package/lib/staging-gate.ts +2 -2
- package/lib/story-reporting-trail.ts +61 -4
- package/package.json +55 -2
- package/routes.manifest.json +23 -1
- package/components/newsroom-overview-skeleton.tsx +0 -25
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { a } from "@aws-amplify/backend";
|
|
2
|
+
/**
|
|
3
|
+
* Messages belong to their author, and the backend says so. The browser cannot create, edit or delete a Message through the
|
|
4
|
+
* model (editors and admins only read it); it calls these four mutations, whose resolvers stamp the author from the signed-in
|
|
5
|
+
* identity and check ownership against the stored `authorSub` in the same DynamoDB write. `renameThread` does the same for a
|
|
6
|
+
* conversation's title. Functions and IAM callers (the router, procedures, the console responder, email, Slack) write the
|
|
7
|
+
* model directly with their own grants, as before.
|
|
8
|
+
*
|
|
9
|
+
* Each resolver is one self-contained file (AppSync takes a single file and offers `@aws-appsync/utils` only).
|
|
10
|
+
*/
|
|
11
|
+
const people = (allow) => [allow.group("editor"), allow.group("admin")];
|
|
12
|
+
const adminsOnly = (allow) => [allow.group("admin")];
|
|
13
|
+
const onMessages = (entry) => a.handler.custom({ dataSource: a.ref("Message"), entry });
|
|
14
|
+
const onThreads = (entry) => a.handler.custom({ dataSource: a.ref("MessageThread"), entry });
|
|
15
|
+
export const messageActionsSchemaDefinitions = {
|
|
16
|
+
postMessage: a
|
|
17
|
+
.mutation()
|
|
18
|
+
.arguments({
|
|
19
|
+
id: a.id().required(),
|
|
20
|
+
threadId: a.id().required(),
|
|
21
|
+
content: a.string(),
|
|
22
|
+
summary: a.string(),
|
|
23
|
+
parentMessageId: a.id(),
|
|
24
|
+
sequenceNumber: a.integer(),
|
|
25
|
+
messageKind: a.string().required(),
|
|
26
|
+
messageDomain: a.string().required(),
|
|
27
|
+
messageType: a.string(),
|
|
28
|
+
role: a.string(),
|
|
29
|
+
source: a.string(),
|
|
30
|
+
authorLabel: a.string(),
|
|
31
|
+
semanticLayer: a.string(),
|
|
32
|
+
searchVisibility: a.string(),
|
|
33
|
+
responseTarget: a.string(),
|
|
34
|
+
responseStatus: a.string(),
|
|
35
|
+
responseOwner: a.string(),
|
|
36
|
+
responseStartedAt: a.datetime(),
|
|
37
|
+
responseCompletedAt: a.datetime(),
|
|
38
|
+
metadata: a.json(),
|
|
39
|
+
newsroomFeedKey: a.string(),
|
|
40
|
+
})
|
|
41
|
+
.returns(a.ref("Message"))
|
|
42
|
+
.authorization(people)
|
|
43
|
+
.handler(onMessages("./resolvers/post-message.js")),
|
|
44
|
+
editMessage: a
|
|
45
|
+
.mutation()
|
|
46
|
+
.arguments({ id: a.id().required(), content: a.string().required(), summary: a.string() })
|
|
47
|
+
.returns(a.ref("Message"))
|
|
48
|
+
.authorization(people)
|
|
49
|
+
.handler(onMessages("./resolvers/edit-message.js")),
|
|
50
|
+
deleteOwnMessage: a
|
|
51
|
+
.mutation()
|
|
52
|
+
.arguments({ id: a.id().required() })
|
|
53
|
+
.returns(a.ref("Message"))
|
|
54
|
+
.authorization(people)
|
|
55
|
+
.handler(onMessages("./resolvers/delete-own-message.js")),
|
|
56
|
+
moderateMessage: a
|
|
57
|
+
.mutation()
|
|
58
|
+
.arguments({ id: a.id().required() })
|
|
59
|
+
.returns(a.ref("Message"))
|
|
60
|
+
.authorization(adminsOnly)
|
|
61
|
+
.handler(onMessages("./resolvers/moderate-message.js")),
|
|
62
|
+
renameThread: a
|
|
63
|
+
.mutation()
|
|
64
|
+
.arguments({ id: a.id().required(), title: a.string().required() })
|
|
65
|
+
.returns(a.ref("MessageThread"))
|
|
66
|
+
.authorization(people)
|
|
67
|
+
.handler(onThreads("./resolvers/rename-thread.js")),
|
|
68
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { a } from "@aws-amplify/backend";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Messages belong to their author, and the backend says so. The browser cannot create, edit or delete a Message through the
|
|
5
|
+
* model (editors and admins only read it); it calls these four mutations, whose resolvers stamp the author from the signed-in
|
|
6
|
+
* identity and check ownership against the stored `authorSub` in the same DynamoDB write. `renameThread` does the same for a
|
|
7
|
+
* conversation's title. Functions and IAM callers (the router, procedures, the console responder, email, Slack) write the
|
|
8
|
+
* model directly with their own grants, as before.
|
|
9
|
+
*
|
|
10
|
+
* Each resolver is one self-contained file (AppSync takes a single file and offers `@aws-appsync/utils` only).
|
|
11
|
+
*/
|
|
12
|
+
const people = (allow: any) => [allow.group("editor"), allow.group("admin")];
|
|
13
|
+
const adminsOnly = (allow: any) => [allow.group("admin")];
|
|
14
|
+
const onMessages = (entry: string) => a.handler.custom({ dataSource: a.ref("Message"), entry });
|
|
15
|
+
const onThreads = (entry: string) => a.handler.custom({ dataSource: a.ref("MessageThread"), entry });
|
|
16
|
+
|
|
17
|
+
export const messageActionsSchemaDefinitions = {
|
|
18
|
+
postMessage: a
|
|
19
|
+
.mutation()
|
|
20
|
+
.arguments({
|
|
21
|
+
id: a.id().required(),
|
|
22
|
+
threadId: a.id().required(),
|
|
23
|
+
content: a.string(),
|
|
24
|
+
summary: a.string(),
|
|
25
|
+
parentMessageId: a.id(),
|
|
26
|
+
sequenceNumber: a.integer(),
|
|
27
|
+
messageKind: a.string().required(),
|
|
28
|
+
messageDomain: a.string().required(),
|
|
29
|
+
messageType: a.string(),
|
|
30
|
+
role: a.string(),
|
|
31
|
+
source: a.string(),
|
|
32
|
+
authorLabel: a.string(),
|
|
33
|
+
semanticLayer: a.string(),
|
|
34
|
+
searchVisibility: a.string(),
|
|
35
|
+
responseTarget: a.string(),
|
|
36
|
+
responseStatus: a.string(),
|
|
37
|
+
responseOwner: a.string(),
|
|
38
|
+
responseStartedAt: a.datetime(),
|
|
39
|
+
responseCompletedAt: a.datetime(),
|
|
40
|
+
metadata: a.json(),
|
|
41
|
+
newsroomFeedKey: a.string(),
|
|
42
|
+
})
|
|
43
|
+
.returns(a.ref("Message"))
|
|
44
|
+
.authorization(people)
|
|
45
|
+
.handler(onMessages("./resolvers/post-message.js")),
|
|
46
|
+
editMessage: a
|
|
47
|
+
.mutation()
|
|
48
|
+
.arguments({ id: a.id().required(), content: a.string().required(), summary: a.string() })
|
|
49
|
+
.returns(a.ref("Message"))
|
|
50
|
+
.authorization(people)
|
|
51
|
+
.handler(onMessages("./resolvers/edit-message.js")),
|
|
52
|
+
deleteOwnMessage: a
|
|
53
|
+
.mutation()
|
|
54
|
+
.arguments({ id: a.id().required() })
|
|
55
|
+
.returns(a.ref("Message"))
|
|
56
|
+
.authorization(people)
|
|
57
|
+
.handler(onMessages("./resolvers/delete-own-message.js")),
|
|
58
|
+
moderateMessage: a
|
|
59
|
+
.mutation()
|
|
60
|
+
.arguments({ id: a.id().required() })
|
|
61
|
+
.returns(a.ref("Message"))
|
|
62
|
+
.authorization(adminsOnly)
|
|
63
|
+
.handler(onMessages("./resolvers/moderate-message.js")),
|
|
64
|
+
renameThread: a
|
|
65
|
+
.mutation()
|
|
66
|
+
.arguments({ id: a.id().required(), title: a.string().required() })
|
|
67
|
+
.returns(a.ref("MessageThread"))
|
|
68
|
+
.authorization(people)
|
|
69
|
+
.handler(onThreads("./resolvers/rename-thread.js")),
|
|
70
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// deleteOwnMessage: the author deletes their own Message. A soft delete: the Message stays (replies keep their place) marked
|
|
2
|
+
// deleted, with when and by whom. Nothing is removed.
|
|
3
|
+
import { util } from "@aws-appsync/utils";
|
|
4
|
+
import * as ddb from "@aws-appsync/utils/dynamodb";
|
|
5
|
+
|
|
6
|
+
export function request(ctx) {
|
|
7
|
+
const identity = ctx.identity;
|
|
8
|
+
if (!identity || !identity.sub) util.error("Sign in to delete a message.", "Unauthorized");
|
|
9
|
+
const now = util.time.nowISO8601();
|
|
10
|
+
return ddb.update({
|
|
11
|
+
key: { id: ctx.args.id },
|
|
12
|
+
update: {
|
|
13
|
+
status: ddb.operations.replace("deleted"),
|
|
14
|
+
deletedAt: ddb.operations.replace(now),
|
|
15
|
+
deletedBySub: ddb.operations.replace(identity.sub),
|
|
16
|
+
updatedAt: ddb.operations.replace(now),
|
|
17
|
+
},
|
|
18
|
+
condition: { authorSub: { eq: identity.sub }, status: { ne: "deleted" } },
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function response(ctx) {
|
|
23
|
+
if (ctx.error) {
|
|
24
|
+
if (ctx.error.type === "DynamoDB:ConditionalCheckFailedException") {
|
|
25
|
+
util.error("Only the author can delete their own message, and it may already be deleted.", "Unauthorized");
|
|
26
|
+
}
|
|
27
|
+
util.error(ctx.error.message, ctx.error.type);
|
|
28
|
+
}
|
|
29
|
+
return ctx.result;
|
|
30
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// editMessage: a person changes the text of their own Message, and no one else's. The condition is checked by DynamoDB against the
|
|
2
|
+
// stored authorSub in the same write, so there is no window between the check and the change. A deleted Message cannot be edited.
|
|
3
|
+
// Authorship cannot be reassigned: the update never touches authorSub.
|
|
4
|
+
import { util } from "@aws-appsync/utils";
|
|
5
|
+
import * as ddb from "@aws-appsync/utils/dynamodb";
|
|
6
|
+
|
|
7
|
+
export function request(ctx) {
|
|
8
|
+
const identity = ctx.identity;
|
|
9
|
+
if (!identity || !identity.sub) util.error("Sign in to edit a message.", "Unauthorized");
|
|
10
|
+
const content = typeof ctx.args.content === "string" ? ctx.args.content.trim() : "";
|
|
11
|
+
if (!content) util.error("A message cannot be empty.", "BadRequest");
|
|
12
|
+
const now = util.time.nowISO8601();
|
|
13
|
+
return ddb.update({
|
|
14
|
+
key: { id: ctx.args.id },
|
|
15
|
+
update: {
|
|
16
|
+
content: ddb.operations.replace(content),
|
|
17
|
+
summary: ddb.operations.replace(ctx.args.summary ? ctx.args.summary : content.slice(0, 120)),
|
|
18
|
+
editedAt: ddb.operations.replace(now),
|
|
19
|
+
updatedAt: ddb.operations.replace(now),
|
|
20
|
+
},
|
|
21
|
+
condition: { authorSub: { eq: identity.sub }, status: { ne: "deleted" } },
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function response(ctx) {
|
|
26
|
+
if (ctx.error) {
|
|
27
|
+
if (ctx.error.type === "DynamoDB:ConditionalCheckFailedException") {
|
|
28
|
+
util.error("Only the author can edit a message, and a deleted message cannot be edited.", "Unauthorized");
|
|
29
|
+
}
|
|
30
|
+
util.error(ctx.error.message, ctx.error.type);
|
|
31
|
+
}
|
|
32
|
+
return ctx.result;
|
|
33
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// moderateMessage: an admin removes anyone's Message. The same soft delete as the author's, with no change to the text, and only
|
|
2
|
+
// for the admin group (checked here as well as by the mutation's authorization).
|
|
3
|
+
import { util } from "@aws-appsync/utils";
|
|
4
|
+
import * as ddb from "@aws-appsync/utils/dynamodb";
|
|
5
|
+
|
|
6
|
+
export function request(ctx) {
|
|
7
|
+
const identity = ctx.identity;
|
|
8
|
+
if (!identity || !identity.sub) util.error("Sign in to moderate a message.", "Unauthorized");
|
|
9
|
+
const groups = identity.groups || [];
|
|
10
|
+
if (groups.indexOf("admin") < 0) util.error("Only an admin can delete someone else's message.", "Unauthorized");
|
|
11
|
+
const now = util.time.nowISO8601();
|
|
12
|
+
return ddb.update({
|
|
13
|
+
key: { id: ctx.args.id },
|
|
14
|
+
update: {
|
|
15
|
+
status: ddb.operations.replace("deleted"),
|
|
16
|
+
deletedAt: ddb.operations.replace(now),
|
|
17
|
+
deletedBySub: ddb.operations.replace(identity.sub),
|
|
18
|
+
updatedAt: ddb.operations.replace(now),
|
|
19
|
+
},
|
|
20
|
+
condition: { id: { attributeExists: true }, status: { ne: "deleted" } },
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function response(ctx) {
|
|
25
|
+
if (ctx.error) {
|
|
26
|
+
if (ctx.error.type === "DynamoDB:ConditionalCheckFailedException") {
|
|
27
|
+
util.error("That message does not exist or is already deleted.", "NotFound");
|
|
28
|
+
}
|
|
29
|
+
util.error(ctx.error.message, ctx.error.type);
|
|
30
|
+
}
|
|
31
|
+
return ctx.result;
|
|
32
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// postMessage: the only way a person's Message is created. The author is the signed-in user (the identity's sub), whatever the
|
|
2
|
+
// client sends: the mutation has no author argument, and a label is only a label. One DynamoDB PutItem that refuses to replace an
|
|
3
|
+
// existing Message (ids are derived from the sequence number, so a lost race comes back as a conflict the caller retries).
|
|
4
|
+
import { util } from "@aws-appsync/utils";
|
|
5
|
+
import * as ddb from "@aws-appsync/utils/dynamodb";
|
|
6
|
+
|
|
7
|
+
function clean(value) {
|
|
8
|
+
const out = {};
|
|
9
|
+
const keys = Object.keys(value);
|
|
10
|
+
for (let index = 0; index < keys.length; index++) {
|
|
11
|
+
const key = keys[index];
|
|
12
|
+
if (value[key] !== null && value[key] !== undefined) out[key] = value[key];
|
|
13
|
+
}
|
|
14
|
+
return out;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function request(ctx) {
|
|
18
|
+
const identity = ctx.identity;
|
|
19
|
+
if (!identity || !identity.sub) util.error("Sign in to post a message.", "Unauthorized");
|
|
20
|
+
const args = ctx.args;
|
|
21
|
+
const content = typeof args.content === "string" ? args.content.trim() : "";
|
|
22
|
+
// A placeholder waiting for a responder (PENDING) may start empty; any other message needs text.
|
|
23
|
+
if (!content && args.responseStatus !== "PENDING") util.error("A message cannot be empty.", "BadRequest");
|
|
24
|
+
if (!args.id || !args.threadId) util.error("A message needs an id and a conversation.", "BadRequest");
|
|
25
|
+
const now = util.time.nowISO8601();
|
|
26
|
+
const claims = identity.claims || {};
|
|
27
|
+
const email = typeof claims.email === "string" ? claims.email : "";
|
|
28
|
+
const label = typeof args.authorLabel === "string" && args.authorLabel.trim() ? args.authorLabel.trim() : email ? email : "editor";
|
|
29
|
+
const item = clean({
|
|
30
|
+
__typename: "Message",
|
|
31
|
+
id: args.id,
|
|
32
|
+
messageKind: args.messageKind,
|
|
33
|
+
messageDomain: args.messageDomain,
|
|
34
|
+
status: "active",
|
|
35
|
+
summary: args.summary ? args.summary : content.slice(0, 120),
|
|
36
|
+
source: args.source,
|
|
37
|
+
authorSub: identity.sub,
|
|
38
|
+
authorLabel: label,
|
|
39
|
+
threadId: args.threadId,
|
|
40
|
+
parentMessageId: args.parentMessageId,
|
|
41
|
+
sequenceNumber: args.sequenceNumber,
|
|
42
|
+
role: args.role ? args.role : "human",
|
|
43
|
+
messageType: args.messageType,
|
|
44
|
+
content: content,
|
|
45
|
+
semanticLayer: args.semanticLayer,
|
|
46
|
+
searchVisibility: args.searchVisibility,
|
|
47
|
+
responseTarget: args.responseTarget,
|
|
48
|
+
responseStatus: args.responseStatus ? args.responseStatus : "COMPLETED",
|
|
49
|
+
responseOwner: args.responseOwner,
|
|
50
|
+
responseStartedAt: args.responseStartedAt,
|
|
51
|
+
responseCompletedAt: args.responseCompletedAt,
|
|
52
|
+
metadata: args.metadata,
|
|
53
|
+
createdAt: now,
|
|
54
|
+
updatedAt: now,
|
|
55
|
+
newsroomFeedKey: args.newsroomFeedKey,
|
|
56
|
+
});
|
|
57
|
+
return ddb.put({ key: { id: args.id }, item: item, condition: { id: { attributeExists: false } } });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function response(ctx) {
|
|
61
|
+
if (ctx.error) {
|
|
62
|
+
if (ctx.error.type === "DynamoDB:ConditionalCheckFailedException") {
|
|
63
|
+
util.error("A message with this id already exists (conditional check failed); try again.", "Conflict");
|
|
64
|
+
}
|
|
65
|
+
util.error(ctx.error.message, ctx.error.type);
|
|
66
|
+
}
|
|
67
|
+
return ctx.result;
|
|
68
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// renameThread: the person who started a conversation, or an admin, gives it a new title. The browser's own update of a thread
|
|
2
|
+
// cannot change the title (the field is read and create only), so this is the one way. Nothing else about the thread changes.
|
|
3
|
+
import { util } from "@aws-appsync/utils";
|
|
4
|
+
import * as ddb from "@aws-appsync/utils/dynamodb";
|
|
5
|
+
|
|
6
|
+
export function request(ctx) {
|
|
7
|
+
const identity = ctx.identity;
|
|
8
|
+
if (!identity || !identity.sub) util.error("Sign in to rename a conversation.", "Unauthorized");
|
|
9
|
+
const title = typeof ctx.args.title === "string" ? ctx.args.title.trim() : "";
|
|
10
|
+
if (!title) util.error("A title cannot be empty.", "BadRequest");
|
|
11
|
+
const groups = identity.groups || [];
|
|
12
|
+
const isAdmin = groups.indexOf("admin") >= 0;
|
|
13
|
+
return ddb.update({
|
|
14
|
+
key: { id: ctx.args.id },
|
|
15
|
+
update: { title: ddb.operations.replace(title.slice(0, 120)) },
|
|
16
|
+
condition: isAdmin ? { id: { attributeExists: true } } : { createdBySub: { eq: identity.sub } },
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function response(ctx) {
|
|
21
|
+
if (ctx.error) {
|
|
22
|
+
if (ctx.error.type === "DynamoDB:ConditionalCheckFailedException") {
|
|
23
|
+
util.error("Only the person who started this conversation, or an admin, can rename it.", "Unauthorized");
|
|
24
|
+
}
|
|
25
|
+
util.error(ctx.error.message, ctx.error.type);
|
|
26
|
+
}
|
|
27
|
+
return ctx.result;
|
|
28
|
+
}
|
package/amplify/data/resource.js
CHANGED
|
@@ -247,8 +247,6 @@ const schema = a.schema({
|
|
|
247
247
|
referenceId: a.id().required(),
|
|
248
248
|
status: a.string().required(),
|
|
249
249
|
reasonCode: a.string(),
|
|
250
|
-
messageId: a.id(),
|
|
251
|
-
relationId: a.id(),
|
|
252
250
|
}),
|
|
253
251
|
ReferenceQualityActionResult: a.customType({
|
|
254
252
|
ok: a.boolean().required(),
|
|
@@ -603,6 +601,12 @@ const schema = a.schema({
|
|
|
603
601
|
.returns(a.json())
|
|
604
602
|
.authorization((allow) => [allow.groups(contentWriteGroups)])
|
|
605
603
|
.handler(functionHandler("contentActions", contentActions)),
|
|
604
|
+
correctReferenceCapture: a
|
|
605
|
+
.mutation()
|
|
606
|
+
.arguments({ input: a.json().required() })
|
|
607
|
+
.returns(a.json())
|
|
608
|
+
.authorization((allow) => [allow.groups(contentWriteGroups)])
|
|
609
|
+
.handler(functionHandler("contentActions", contentActions)),
|
|
606
610
|
saveItemDraft: a
|
|
607
611
|
.mutation()
|
|
608
612
|
.arguments({ input: a.json().required() })
|
|
@@ -1563,8 +1567,26 @@ const schema = a.schema({
|
|
|
1563
1567
|
curationStatusUpdatedAt: a.datetime(),
|
|
1564
1568
|
curationStatusUpdatedBy: a.string(),
|
|
1565
1569
|
curationStatusReason: a.string(),
|
|
1570
|
+
curationReasonCode: a.string(),
|
|
1571
|
+
curationActorKind: a.string(),
|
|
1572
|
+
curationSectionId: a.string(),
|
|
1573
|
+
curationShareable: a.boolean(),
|
|
1574
|
+
curationDelegation: a.json(),
|
|
1575
|
+
curationDecisionRelationId: a.string(),
|
|
1566
1576
|
newsroomFeedKey: a.string(),
|
|
1567
1577
|
reviewedFeedKey: a.string(),
|
|
1578
|
+
discoveredByMonitorId: a.string(),
|
|
1579
|
+
discoveryDetails: a.json(),
|
|
1580
|
+
discoveryRule: a.json(),
|
|
1581
|
+
// The References page reads the feed through two indexes (docs/reference-feed-indexes.md). `feedStateKey` is
|
|
1582
|
+
// "<corpusId>#unrated" or "<corpusId>#rated" for a current, not archived Reference (null otherwise: it is in no feed).
|
|
1583
|
+
// `predictionSortKey` orders Best bets, `feedArrivalAt` orders Newest. The prediction is the Cyclotron's ORIGINAL
|
|
1584
|
+
// P(accept), written once, and never rewritten by a vote.
|
|
1585
|
+
feedStateKey: a.string(),
|
|
1586
|
+
feedArrivalAt: a.datetime(),
|
|
1587
|
+
predictedAcceptProbability: a.float(),
|
|
1588
|
+
predictionDecidedAt: a.datetime(),
|
|
1589
|
+
predictionSortKey: a.string(),
|
|
1568
1590
|
updatedAt: a.datetime(),
|
|
1569
1591
|
})
|
|
1570
1592
|
.secondaryIndexes((index) => [
|
|
@@ -1577,6 +1599,9 @@ const schema = a.schema({
|
|
|
1577
1599
|
index("curationStatus").sortKeys(["curationStatusUpdatedAt"]).queryField("listReferencesByCurationStatusAndUpdatedAt"),
|
|
1578
1600
|
index("curationStatusKey").sortKeys(["curationStatusUpdatedAt"]).queryField("listReferencesByCurationStatusKeyAndUpdatedAt"),
|
|
1579
1601
|
index("reviewedFeedKey").sortKeys(["updatedAt"]).queryField("listReferencesByReviewedFeedAndUpdatedAt"),
|
|
1602
|
+
index("discoveredByMonitorId").sortKeys(["createdAt"]).queryField("listReferencesByMonitorAndCreatedAt"),
|
|
1603
|
+
index("feedStateKey").sortKeys(["predictionSortKey"]).queryField("listReferencesByFeedStateAndPrediction"),
|
|
1604
|
+
index("feedStateKey").sortKeys(["feedArrivalAt"]).queryField("listReferencesByFeedStateAndArrival"),
|
|
1580
1605
|
])
|
|
1581
1606
|
.authorization((allow) => [
|
|
1582
1607
|
allow.groups(categoryWriteGroups).to(["read"]),
|
|
@@ -1664,6 +1689,9 @@ const schema = a.schema({
|
|
|
1664
1689
|
authorSub: a.string(),
|
|
1665
1690
|
authorUserProfileId: a.id(),
|
|
1666
1691
|
authorLabel: a.string(),
|
|
1692
|
+
editedAt: a.datetime(),
|
|
1693
|
+
deletedAt: a.datetime(),
|
|
1694
|
+
deletedBySub: a.string(),
|
|
1667
1695
|
threadId: a.id(),
|
|
1668
1696
|
parentMessageId: a.id(),
|
|
1669
1697
|
sequenceNumber: a.integer(),
|
|
@@ -1698,7 +1726,10 @@ const schema = a.schema({
|
|
|
1698
1726
|
index("searchVisibility").sortKeys(["createdAt"]).name("messagesBySearchVisibilityCreatedAt").queryField("listMessagesBySearchVisibilityAndCreatedAt"),
|
|
1699
1727
|
])
|
|
1700
1728
|
.authorization((allow) => [
|
|
1701
|
-
|
|
1729
|
+
// Messages belong to their author, and the backend stamps the author: people read Messages here and write them only through
|
|
1730
|
+
// postMessage, editMessage, deleteOwnMessage and moderateMessage (message-actions.ts). Functions and IAM callers write directly.
|
|
1731
|
+
allow.group("editor").to(["read"]),
|
|
1732
|
+
allow.group(adminGroup).to(["read"]),
|
|
1702
1733
|
allow.authenticated("identityPool").to(["read", "create", "update"]),
|
|
1703
1734
|
]),
|
|
1704
1735
|
MessageThread: a
|
package/amplify/data/resource.ts
CHANGED
|
@@ -267,8 +267,6 @@ const schema = a.schema({
|
|
|
267
267
|
referenceId: a.id().required(),
|
|
268
268
|
status: a.string().required(),
|
|
269
269
|
reasonCode: a.string(),
|
|
270
|
-
messageId: a.id(),
|
|
271
|
-
relationId: a.id(),
|
|
272
270
|
}),
|
|
273
271
|
|
|
274
272
|
ReferenceQualityActionResult: a.customType({
|
|
@@ -657,6 +655,13 @@ const schema = a.schema({
|
|
|
657
655
|
.authorization((allow) => [allow.groups(contentWriteGroups)])
|
|
658
656
|
.handler(functionHandler("contentActions", contentActions)),
|
|
659
657
|
|
|
658
|
+
correctReferenceCapture: a
|
|
659
|
+
.mutation()
|
|
660
|
+
.arguments({ input: a.json().required() })
|
|
661
|
+
.returns(a.json())
|
|
662
|
+
.authorization((allow) => [allow.groups(contentWriteGroups)])
|
|
663
|
+
.handler(functionHandler("contentActions", contentActions)),
|
|
664
|
+
|
|
660
665
|
saveItemDraft: a
|
|
661
666
|
.mutation()
|
|
662
667
|
.arguments({ input: a.json().required() })
|
|
@@ -1675,8 +1680,26 @@ const schema = a.schema({
|
|
|
1675
1680
|
curationStatusUpdatedAt: a.datetime(),
|
|
1676
1681
|
curationStatusUpdatedBy: a.string(),
|
|
1677
1682
|
curationStatusReason: a.string(),
|
|
1683
|
+
curationReasonCode: a.string(),
|
|
1684
|
+
curationActorKind: a.string(),
|
|
1685
|
+
curationSectionId: a.string(),
|
|
1686
|
+
curationShareable: a.boolean(),
|
|
1687
|
+
curationDelegation: a.json(),
|
|
1688
|
+
curationDecisionRelationId: a.string(),
|
|
1678
1689
|
newsroomFeedKey: a.string(),
|
|
1679
1690
|
reviewedFeedKey: a.string(),
|
|
1691
|
+
discoveredByMonitorId: a.string(),
|
|
1692
|
+
discoveryDetails: a.json(),
|
|
1693
|
+
discoveryRule: a.json(),
|
|
1694
|
+
// The References page reads the feed through two indexes (docs/reference-feed-indexes.md). `feedStateKey` is
|
|
1695
|
+
// "<corpusId>#unrated" or "<corpusId>#rated" for a current, not archived Reference (null otherwise: it is in no feed).
|
|
1696
|
+
// `predictionSortKey` orders Best bets, `feedArrivalAt` orders Newest. The prediction is the Cyclotron's ORIGINAL
|
|
1697
|
+
// P(accept), written once, and never rewritten by a vote.
|
|
1698
|
+
feedStateKey: a.string(),
|
|
1699
|
+
feedArrivalAt: a.datetime(),
|
|
1700
|
+
predictedAcceptProbability: a.float(),
|
|
1701
|
+
predictionDecidedAt: a.datetime(),
|
|
1702
|
+
predictionSortKey: a.string(),
|
|
1680
1703
|
updatedAt: a.datetime(),
|
|
1681
1704
|
})
|
|
1682
1705
|
.secondaryIndexes((index) => [
|
|
@@ -1689,6 +1712,9 @@ const schema = a.schema({
|
|
|
1689
1712
|
index("curationStatus").sortKeys(["curationStatusUpdatedAt"]).queryField("listReferencesByCurationStatusAndUpdatedAt"),
|
|
1690
1713
|
index("curationStatusKey").sortKeys(["curationStatusUpdatedAt"]).queryField("listReferencesByCurationStatusKeyAndUpdatedAt"),
|
|
1691
1714
|
index("reviewedFeedKey").sortKeys(["updatedAt"]).queryField("listReferencesByReviewedFeedAndUpdatedAt"),
|
|
1715
|
+
index("discoveredByMonitorId").sortKeys(["createdAt"]).queryField("listReferencesByMonitorAndCreatedAt"),
|
|
1716
|
+
index("feedStateKey").sortKeys(["predictionSortKey"]).queryField("listReferencesByFeedStateAndPrediction"),
|
|
1717
|
+
index("feedStateKey").sortKeys(["feedArrivalAt"]).queryField("listReferencesByFeedStateAndArrival"),
|
|
1692
1718
|
])
|
|
1693
1719
|
.authorization((allow) => [
|
|
1694
1720
|
allow.groups(categoryWriteGroups).to(["read"]),
|
|
@@ -1779,6 +1805,9 @@ const schema = a.schema({
|
|
|
1779
1805
|
authorSub: a.string(),
|
|
1780
1806
|
authorUserProfileId: a.id(),
|
|
1781
1807
|
authorLabel: a.string(),
|
|
1808
|
+
editedAt: a.datetime(),
|
|
1809
|
+
deletedAt: a.datetime(),
|
|
1810
|
+
deletedBySub: a.string(),
|
|
1782
1811
|
threadId: a.id(),
|
|
1783
1812
|
parentMessageId: a.id(),
|
|
1784
1813
|
sequenceNumber: a.integer(),
|
|
@@ -1813,7 +1842,10 @@ const schema = a.schema({
|
|
|
1813
1842
|
index("searchVisibility").sortKeys(["createdAt"]).name("messagesBySearchVisibilityCreatedAt").queryField("listMessagesBySearchVisibilityAndCreatedAt"),
|
|
1814
1843
|
])
|
|
1815
1844
|
.authorization((allow) => [
|
|
1816
|
-
|
|
1845
|
+
// Messages belong to their author, and the backend stamps the author: people read Messages here and write them only through
|
|
1846
|
+
// postMessage, editMessage, deleteOwnMessage and moderateMessage (message-actions.ts). Functions and IAM callers write directly.
|
|
1847
|
+
allow.group("editor").to(["read"]),
|
|
1848
|
+
allow.group(adminGroup).to(["read"]),
|
|
1817
1849
|
allow.authenticated("identityPool").to(["read", "create", "update"]),
|
|
1818
1850
|
]),
|
|
1819
1851
|
|
package/amplify/data/schema.js
CHANGED
|
@@ -4,6 +4,7 @@ import { categoryAction } from "../functions/category-action/resource.js";
|
|
|
4
4
|
import { editorialChecksSchemaDefinitions } from "../functions/editorial-checks/schema.js";
|
|
5
5
|
import { automationViewSchemaDefinitions } from "../functions/automation-view/schema.js";
|
|
6
6
|
import { proposalActionsSchemaDefinitions } from "../functions/proposal-actions/schema.js";
|
|
7
|
+
import { messageActionsSchemaDefinitions } from "./message-actions.js";
|
|
7
8
|
import { monitoringViewSchemaDefinitions } from "../functions/monitoring-view/schema.js";
|
|
8
9
|
import { contentActions } from "../functions/content-actions/resource.js";
|
|
9
10
|
import { knowledgeQuery } from "../functions/knowledge-query/resource.js";
|
|
@@ -259,8 +260,6 @@ function buildBaseDefinitions(includeEditions) {
|
|
|
259
260
|
referenceId: a.id().required(),
|
|
260
261
|
status: a.string().required(),
|
|
261
262
|
reasonCode: a.string(),
|
|
262
|
-
messageId: a.id(),
|
|
263
|
-
relationId: a.id(),
|
|
264
263
|
}),
|
|
265
264
|
ReferenceQualityActionResult: a.customType({
|
|
266
265
|
ok: a.boolean().required(),
|
|
@@ -530,6 +529,12 @@ function buildBaseDefinitions(includeEditions) {
|
|
|
530
529
|
.returns(a.json())
|
|
531
530
|
.authorization((allow) => [allow.groups(contentWriteGroups)])
|
|
532
531
|
.handler(functionHandler("contentActions", contentActions)),
|
|
532
|
+
correctReferenceCapture: a
|
|
533
|
+
.mutation()
|
|
534
|
+
.arguments({ input: a.json().required() })
|
|
535
|
+
.returns(a.json())
|
|
536
|
+
.authorization((allow) => [allow.groups(contentWriteGroups)])
|
|
537
|
+
.handler(functionHandler("contentActions", contentActions)),
|
|
533
538
|
saveItemDraft: a
|
|
534
539
|
.mutation()
|
|
535
540
|
.arguments({ input: a.json().required() })
|
|
@@ -1469,8 +1474,26 @@ function buildBaseDefinitions(includeEditions) {
|
|
|
1469
1474
|
curationStatusUpdatedAt: a.datetime(),
|
|
1470
1475
|
curationStatusUpdatedBy: a.string(),
|
|
1471
1476
|
curationStatusReason: a.string(),
|
|
1477
|
+
curationReasonCode: a.string(),
|
|
1478
|
+
curationActorKind: a.string(),
|
|
1479
|
+
curationSectionId: a.string(),
|
|
1480
|
+
curationShareable: a.boolean(),
|
|
1481
|
+
curationDelegation: a.json(),
|
|
1482
|
+
curationDecisionRelationId: a.string(),
|
|
1472
1483
|
newsroomFeedKey: a.string(),
|
|
1473
1484
|
reviewedFeedKey: a.string(),
|
|
1485
|
+
discoveredByMonitorId: a.string(),
|
|
1486
|
+
discoveryDetails: a.json(),
|
|
1487
|
+
discoveryRule: a.json(),
|
|
1488
|
+
// The References page reads the feed through two indexes (docs/reference-feed-indexes.md). `feedStateKey` is
|
|
1489
|
+
// "<corpusId>#unrated" or "<corpusId>#rated" for a current, not archived Reference (null otherwise: it is in no feed).
|
|
1490
|
+
// `predictionSortKey` orders Best bets, `feedArrivalAt` orders Newest. The prediction is the Cyclotron's ORIGINAL
|
|
1491
|
+
// P(accept), written once, and never rewritten by a vote.
|
|
1492
|
+
feedStateKey: a.string(),
|
|
1493
|
+
feedArrivalAt: a.datetime(),
|
|
1494
|
+
predictedAcceptProbability: a.float(),
|
|
1495
|
+
predictionDecidedAt: a.datetime(),
|
|
1496
|
+
predictionSortKey: a.string(),
|
|
1474
1497
|
updatedAt: a.datetime(),
|
|
1475
1498
|
})
|
|
1476
1499
|
.secondaryIndexes((index) => [
|
|
@@ -1483,6 +1506,9 @@ function buildBaseDefinitions(includeEditions) {
|
|
|
1483
1506
|
index("curationStatus").sortKeys(["curationStatusUpdatedAt"]).queryField("listReferencesByCurationStatusAndUpdatedAt"),
|
|
1484
1507
|
index("curationStatusKey").sortKeys(["curationStatusUpdatedAt"]).queryField("listReferencesByCurationStatusKeyAndUpdatedAt"),
|
|
1485
1508
|
index("reviewedFeedKey").sortKeys(["updatedAt"]).queryField("listReferencesByReviewedFeedAndUpdatedAt"),
|
|
1509
|
+
index("discoveredByMonitorId").sortKeys(["createdAt"]).queryField("listReferencesByMonitorAndCreatedAt"),
|
|
1510
|
+
index("feedStateKey").sortKeys(["predictionSortKey"]).queryField("listReferencesByFeedStateAndPrediction"),
|
|
1511
|
+
index("feedStateKey").sortKeys(["feedArrivalAt"]).queryField("listReferencesByFeedStateAndArrival"),
|
|
1486
1512
|
])
|
|
1487
1513
|
.authorization((allow) => [
|
|
1488
1514
|
allow.groups(categoryWriteGroups).to(["read"]),
|
|
@@ -1567,6 +1593,9 @@ function buildBaseDefinitions(includeEditions) {
|
|
|
1567
1593
|
authorSub: a.string(),
|
|
1568
1594
|
authorUserProfileId: a.id(),
|
|
1569
1595
|
authorLabel: a.string(),
|
|
1596
|
+
editedAt: a.datetime(),
|
|
1597
|
+
deletedAt: a.datetime(),
|
|
1598
|
+
deletedBySub: a.string(),
|
|
1570
1599
|
threadId: a.id(),
|
|
1571
1600
|
parentMessageId: a.id(),
|
|
1572
1601
|
sequenceNumber: a.integer(),
|
|
@@ -1601,19 +1630,24 @@ function buildBaseDefinitions(includeEditions) {
|
|
|
1601
1630
|
index("searchVisibility").sortKeys(["createdAt"]).name("messagesBySearchVisibilityCreatedAt").queryField("listMessagesBySearchVisibilityAndCreatedAt"),
|
|
1602
1631
|
])
|
|
1603
1632
|
.authorization((allow) => [
|
|
1604
|
-
|
|
1633
|
+
// Messages belong to their author, and the backend stamps the author: people read Messages here and write them only through
|
|
1634
|
+
// postMessage, editMessage, deleteOwnMessage and moderateMessage (message-actions.ts). Functions and IAM callers write directly.
|
|
1635
|
+
allow.group("editor").to(["read"]),
|
|
1636
|
+
allow.group(adminGroup).to(["read"]),
|
|
1605
1637
|
]),
|
|
1606
1638
|
MessageThread: realtimeModel({
|
|
1607
1639
|
id: a.id().required(),
|
|
1608
1640
|
threadKind: a.string().required(),
|
|
1609
1641
|
status: a.string().required(),
|
|
1610
|
-
title
|
|
1642
|
+
// The title and the creator are set when a conversation is created and read afterwards; a title changes only through
|
|
1643
|
+
// renameThread (its creator or an admin), and the creator never changes.
|
|
1644
|
+
title: a.string().required().authorization((allow) => [allow.group("editor").to(["read", "create"]), allow.group(adminGroup).to(["read", "create"])]),
|
|
1611
1645
|
summary: a.string(),
|
|
1612
1646
|
primaryAnchorKind: a.string(),
|
|
1613
1647
|
primaryAnchorId: a.id(),
|
|
1614
1648
|
primaryAnchorLineageId: a.id(),
|
|
1615
1649
|
primaryAnchorKey: a.string(),
|
|
1616
|
-
createdBySub: a.string(),
|
|
1650
|
+
createdBySub: a.string().authorization((allow) => [allow.group("editor").to(["read", "create"]), allow.group(adminGroup).to(["read", "create"])]),
|
|
1617
1651
|
createdByUserProfileId: a.id(),
|
|
1618
1652
|
createdByLabel: a.string(),
|
|
1619
1653
|
messageCount: a.integer(),
|
|
@@ -2098,6 +2132,7 @@ function buildBaseDefinitions(includeEditions) {
|
|
|
2098
2132
|
...monitoringViewSchemaDefinitions,
|
|
2099
2133
|
...automationViewSchemaDefinitions,
|
|
2100
2134
|
...proposalActionsSchemaDefinitions,
|
|
2135
|
+
...messageActionsSchemaDefinitions,
|
|
2101
2136
|
};
|
|
2102
2137
|
if (!includeEditions) {
|
|
2103
2138
|
const mutableDefinitions = definitions;
|