@headless-lms/server 0.3.0 → 0.5.0
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/README.md +14 -0
- package/dist/app/community-mail.d.ts +10 -10
- package/dist/app/community-mail.js +72 -28
- package/dist/app/community-mail.js.map +1 -1
- package/dist/app/container.d.ts +48 -10
- package/dist/app/container.js +268 -48
- package/dist/app/container.js.map +1 -1
- package/dist/app/notification-channels.d.ts +47 -0
- package/dist/app/notification-channels.js +175 -0
- package/dist/app/notification-channels.js.map +1 -0
- package/dist/app/notification-reads.d.ts +23 -0
- package/dist/app/notification-reads.js +74 -0
- package/dist/app/notification-reads.js.map +1 -0
- package/dist/app/platform.d.ts +14 -0
- package/dist/app/platform.js +14 -0
- package/dist/app/platform.js.map +1 -0
- package/dist/http/config.d.ts +4 -0
- package/dist/http/errors.d.ts +1 -0
- package/dist/http/errors.js +24 -4
- package/dist/http/errors.js.map +1 -1
- package/dist/http/fastify.d.ts +8 -0
- package/dist/http/mcp/catalogue.d.ts +11 -9
- package/dist/http/mcp/catalogue.js +15 -21
- package/dist/http/mcp/catalogue.js.map +1 -1
- package/dist/http/mcp/challenge.js +3 -3
- package/dist/http/mcp/challenge.js.map +1 -1
- package/dist/http/mcp/route.js +7 -7
- package/dist/http/mcp/route.js.map +1 -1
- package/dist/http/mcp/test-support.d.ts +6 -5
- package/dist/http/mcp/test-support.js +32 -11
- package/dist/http/mcp/test-support.js.map +1 -1
- package/dist/http/mcp/tool.d.ts +3 -9
- package/dist/http/mcp/tool.js +14 -6
- package/dist/http/mcp/tool.js.map +1 -1
- package/dist/http/mcp/tools/automations.js +10 -20
- package/dist/http/mcp/tools/automations.js.map +1 -1
- package/dist/http/mcp/tools/catalog.js +25 -42
- package/dist/http/mcp/tools/catalog.js.map +1 -1
- package/dist/http/mcp/tools/comments.js +9 -19
- package/dist/http/mcp/tools/comments.js.map +1 -1
- package/dist/http/mcp/tools/communities.js +16 -31
- package/dist/http/mcp/tools/communities.js.map +1 -1
- package/dist/http/mcp/tools/community-members.js +9 -16
- package/dist/http/mcp/tools/community-members.js.map +1 -1
- package/dist/http/mcp/tools/community-moderation.js +13 -25
- package/dist/http/mcp/tools/community-moderation.js.map +1 -1
- package/dist/http/mcp/tools/courses.js +11 -21
- package/dist/http/mcp/tools/courses.js.map +1 -1
- package/dist/http/mcp/tools/events.d.ts +6 -0
- package/dist/http/mcp/tools/events.js +170 -0
- package/dist/http/mcp/tools/events.js.map +1 -0
- package/dist/http/mcp/tools/index.d.ts +5 -1
- package/dist/http/mcp/tools/index.js +45 -10
- package/dist/http/mcp/tools/index.js.map +1 -1
- package/dist/http/mcp/tools/organization.d.ts +6 -0
- package/dist/http/mcp/tools/organization.js +214 -0
- package/dist/http/mcp/tools/organization.js.map +1 -0
- package/dist/http/mcp/tools/people.js +30 -49
- package/dist/http/mcp/tools/people.js.map +1 -1
- package/dist/http/plugins/auth.js +37 -8
- package/dist/http/plugins/auth.js.map +1 -1
- package/dist/http/plugins/error-handler.d.ts +5 -1
- package/dist/http/plugins/error-handler.js +13 -3
- package/dist/http/plugins/error-handler.js.map +1 -1
- package/dist/http/plugins/openapi.js +18 -2
- package/dist/http/plugins/openapi.js.map +1 -1
- package/dist/http/plugins/platform.d.ts +7 -0
- package/dist/http/plugins/platform.js +13 -0
- package/dist/http/plugins/platform.js.map +1 -0
- package/dist/http/routes/access.js +54 -36
- package/dist/http/routes/access.js.map +1 -1
- package/dist/http/routes/activities.js +45 -45
- package/dist/http/routes/activities.js.map +1 -1
- package/dist/http/routes/assets.js +30 -65
- package/dist/http/routes/assets.js.map +1 -1
- package/dist/http/routes/automations.js +37 -42
- package/dist/http/routes/automations.js.map +1 -1
- package/dist/http/routes/bundles.js +33 -36
- package/dist/http/routes/bundles.js.map +1 -1
- package/dist/http/routes/communities.js +144 -136
- package/dist/http/routes/communities.js.map +1 -1
- package/dist/http/routes/community-moderation.js +83 -137
- package/dist/http/routes/community-moderation.js.map +1 -1
- package/dist/http/routes/course-analytics.js +32 -15
- package/dist/http/routes/course-analytics.js.map +1 -1
- package/dist/http/routes/courses.js +25 -32
- package/dist/http/routes/courses.js.map +1 -1
- package/dist/http/routes/dashboard.js +9 -9
- package/dist/http/routes/dashboard.js.map +1 -1
- package/dist/http/routes/discussion.js +21 -39
- package/dist/http/routes/discussion.js.map +1 -1
- package/dist/http/routes/downloads.js +41 -47
- package/dist/http/routes/downloads.js.map +1 -1
- package/dist/http/routes/entitlements.js +19 -23
- package/dist/http/routes/entitlements.js.map +1 -1
- package/dist/http/routes/events.d.ts +7 -0
- package/dist/http/routes/events.js +333 -0
- package/dist/http/routes/events.js.map +1 -0
- package/dist/http/routes/integrations.js +40 -73
- package/dist/http/routes/integrations.js.map +1 -1
- package/dist/http/routes/member/assets.js +10 -13
- package/dist/http/routes/member/assets.js.map +1 -1
- package/dist/http/routes/member/chats.js +177 -75
- package/dist/http/routes/member/chats.js.map +1 -1
- package/dist/http/routes/member/comments.js +65 -26
- package/dist/http/routes/member/comments.js.map +1 -1
- package/dist/http/routes/member/community.js +68 -51
- package/dist/http/routes/member/community.js.map +1 -1
- package/dist/http/routes/member/courses.js +12 -19
- package/dist/http/routes/member/courses.js.map +1 -1
- package/dist/http/routes/member/devices.d.ts +7 -0
- package/dist/http/routes/member/devices.js +97 -0
- package/dist/http/routes/member/devices.js.map +1 -0
- package/dist/http/routes/member/downloads.js +6 -9
- package/dist/http/routes/member/downloads.js.map +1 -1
- package/dist/http/routes/member/events.d.ts +7 -0
- package/dist/http/routes/member/events.js +386 -0
- package/dist/http/routes/member/events.js.map +1 -0
- package/dist/http/routes/member/files.js +71 -46
- package/dist/http/routes/member/files.js.map +1 -1
- package/dist/http/routes/member/index.js +6 -0
- package/dist/http/routes/member/index.js.map +1 -1
- package/dist/http/routes/member/notification-settings.d.ts +7 -0
- package/dist/http/routes/member/notification-settings.js +100 -0
- package/dist/http/routes/member/notification-settings.js.map +1 -0
- package/dist/http/routes/member/notifications.js +69 -45
- package/dist/http/routes/member/notifications.js.map +1 -1
- package/dist/http/routes/member/org.js +5 -15
- package/dist/http/routes/member/org.js.map +1 -1
- package/dist/http/routes/member/posts.js +94 -95
- package/dist/http/routes/member/posts.js.map +1 -1
- package/dist/http/routes/member/profile.js +15 -6
- package/dist/http/routes/member/profile.js.map +1 -1
- package/dist/http/routes/member/progress.js +7 -11
- package/dist/http/routes/member/progress.js.map +1 -1
- package/dist/http/routes/organizations.js +415 -110
- package/dist/http/routes/organizations.js.map +1 -1
- package/dist/http/routes/platform.d.ts +7 -0
- package/dist/http/routes/platform.js +61 -0
- package/dist/http/routes/platform.js.map +1 -0
- package/dist/http/routes/students.js +12 -75
- package/dist/http/routes/students.js.map +1 -1
- package/dist/http/routes/webhooks.js +30 -39
- package/dist/http/routes/webhooks.js.map +1 -1
- package/dist/http/routes.js +9 -0
- package/dist/http/routes.js.map +1 -1
- package/dist/http/schemas/access.d.ts +346 -64
- package/dist/http/schemas/access.js +39 -12
- package/dist/http/schemas/access.js.map +1 -1
- package/dist/http/schemas/assets.d.ts +13 -8
- package/dist/http/schemas/assets.js +6 -5
- package/dist/http/schemas/assets.js.map +1 -1
- package/dist/http/schemas/automations.d.ts +4 -8
- package/dist/http/schemas/chats.d.ts +238 -36
- package/dist/http/schemas/chats.js +14 -7
- package/dist/http/schemas/chats.js.map +1 -1
- package/dist/http/schemas/community.d.ts +140 -33
- package/dist/http/schemas/community.js +25 -9
- package/dist/http/schemas/community.js.map +1 -1
- package/dist/http/schemas/course-analytics.d.ts +51 -1
- package/dist/http/schemas/course-analytics.js +19 -1
- package/dist/http/schemas/course-analytics.js.map +1 -1
- package/dist/http/schemas/dashboard.d.ts +1 -0
- package/dist/http/schemas/dashboard.js +2 -1
- package/dist/http/schemas/dashboard.js.map +1 -1
- package/dist/http/schemas/discussion.d.ts +45 -73
- package/dist/http/schemas/discussion.js +16 -4
- package/dist/http/schemas/discussion.js.map +1 -1
- package/dist/http/schemas/entitlements.d.ts +9 -12
- package/dist/http/schemas/entitlements.js +11 -5
- package/dist/http/schemas/entitlements.js.map +1 -1
- package/dist/http/schemas/events.d.ts +527 -0
- package/dist/http/schemas/events.js +64 -0
- package/dist/http/schemas/events.js.map +1 -0
- package/dist/http/schemas/files.d.ts +15 -5
- package/dist/http/schemas/files.js +10 -2
- package/dist/http/schemas/files.js.map +1 -1
- package/dist/http/schemas/index.d.ts +14 -12
- package/dist/http/schemas/index.js +14 -12
- package/dist/http/schemas/invites.d.ts +3 -47
- package/dist/http/schemas/invites.js +4 -25
- package/dist/http/schemas/invites.js.map +1 -1
- package/dist/http/schemas/member.d.ts +94 -7
- package/dist/http/schemas/member.js +7 -3
- package/dist/http/schemas/member.js.map +1 -1
- package/dist/http/schemas/members.d.ts +329 -65
- package/dist/http/schemas/members.js +67 -25
- package/dist/http/schemas/members.js.map +1 -1
- package/dist/http/schemas/notifications.d.ts +502 -175
- package/dist/http/schemas/notifications.js +148 -28
- package/dist/http/schemas/notifications.js.map +1 -1
- package/dist/http/schemas/platform.d.ts +37 -0
- package/dist/http/schemas/platform.js +19 -0
- package/dist/http/schemas/platform.js.map +1 -0
- package/dist/http/schemas/posts.d.ts +92 -38
- package/dist/http/schemas/posts.js +4 -4
- package/dist/http/schemas/posts.js.map +1 -1
- package/dist/http/schemas/profile.d.ts +1 -1
- package/dist/http/schemas/shared.d.ts +10 -13
- package/dist/http/schemas/shared.js +3 -11
- package/dist/http/schemas/shared.js.map +1 -1
- package/dist/http/schemas/students.d.ts +22 -0
- package/dist/http/schemas/students.js +3 -1
- package/dist/http/schemas/students.js.map +1 -1
- package/dist/http/scope.d.ts +9 -12
- package/dist/http/scope.js +30 -35
- package/dist/http/scope.js.map +1 -1
- package/dist/http/server.js +9 -0
- package/dist/http/server.js.map +1 -1
- package/dist/http/shutdown.d.ts +11 -0
- package/dist/http/shutdown.js +40 -0
- package/dist/http/shutdown.js.map +1 -0
- package/dist/http/sse.d.ts +19 -0
- package/dist/http/sse.js +104 -0
- package/dist/http/sse.js.map +1 -0
- package/dist/http/test-caller.d.ts +13 -0
- package/dist/http/test-caller.js +14 -0
- package/dist/http/test-caller.js.map +1 -0
- package/dist/http/well-known.js +2 -2
- package/dist/http/well-known.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/packages/server/package.js +1 -1
- package/package.json +7 -6
- package/dist/http/routes/member/actor.d.ts +0 -14
- package/dist/http/routes/member/actor.js +0 -11
- package/dist/http/routes/member/actor.js.map +0 -1
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { refusals } from "../../schemas/shared.js";
|
|
2
|
+
import { resolveActor } from "../../scope.js";
|
|
2
3
|
import { Asset, AssetIdParam, RequestMemberUpload, UploadTicket } from "../../schemas/assets.js";
|
|
3
4
|
import "../../schemas/index.js";
|
|
4
|
-
import { actorOf } from "./actor.js";
|
|
5
5
|
import { z } from "zod";
|
|
6
|
-
import { NotFoundError } from "@headless-lms/core/shared/errors";
|
|
7
6
|
//#region src/http/routes/member/assets.ts
|
|
8
7
|
const tags = ["Assets"];
|
|
9
8
|
async function memberAssetsRoutes(app, container) {
|
|
@@ -15,8 +14,8 @@ async function memberAssetsRoutes(app, container) {
|
|
|
15
14
|
schema: {
|
|
16
15
|
operationId: "requestMemberUpload",
|
|
17
16
|
tags,
|
|
18
|
-
summary: "Register
|
|
19
|
-
description: "For a member of the organization.
|
|
17
|
+
summary: "Register a file you are about to upload and get a presigned upload URL",
|
|
18
|
+
description: "For a member of the organization. Any file type. A raster image (PNG, JPEG, GIF, WebP, AVIF) can be your profile photo, a post cover or a message attachment; any upload can be shown in the body of your post. The asset is yours: only you can finalize it or attach it. You can delete it while nothing references it.",
|
|
20
19
|
body: RequestMemberUpload,
|
|
21
20
|
response: {
|
|
22
21
|
201: UploadTicket,
|
|
@@ -24,8 +23,8 @@ async function memberAssetsRoutes(app, container) {
|
|
|
24
23
|
}
|
|
25
24
|
},
|
|
26
25
|
handler: async (req, reply) => {
|
|
27
|
-
const actor = await
|
|
28
|
-
const ticket = await container.assets.requestMemberUpload(req.
|
|
26
|
+
const actor = await resolveActor(container, req);
|
|
27
|
+
const ticket = await container.assets.requestMemberUpload(req.body, actor);
|
|
29
28
|
return reply.code(201).send(ticket);
|
|
30
29
|
}
|
|
31
30
|
});
|
|
@@ -37,7 +36,7 @@ async function memberAssetsRoutes(app, container) {
|
|
|
37
36
|
operationId: "finalizeMemberUpload",
|
|
38
37
|
tags,
|
|
39
38
|
summary: "Confirm an upload you started",
|
|
40
|
-
description: "Uploader only; anyone else gets 404. Reads the stored size and content type. A file
|
|
39
|
+
description: "Uploader only; anyone else gets 404. Reads the stored size and content type. A file whose stored type differs from the declared one, or that is over its size limit (`MEMBER_IMAGE_MAX_BYTES` for images, `MEMBER_FILE_MAX_BYTES` for any other file), is discarded and answered with 409. A finalized file moves where the upload URL no longer reaches; finalizing it again returns it unchanged.",
|
|
41
40
|
params: AssetIdParam,
|
|
42
41
|
response: {
|
|
43
42
|
200: Asset,
|
|
@@ -45,10 +44,8 @@ async function memberAssetsRoutes(app, container) {
|
|
|
45
44
|
}
|
|
46
45
|
},
|
|
47
46
|
handler: async (req) => {
|
|
48
|
-
const actor = await
|
|
49
|
-
|
|
50
|
-
if (!asset) throw new NotFoundError("Asset", req.params.id);
|
|
51
|
-
return asset;
|
|
47
|
+
const actor = await resolveActor(container, req);
|
|
48
|
+
return container.assets.confirmOwn(req.params.id, actor);
|
|
52
49
|
}
|
|
53
50
|
});
|
|
54
51
|
r.route({
|
|
@@ -67,8 +64,8 @@ async function memberAssetsRoutes(app, container) {
|
|
|
67
64
|
}
|
|
68
65
|
},
|
|
69
66
|
handler: async (req, reply) => {
|
|
70
|
-
const actor = await
|
|
71
|
-
|
|
67
|
+
const actor = await resolveActor(container, req);
|
|
68
|
+
await container.assets.removeOwn(req.params.id, actor);
|
|
72
69
|
return reply.code(204).send();
|
|
73
70
|
}
|
|
74
71
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assets.js","names":[],"sources":["../../../../src/http/routes/member/assets.ts"],"sourcesContent":["import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport { z } from 'zod';\nimport {\n Asset,\n AssetIdParam,\n RequestMemberUpload,\n UploadTicket,\n refusals,\n} from '../../schemas/index.js';\nimport {
|
|
1
|
+
{"version":3,"file":"assets.js","names":[],"sources":["../../../../src/http/routes/member/assets.ts"],"sourcesContent":["import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport { z } from 'zod';\nimport {\n Asset,\n AssetIdParam,\n RequestMemberUpload,\n UploadTicket,\n refusals,\n} from '../../schemas/index.js';\nimport { resolveActor } from '../../scope.js';\nimport type { Container } from '../../../app/container.js';\n\nconst tags = ['Assets'];\n\nexport async function memberAssetsRoutes(\n app: FastifyInstance,\n container: Container,\n): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n\n r.route({\n method: 'POST',\n url: '/api/member/uploads',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'requestMemberUpload',\n tags,\n summary: 'Register a file you are about to upload and get a presigned upload URL',\n description:\n 'For a member of the organization. Any file type. A raster image (PNG, JPEG, GIF, WebP, AVIF) can be your profile photo, a post cover or a message attachment; any upload can be shown in the body of your post. The asset is yours: only you can finalize it or attach it. You can delete it while nothing references it.',\n body: RequestMemberUpload,\n response: { 201: UploadTicket, ...refusals(403, 409) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n const ticket = await container.assets.requestMemberUpload(req.body, actor);\n return reply.code(201).send(ticket);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/uploads/:id/finalize',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'finalizeMemberUpload',\n tags,\n summary: 'Confirm an upload you started',\n description:\n 'Uploader only; anyone else gets 404. Reads the stored size and content type. A file whose stored type differs from the declared one, or that is over its size limit (`MEMBER_IMAGE_MAX_BYTES` for images, `MEMBER_FILE_MAX_BYTES` for any other file), is discarded and answered with 409. A finalized file moves where the upload URL no longer reaches; finalizing it again returns it unchanged.',\n params: AssetIdParam,\n response: { 200: Asset, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return container.assets.confirmOwn(req.params.id, actor);\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/member/uploads/:id',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'deleteMemberUpload',\n tags,\n summary: 'Delete an upload of yours that nothing references',\n description:\n 'Uploader only; anyone else gets 404. 409 while a profile, post or message still uses it.',\n params: AssetIdParam,\n response: { 204: z.void(), ...refusals(403, 404, 409) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n await container.assets.removeOwn(req.params.id, actor);\n return reply.code(204).send();\n },\n });\n}\n"],"mappings":";;;;;;AAaA,MAAM,OAAO,CAAC,QAAQ;AAEtB,eAAsB,mBACpB,KACA,WACe;CACf,MAAM,IAAI,IAAI,iBAAkC;CAEhD,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb;GACA,SAAS;GACT,aACE;GACF,MAAM;GACN,UAAU;IAAE,KAAK;IAAc,GAAG,SAAS,KAAK,GAAG;GAAE;EACvD;EACA,SAAS,OAAO,KAAK,UAAU;GAC7B,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,MAAM,SAAS,MAAM,UAAU,OAAO,oBAAoB,IAAI,MAAM,KAAK;GACzE,OAAO,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,MAAM;EACpC;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb;GACA,SAAS;GACT,aACE;GACF,QAAQ;GACR,UAAU;IAAE,KAAK;IAAO,GAAG,SAAS,KAAK,KAAK,GAAG;GAAE;EACrD;EACA,SAAS,OAAO,QAAQ;GACtB,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,OAAO,UAAU,OAAO,WAAW,IAAI,OAAO,IAAI,KAAK;EACzD;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb;GACA,SAAS;GACT,aACE;GACF,QAAQ;GACR,UAAU;IAAE,KAAK,EAAE,KAAK;IAAG,GAAG,SAAS,KAAK,KAAK,GAAG;GAAE;EACxD;EACA,SAAS,OAAO,KAAK,UAAU;GAC7B,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,MAAM,UAAU,OAAO,UAAU,IAAI,OAAO,IAAI,KAAK;GACrD,OAAO,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK;EAC9B;CACF,CAAC;AACH"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { PageQuery, refusals } from "../../schemas/shared.js";
|
|
2
|
-
import {
|
|
2
|
+
import { resolveActor } from "../../scope.js";
|
|
3
|
+
import { Reactions, SetMute, SetReaction } from "../../schemas/discussion.js";
|
|
3
4
|
import { FlagReason } from "../../schemas/posts.js";
|
|
4
|
-
import { BlockParam, Chat, ChatIdParam, ChatsPage, CommunityParam, EditMessage, MarkRead, MessageFlag, MessageIdParam, MessageView, MessagesPage,
|
|
5
|
+
import { BlockParam, Chat, ChatIdParam, ChatListItem, ChatListQuery, ChatLiveEvent, ChatUnreadSummary, ChatsPage, CommunityParam, DirectChatParam, EditMessage, MarkRead, MessageFlag, MessageIdParam, MessageQueue, MessageView, MessagesPage, OrgUserBody, ResolveMessageFlags, SendMessage, StartDirectChat, StartGroupChat } from "../../schemas/chats.js";
|
|
5
6
|
import "../../schemas/index.js";
|
|
6
|
-
import {
|
|
7
|
+
import { sse } from "../../sse.js";
|
|
7
8
|
import { z } from "zod";
|
|
8
9
|
//#region src/http/routes/member/chats.ts
|
|
9
10
|
async function memberChatRoutes(app, container) {
|
|
@@ -18,17 +19,139 @@ async function memberChatRoutes(app, container) {
|
|
|
18
19
|
operationId: "listMemberChats",
|
|
19
20
|
tags,
|
|
20
21
|
summary: "List your chats in a community",
|
|
21
|
-
description: "For a member of the community. Every chat you are in, with your unread count and its last message.",
|
|
22
|
+
description: "For a member of the community. Every chat you are in, with your unread count and its last message. `requests=true` lists only the pending message requests to you, `requests=false` everything else.",
|
|
22
23
|
params: CommunityParam,
|
|
23
|
-
querystring:
|
|
24
|
+
querystring: ChatListQuery,
|
|
24
25
|
response: {
|
|
25
26
|
200: ChatsPage,
|
|
26
27
|
...refusals(403, 404)
|
|
27
28
|
}
|
|
28
29
|
},
|
|
29
30
|
handler: async (req) => {
|
|
30
|
-
const actor = await
|
|
31
|
-
return chats.listChats(req.
|
|
31
|
+
const actor = await resolveActor(container, req);
|
|
32
|
+
return chats.listChats(req.params.communityId, req.query, actor);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
r.route({
|
|
36
|
+
method: "GET",
|
|
37
|
+
url: "/api/member/communities/:communityId/chats/events",
|
|
38
|
+
preHandler: app.requireOrgSession,
|
|
39
|
+
config: { eventStream: true },
|
|
40
|
+
schema: {
|
|
41
|
+
operationId: "streamMemberChatEvents",
|
|
42
|
+
tags,
|
|
43
|
+
summary: "Stream your chat events in a community",
|
|
44
|
+
description: `Any active member of the organization. For a member of the community. A server-sent event stream of the changes to the chats you are in. It starts with \`ready\` and your \`unread\`; load your chats on \`ready\` and on \`resync\`. A \`: ping\` comment every 25 s keeps it open. It ends with \`closed\` when the server shuts down. 503 when this server has no live delivery.`,
|
|
45
|
+
params: CommunityParam,
|
|
46
|
+
response: {
|
|
47
|
+
200: { content: { "text/event-stream": { schema: ChatLiveEvent } } },
|
|
48
|
+
...refusals(403, 404, 503)
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
handler: async (req, reply) => {
|
|
52
|
+
const actor = await resolveActor(container, req);
|
|
53
|
+
await sse(reply, await chats.watch(req.params.communityId, actor));
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
r.route({
|
|
57
|
+
method: "GET",
|
|
58
|
+
url: "/api/member/communities/:communityId/chats/unread",
|
|
59
|
+
preHandler: app.requireOrgSession,
|
|
60
|
+
schema: {
|
|
61
|
+
operationId: "getMemberChatUnread",
|
|
62
|
+
tags,
|
|
63
|
+
summary: "Your unread chat total in a community",
|
|
64
|
+
description: `Any active member of the organization. For a member of the community. \`unread\` counts the unread messages in your chats that are neither muted nor requests to you, plus your pending requests; \`requests\` is the number of pending requests to you.`,
|
|
65
|
+
params: CommunityParam,
|
|
66
|
+
response: {
|
|
67
|
+
200: ChatUnreadSummary,
|
|
68
|
+
...refusals(403, 404)
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
handler: async (req) => {
|
|
72
|
+
const actor = await resolveActor(container, req);
|
|
73
|
+
return chats.unreadSummary(req.params.communityId, actor);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
r.route({
|
|
77
|
+
method: "GET",
|
|
78
|
+
url: "/api/member/communities/:communityId/chats/direct/:orgUserId",
|
|
79
|
+
preHandler: app.requireOrgSession,
|
|
80
|
+
schema: {
|
|
81
|
+
operationId: "getMemberDirectChat",
|
|
82
|
+
tags,
|
|
83
|
+
summary: "Your direct chat with a person",
|
|
84
|
+
description: `Any active member of the organization. For a member of the community. Your direct chat with the person while you are in it; 404 when there is none.`,
|
|
85
|
+
params: DirectChatParam,
|
|
86
|
+
response: {
|
|
87
|
+
200: ChatListItem,
|
|
88
|
+
...refusals(403, 404)
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
handler: async (req) => {
|
|
92
|
+
const actor = await resolveActor(container, req);
|
|
93
|
+
return chats.directChat(req.params.communityId, req.params.orgUserId, actor);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
r.route({
|
|
97
|
+
method: "GET",
|
|
98
|
+
url: "/api/member/chats/:chatId",
|
|
99
|
+
preHandler: app.requireOrgSession,
|
|
100
|
+
schema: {
|
|
101
|
+
operationId: "getMemberChat",
|
|
102
|
+
tags,
|
|
103
|
+
summary: "Read one of your chats",
|
|
104
|
+
description: `Any active member of the organization. For a participant of the chat. The chat as it appears in your chat list.`,
|
|
105
|
+
params: ChatIdParam,
|
|
106
|
+
response: {
|
|
107
|
+
200: ChatListItem,
|
|
108
|
+
...refusals(403, 404)
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
handler: async (req) => {
|
|
112
|
+
const actor = await resolveActor(container, req);
|
|
113
|
+
return chats.chat(req.params.chatId, actor);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
r.route({
|
|
117
|
+
method: "POST",
|
|
118
|
+
url: "/api/member/chats/:chatId/typing",
|
|
119
|
+
preHandler: app.requireOrgSession,
|
|
120
|
+
schema: {
|
|
121
|
+
operationId: "sendChatTyping",
|
|
122
|
+
tags,
|
|
123
|
+
summary: "Tell the chat you are typing",
|
|
124
|
+
description: `Any active member of the organization. For a participant while the chat is open and not locked (403 otherwise). The others see you typing for 5 s; a repeat within 2 s is dropped.`,
|
|
125
|
+
params: ChatIdParam,
|
|
126
|
+
response: {
|
|
127
|
+
204: z.void(),
|
|
128
|
+
...refusals(403, 404)
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
handler: async (req, reply) => {
|
|
132
|
+
const actor = await resolveActor(container, req);
|
|
133
|
+
await chats.typing(req.params.chatId, actor);
|
|
134
|
+
return reply.code(204).send();
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
r.route({
|
|
138
|
+
method: "GET",
|
|
139
|
+
url: "/api/member/communities/:communityId/message-queue",
|
|
140
|
+
preHandler: app.requireOrgSession,
|
|
141
|
+
schema: {
|
|
142
|
+
operationId: "getMemberMessageQueue",
|
|
143
|
+
tags,
|
|
144
|
+
summary: "Open message flags in a community you moderate",
|
|
145
|
+
description: `Requires \`communities:moderate\`. Needed on the community, as a member of it. The messages in its chats with open flags, with the flags and the chat each is in. Holds at most the 100 oldest open flags; working the queue brings in the next ones.`,
|
|
146
|
+
params: CommunityParam,
|
|
147
|
+
response: {
|
|
148
|
+
200: MessageQueue,
|
|
149
|
+
...refusals(403, 404)
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
handler: async (req) => {
|
|
153
|
+
const actor = await resolveActor(container, req);
|
|
154
|
+
return chats.messageQueue(req.params.communityId, actor);
|
|
32
155
|
}
|
|
33
156
|
});
|
|
34
157
|
r.route({
|
|
@@ -47,8 +170,8 @@ async function memberChatRoutes(app, container) {
|
|
|
47
170
|
}
|
|
48
171
|
},
|
|
49
172
|
handler: async (req) => {
|
|
50
|
-
const actor = await
|
|
51
|
-
return chats.startDirect(req.
|
|
173
|
+
const actor = await resolveActor(container, req);
|
|
174
|
+
return chats.startDirect(req.body, actor);
|
|
52
175
|
}
|
|
53
176
|
});
|
|
54
177
|
r.route({
|
|
@@ -67,8 +190,8 @@ async function memberChatRoutes(app, container) {
|
|
|
67
190
|
}
|
|
68
191
|
},
|
|
69
192
|
handler: async (req, reply) => {
|
|
70
|
-
const actor = await
|
|
71
|
-
const chat = await chats.startGroup(req.
|
|
193
|
+
const actor = await resolveActor(container, req);
|
|
194
|
+
const chat = await chats.startGroup(req.body, actor);
|
|
72
195
|
return reply.code(201).send(chat);
|
|
73
196
|
}
|
|
74
197
|
});
|
|
@@ -89,8 +212,8 @@ async function memberChatRoutes(app, container) {
|
|
|
89
212
|
}
|
|
90
213
|
},
|
|
91
214
|
handler: async (req) => {
|
|
92
|
-
const actor = await
|
|
93
|
-
return chats.addParticipant(req.
|
|
215
|
+
const actor = await resolveActor(container, req);
|
|
216
|
+
return chats.addParticipant(req.params.chatId, req.body.orgUserId, actor);
|
|
94
217
|
}
|
|
95
218
|
});
|
|
96
219
|
r.route({
|
|
@@ -109,13 +232,13 @@ async function memberChatRoutes(app, container) {
|
|
|
109
232
|
}
|
|
110
233
|
},
|
|
111
234
|
handler: async (req) => {
|
|
112
|
-
const actor = await
|
|
113
|
-
return chats.leave(req.
|
|
235
|
+
const actor = await resolveActor(container, req);
|
|
236
|
+
return chats.leave(req.params.chatId, actor);
|
|
114
237
|
}
|
|
115
238
|
});
|
|
116
239
|
r.route({
|
|
117
240
|
method: "POST",
|
|
118
|
-
url: "/api/member/chats/:chatId/
|
|
241
|
+
url: "/api/member/chats/:chatId/accept",
|
|
119
242
|
preHandler: app.requireOrgSession,
|
|
120
243
|
schema: {
|
|
121
244
|
operationId: "acceptChat",
|
|
@@ -129,8 +252,8 @@ async function memberChatRoutes(app, container) {
|
|
|
129
252
|
}
|
|
130
253
|
},
|
|
131
254
|
handler: async (req) => {
|
|
132
|
-
const actor = await
|
|
133
|
-
return chats.accept(req.
|
|
255
|
+
const actor = await resolveActor(container, req);
|
|
256
|
+
return chats.accept(req.params.chatId, actor);
|
|
134
257
|
}
|
|
135
258
|
});
|
|
136
259
|
r.route({
|
|
@@ -150,8 +273,8 @@ async function memberChatRoutes(app, container) {
|
|
|
150
273
|
}
|
|
151
274
|
},
|
|
152
275
|
handler: async (req) => {
|
|
153
|
-
const actor = await
|
|
154
|
-
return chats.messages(req.
|
|
276
|
+
const actor = await resolveActor(container, req);
|
|
277
|
+
return chats.messages(req.params.chatId, req.query, actor);
|
|
155
278
|
}
|
|
156
279
|
});
|
|
157
280
|
r.route({
|
|
@@ -162,7 +285,7 @@ async function memberChatRoutes(app, container) {
|
|
|
162
285
|
operationId: "sendChatMessage",
|
|
163
286
|
tags,
|
|
164
287
|
summary: "Send a message",
|
|
165
|
-
description: "For a participant while the chat is open and not locked, and nobody in it has blocked the other (403 otherwise). A request's sender cannot send more until it is accepted.",
|
|
288
|
+
description: "For a participant while the chat is open and not locked, and nobody in it has blocked the other (403 otherwise). A request's sender cannot send more until it is accepted. Sending again with the same `clientId` returns the message already sent.",
|
|
166
289
|
params: ChatIdParam,
|
|
167
290
|
body: SendMessage,
|
|
168
291
|
response: {
|
|
@@ -171,8 +294,8 @@ async function memberChatRoutes(app, container) {
|
|
|
171
294
|
}
|
|
172
295
|
},
|
|
173
296
|
handler: async (req, reply) => {
|
|
174
|
-
const actor = await
|
|
175
|
-
const message = await chats.send(req.
|
|
297
|
+
const actor = await resolveActor(container, req);
|
|
298
|
+
const message = await chats.send(req.params.chatId, req.body, actor);
|
|
176
299
|
return reply.code(201).send(message);
|
|
177
300
|
}
|
|
178
301
|
});
|
|
@@ -193,8 +316,8 @@ async function memberChatRoutes(app, container) {
|
|
|
193
316
|
}
|
|
194
317
|
},
|
|
195
318
|
handler: async (req) => {
|
|
196
|
-
const actor = await
|
|
197
|
-
return chats.editMessage(req.
|
|
319
|
+
const actor = await resolveActor(container, req);
|
|
320
|
+
return chats.editMessage(req.params.messageId, req.body.body, actor);
|
|
198
321
|
}
|
|
199
322
|
});
|
|
200
323
|
r.route({
|
|
@@ -213,8 +336,8 @@ async function memberChatRoutes(app, container) {
|
|
|
213
336
|
}
|
|
214
337
|
},
|
|
215
338
|
handler: async (req) => {
|
|
216
|
-
const actor = await
|
|
217
|
-
return chats.deleteMessage(req.
|
|
339
|
+
const actor = await resolveActor(container, req);
|
|
340
|
+
return chats.deleteMessage(req.params.messageId, actor);
|
|
218
341
|
}
|
|
219
342
|
});
|
|
220
343
|
r.route({
|
|
@@ -234,8 +357,8 @@ async function memberChatRoutes(app, container) {
|
|
|
234
357
|
}
|
|
235
358
|
},
|
|
236
359
|
handler: async (req) => {
|
|
237
|
-
const actor = await
|
|
238
|
-
return chats.setReaction(req.
|
|
360
|
+
const actor = await resolveActor(container, req);
|
|
361
|
+
return chats.setReaction(req.params.messageId, req.body.emoji, actor);
|
|
239
362
|
}
|
|
240
363
|
});
|
|
241
364
|
r.route({
|
|
@@ -254,8 +377,8 @@ async function memberChatRoutes(app, container) {
|
|
|
254
377
|
}
|
|
255
378
|
},
|
|
256
379
|
handler: async (req) => {
|
|
257
|
-
const actor = await
|
|
258
|
-
return chats.setReaction(req.
|
|
380
|
+
const actor = await resolveActor(container, req);
|
|
381
|
+
return chats.setReaction(req.params.messageId, null, actor);
|
|
259
382
|
}
|
|
260
383
|
});
|
|
261
384
|
r.route({
|
|
@@ -275,14 +398,14 @@ async function memberChatRoutes(app, container) {
|
|
|
275
398
|
}
|
|
276
399
|
},
|
|
277
400
|
handler: async (req, reply) => {
|
|
278
|
-
const actor = await
|
|
279
|
-
const flag = await chats.flagMessage(req.
|
|
401
|
+
const actor = await resolveActor(container, req);
|
|
402
|
+
const flag = await chats.flagMessage(req.params.messageId, req.body.reason, actor);
|
|
280
403
|
return reply.code(201).send(flag);
|
|
281
404
|
}
|
|
282
405
|
});
|
|
283
406
|
r.route({
|
|
284
407
|
method: "POST",
|
|
285
|
-
url: "/api/member/messages/:messageId/flags/
|
|
408
|
+
url: "/api/member/messages/:messageId/flags/resolve",
|
|
286
409
|
preHandler: app.requireOrgSession,
|
|
287
410
|
schema: {
|
|
288
411
|
operationId: "resolveMessageFlags",
|
|
@@ -297,8 +420,8 @@ async function memberChatRoutes(app, container) {
|
|
|
297
420
|
}
|
|
298
421
|
},
|
|
299
422
|
handler: async (req, reply) => {
|
|
300
|
-
const actor = await
|
|
301
|
-
await chats.resolveMessageFlags(req.
|
|
423
|
+
const actor = await resolveActor(container, req);
|
|
424
|
+
await chats.resolveMessageFlags(req.params.messageId, req.body.resolution, null, actor);
|
|
302
425
|
return reply.code(204).send();
|
|
303
426
|
}
|
|
304
427
|
});
|
|
@@ -319,51 +442,30 @@ async function memberChatRoutes(app, container) {
|
|
|
319
442
|
}
|
|
320
443
|
},
|
|
321
444
|
handler: async (req, reply) => {
|
|
322
|
-
const actor = await
|
|
323
|
-
await chats.markRead(req.
|
|
324
|
-
return reply.code(204).send();
|
|
325
|
-
}
|
|
326
|
-
});
|
|
327
|
-
r.route({
|
|
328
|
-
method: "POST",
|
|
329
|
-
url: "/api/member/chats/:chatId/mute",
|
|
330
|
-
preHandler: app.requireOrgSession,
|
|
331
|
-
schema: {
|
|
332
|
-
operationId: "muteChat",
|
|
333
|
-
tags,
|
|
334
|
-
summary: "Mute a chat until a time, or until unmuted",
|
|
335
|
-
description: "For a participant. Without `until` the chat stays muted until you unmute it.",
|
|
336
|
-
params: ChatIdParam,
|
|
337
|
-
body: MuteChat,
|
|
338
|
-
response: {
|
|
339
|
-
204: z.void(),
|
|
340
|
-
...refusals(403, 404)
|
|
341
|
-
}
|
|
342
|
-
},
|
|
343
|
-
handler: async (req, reply) => {
|
|
344
|
-
const actor = await actorOf(container, req.orgId, req.userId);
|
|
345
|
-
await chats.mute(req.orgId, actor, req.params.chatId, req.body.until);
|
|
445
|
+
const actor = await resolveActor(container, req);
|
|
446
|
+
await chats.markRead(req.params.chatId, req.body.messageId, actor);
|
|
346
447
|
return reply.code(204).send();
|
|
347
448
|
}
|
|
348
449
|
});
|
|
349
450
|
r.route({
|
|
350
|
-
method: "
|
|
351
|
-
url: "/api/member/chats/:chatId/
|
|
451
|
+
method: "PUT",
|
|
452
|
+
url: "/api/member/chats/:chatId/subscription",
|
|
352
453
|
preHandler: app.requireOrgSession,
|
|
353
454
|
schema: {
|
|
354
|
-
operationId: "
|
|
455
|
+
operationId: "setChatSubscription",
|
|
355
456
|
tags,
|
|
356
|
-
summary: "
|
|
357
|
-
description: "For a participant.",
|
|
457
|
+
summary: "Mute a chat, or clear your mute",
|
|
458
|
+
description: "For a participant. `muted` stops its messages notifying you, until `mutedUntil` when given; a mention still notifies you. `none` clears the mute.",
|
|
358
459
|
params: ChatIdParam,
|
|
460
|
+
body: SetMute,
|
|
359
461
|
response: {
|
|
360
462
|
204: z.void(),
|
|
361
463
|
...refusals(403, 404)
|
|
362
464
|
}
|
|
363
465
|
},
|
|
364
466
|
handler: async (req, reply) => {
|
|
365
|
-
const actor = await
|
|
366
|
-
await
|
|
467
|
+
const actor = await resolveActor(container, req);
|
|
468
|
+
await container.subscriptions.setChat(req.params.chatId, req.body, actor);
|
|
367
469
|
return reply.code(204).send();
|
|
368
470
|
}
|
|
369
471
|
});
|
|
@@ -383,8 +485,8 @@ async function memberChatRoutes(app, container) {
|
|
|
383
485
|
}
|
|
384
486
|
},
|
|
385
487
|
handler: async (req) => {
|
|
386
|
-
const actor = await
|
|
387
|
-
return chats.lock(req.
|
|
488
|
+
const actor = await resolveActor(container, req);
|
|
489
|
+
return chats.lock(req.params.chatId, null, actor);
|
|
388
490
|
}
|
|
389
491
|
});
|
|
390
492
|
r.route({
|
|
@@ -403,8 +505,8 @@ async function memberChatRoutes(app, container) {
|
|
|
403
505
|
}
|
|
404
506
|
},
|
|
405
507
|
handler: async (req) => {
|
|
406
|
-
const actor = await
|
|
407
|
-
return chats.unlock(req.
|
|
508
|
+
const actor = await resolveActor(container, req);
|
|
509
|
+
return chats.unlock(req.params.chatId, null, actor);
|
|
408
510
|
}
|
|
409
511
|
});
|
|
410
512
|
r.route({
|
|
@@ -423,8 +525,8 @@ async function memberChatRoutes(app, container) {
|
|
|
423
525
|
}
|
|
424
526
|
},
|
|
425
527
|
handler: async (req, reply) => {
|
|
426
|
-
const actor = await
|
|
427
|
-
await chats.block(req.
|
|
528
|
+
const actor = await resolveActor(container, req);
|
|
529
|
+
await chats.block(req.params.communityId, req.params.orgUserId, actor);
|
|
428
530
|
return reply.code(204).send();
|
|
429
531
|
}
|
|
430
532
|
});
|
|
@@ -444,8 +546,8 @@ async function memberChatRoutes(app, container) {
|
|
|
444
546
|
}
|
|
445
547
|
},
|
|
446
548
|
handler: async (req, reply) => {
|
|
447
|
-
const actor = await
|
|
448
|
-
await chats.unblock(req.
|
|
549
|
+
const actor = await resolveActor(container, req);
|
|
550
|
+
await chats.unblock(req.params.communityId, req.params.orgUserId, actor);
|
|
449
551
|
return reply.code(204).send();
|
|
450
552
|
}
|
|
451
553
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chats.js","names":[],"sources":["../../../../src/http/routes/member/chats.ts"],"sourcesContent":["import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport { z } from 'zod';\nimport type { Container } from '../../../app/container.js';\nimport { actorOf } from './actor.js';\nimport {\n BlockParam,\n Chat,\n ChatIdParam,\n ChatsPage,\n CommunityParam,\n EditMessage,\n FlagReason,\n PageQuery,\n MarkRead,\n MessageFlag,\n MessageIdParam,\n MessagesPage,\n MessageView,\n MuteChat,\n OrgUserBody,\n Reactions,\n ResolveMessageFlags,\n SendMessage,\n SetReaction,\n StartDirectChat,\n StartGroupChat,\n refusals,\n} from '../../schemas/index.js';\n\nexport async function memberChatRoutes(app: FastifyInstance, container: Container): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n const chats = container.chats;\n const tags = ['Chats'];\n\n r.route({\n method: 'GET',\n url: '/api/member/communities/:communityId/chats',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listMemberChats',\n tags,\n summary: 'List your chats in a community',\n description:\n 'For a member of the community. Every chat you are in, with your unread count and its last message.',\n params: CommunityParam,\n querystring: PageQuery,\n response: { 200: ChatsPage, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n return chats.listChats(req.orgId, actor, req.params.communityId, req.query);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/chats/direct',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'startDirectChat',\n tags,\n summary: 'Start a direct chat, or return the one that already exists',\n description:\n 'For a member of the community, within its direct-message settings (403 otherwise). With the community set so a first message is a request, a new chat starts `pending` until the other person accepts it. 409 when you message yourself, send attachments without a body, or start a request without a message.',\n body: StartDirectChat,\n response: { 200: Chat, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n return chats.startDirect(req.orgId, actor, req.body);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/chats/group',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'startGroupChat',\n tags,\n summary: 'Start a group chat',\n description:\n \"For a member of the community while group chats are on (403 otherwise). Everyone named must hold the community and be someone you may message. 409 when fewer than two others are named or the group would exceed the community's group size.\",\n body: StartGroupChat,\n response: { 201: Chat, ...refusals(403, 404, 409) },\n },\n handler: async (req, reply) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n const chat = await chats.startGroup(req.orgId, actor, req.body);\n return reply.code(201).send(chat);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/chats/:chatId/participants',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'addChatParticipant',\n tags,\n summary: 'Add a person to a group chat you are in',\n description:\n 'For a participant of a group chat. 409 when the chat is direct, the person is already in it, or it is full.',\n params: ChatIdParam,\n body: OrgUserBody,\n response: { 200: Chat, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n return chats.addParticipant(req.orgId, actor, req.params.chatId, req.body.orgUserId);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/chats/:chatId/leave',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'leaveChat',\n tags,\n summary: 'Leave a chat',\n description: 'For a participant. The chat stays for the others.',\n params: ChatIdParam,\n response: { 200: Chat, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n return chats.leave(req.orgId, actor, req.params.chatId);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/chats/:chatId/acceptance',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'acceptChat',\n tags,\n summary: 'Accept a message request',\n description:\n 'For the person the request was sent to. The chat opens for both sides. 409 when the chat is not a pending request.',\n params: ChatIdParam,\n response: { 200: Chat, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n return chats.accept(req.orgId, actor, req.params.chatId);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/member/chats/:chatId/messages',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listChatMessages',\n tags,\n summary: 'Read the messages in a chat, newest first',\n description: 'For a participant of the chat.',\n params: ChatIdParam,\n querystring: PageQuery,\n response: { 200: MessagesPage, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n return chats.messages(req.orgId, actor, req.params.chatId, req.query);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/chats/:chatId/messages',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'sendChatMessage',\n tags,\n summary: 'Send a message',\n description:\n \"For a participant while the chat is open and not locked, and nobody in it has blocked the other (403 otherwise). A request's sender cannot send more until it is accepted.\",\n params: ChatIdParam,\n body: SendMessage,\n response: { 201: MessageView, ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n const message = await chats.send(req.orgId, actor, req.params.chatId, req.body);\n return reply.code(201).send(message);\n },\n });\n\n r.route({\n method: 'PATCH',\n url: '/api/member/messages/:messageId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'editChatMessage',\n tags,\n summary: 'Edit your own message',\n description:\n 'Sender only, while the chat is open and not locked. 409 when the message is deleted.',\n params: MessageIdParam,\n body: EditMessage,\n response: { 200: MessageView, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n return chats.editMessage(req.orgId, actor, req.params.messageId, req.body.body);\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/member/messages/:messageId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'deleteChatMessage',\n tags,\n summary: 'Delete your message, or one in a community you moderate',\n description:\n 'For the sender, or a moderator of the community. The message stays in the history, marked deleted. 409 when it is already deleted.',\n params: MessageIdParam,\n response: { 200: MessageView, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n return chats.deleteMessage(req.orgId, actor, req.params.messageId);\n },\n });\n\n r.route({\n method: 'PUT',\n url: '/api/member/messages/:messageId/reaction',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'setMessageReaction',\n tags,\n summary: 'Set your reaction on a message',\n description:\n 'For a participant of the chat. Replaces any reaction you already had and returns the new counts.',\n params: MessageIdParam,\n body: SetReaction,\n response: { 200: Reactions, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n return chats.setReaction(req.orgId, actor, req.params.messageId, req.body.emoji);\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/member/messages/:messageId/reaction',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'clearMessageReaction',\n tags,\n summary: 'Withdraw your reaction from a message',\n description: 'For a participant of the chat. Returns the new counts.',\n params: MessageIdParam,\n response: { 200: Reactions, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n return chats.setReaction(req.orgId, actor, req.params.messageId, null);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/messages/:messageId/flags',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'flagMessage',\n tags,\n summary: 'Flag a message for the moderators',\n description:\n 'For a participant of the chat. Flagging it again while your flag is open returns that flag.',\n params: MessageIdParam,\n body: FlagReason,\n response: { 201: MessageFlag, ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n const flag = await chats.flagMessage(req.orgId, actor, req.params.messageId, req.body.reason);\n return reply.code(201).send(flag);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/messages/:messageId/flags/resolution',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'resolveMessageFlags',\n tags,\n summary: 'Dismiss the open flags on a message in a community you moderate',\n description:\n 'For a moderator who is a member of the community. Closes every open flag and leaves the message up.',\n params: MessageIdParam,\n body: ResolveMessageFlags,\n response: { 204: z.void(), ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n await chats.resolveMessageFlags(req.orgId, actor, req.params.messageId, req.body.resolution);\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/chats/:chatId/read',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'markChatRead',\n tags,\n summary: 'Mark a chat read up to a message',\n description: 'For a participant. The message must be in the chat (404 otherwise).',\n params: ChatIdParam,\n body: MarkRead,\n response: { 204: z.void(), ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n await chats.markRead(req.orgId, actor, req.params.chatId, req.body.messageId);\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/chats/:chatId/mute',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'muteChat',\n tags,\n summary: 'Mute a chat until a time, or until unmuted',\n description: 'For a participant. Without `until` the chat stays muted until you unmute it.',\n params: ChatIdParam,\n body: MuteChat,\n response: { 204: z.void(), ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n await chats.mute(req.orgId, actor, req.params.chatId, req.body.until);\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/chats/:chatId/unmute',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'unmuteChat',\n tags,\n summary: 'Unmute a chat',\n description: 'For a participant.',\n params: ChatIdParam,\n response: { 204: z.void(), ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n await chats.unmute(req.orgId, actor, req.params.chatId);\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/chats/:chatId/lock',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'lockChat',\n tags,\n summary: 'Lock a chat in a community you moderate',\n description:\n 'For a moderator who is a member of the community. Nobody can send or edit messages until it is unlocked; its open message flags are resolved as `locked`. Locking a locked chat returns it unchanged.',\n params: ChatIdParam,\n response: { 200: Chat, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n return chats.lock(req.orgId, actor, req.params.chatId);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/chats/:chatId/unlock',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'unlockChat',\n tags,\n summary: 'Unlock a chat in a community you moderate',\n description:\n 'For a moderator who is a member of the community. Unlocking an unlocked chat returns it unchanged.',\n params: ChatIdParam,\n response: { 200: Chat, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n return chats.unlock(req.orgId, actor, req.params.chatId);\n },\n });\n\n r.route({\n method: 'PUT',\n url: '/api/member/communities/:communityId/blocks/:orgUserId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'blockMember',\n tags,\n summary: 'Block a person in a community',\n description:\n 'For a member of the community. Neither of you can message the other there; a direct chat between you closes. Blocking twice is harmless. 409 when you block yourself.',\n params: BlockParam,\n response: { 204: z.void(), ...refusals(403, 404, 409) },\n },\n handler: async (req, reply) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n await chats.block(req.orgId, actor, req.params.communityId, req.params.orgUserId);\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/member/communities/:communityId/blocks/:orgUserId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'unblockMember',\n tags,\n summary: 'Unblock a person in a community',\n description:\n 'For a member of the community. A direct chat closed by the block reopens unless a moderator locked it. 409 when you unblock yourself.',\n params: BlockParam,\n response: { 204: z.void(), ...refusals(403, 404, 409) },\n },\n handler: async (req, reply) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n await chats.unblock(req.orgId, actor, req.params.communityId, req.params.orgUserId);\n return reply.code(204).send();\n },\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chats.js","names":[],"sources":["../../../../src/http/routes/member/chats.ts"],"sourcesContent":["import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport { z } from 'zod';\nimport type { Container } from '../../../app/container.js';\nimport { resolveActor } from '../../scope.js';\nimport { sse } from '../../sse.js';\nimport {\n BlockParam,\n Chat,\n ChatIdParam,\n ChatListItem,\n ChatListQuery,\n ChatLiveEvent,\n ChatsPage,\n ChatUnreadSummary,\n CommunityParam,\n DirectChatParam,\n EditMessage,\n FlagReason,\n PageQuery,\n MarkRead,\n MessageQueue,\n MessageFlag,\n MessageIdParam,\n MessagesPage,\n MessageView,\n OrgUserBody,\n Reactions,\n ResolveMessageFlags,\n SendMessage,\n SetMute,\n SetReaction,\n StartDirectChat,\n StartGroupChat,\n refusals,\n} from '../../schemas/index.js';\n\nexport async function memberChatRoutes(app: FastifyInstance, container: Container): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n const chats = container.chats;\n const tags = ['Chats'];\n\n r.route({\n method: 'GET',\n url: '/api/member/communities/:communityId/chats',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listMemberChats',\n tags,\n summary: 'List your chats in a community',\n description:\n 'For a member of the community. Every chat you are in, with your unread count and its last message. `requests=true` lists only the pending message requests to you, `requests=false` everything else.',\n params: CommunityParam,\n querystring: ChatListQuery,\n response: { 200: ChatsPage, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return chats.listChats(req.params.communityId, req.query, actor);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/member/communities/:communityId/chats/events',\n preHandler: app.requireOrgSession,\n config: { eventStream: true },\n schema: {\n operationId: 'streamMemberChatEvents',\n tags,\n summary: 'Stream your chat events in a community',\n description: `Any active member of the organization. For a member of the community. A server-sent event stream of the changes to the chats you are in. It starts with \\`ready\\` and your \\`unread\\`; load your chats on \\`ready\\` and on \\`resync\\`. A \\`: ping\\` comment every 25 s keeps it open. It ends with \\`closed\\` when the server shuts down. 503 when this server has no live delivery.`,\n params: CommunityParam,\n response: {\n 200: { content: { 'text/event-stream': { schema: ChatLiveEvent } } },\n ...refusals(403, 404, 503),\n },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n const events = await chats.watch(req.params.communityId, actor);\n await sse(reply, events);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/member/communities/:communityId/chats/unread',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getMemberChatUnread',\n tags,\n summary: 'Your unread chat total in a community',\n description: `Any active member of the organization. For a member of the community. \\`unread\\` counts the unread messages in your chats that are neither muted nor requests to you, plus your pending requests; \\`requests\\` is the number of pending requests to you.`,\n params: CommunityParam,\n response: { 200: ChatUnreadSummary, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return chats.unreadSummary(req.params.communityId, actor);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/member/communities/:communityId/chats/direct/:orgUserId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getMemberDirectChat',\n tags,\n summary: 'Your direct chat with a person',\n description: `Any active member of the organization. For a member of the community. Your direct chat with the person while you are in it; 404 when there is none.`,\n params: DirectChatParam,\n response: { 200: ChatListItem, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return chats.directChat(req.params.communityId, req.params.orgUserId, actor);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/member/chats/:chatId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getMemberChat',\n tags,\n summary: 'Read one of your chats',\n description: `Any active member of the organization. For a participant of the chat. The chat as it appears in your chat list.`,\n params: ChatIdParam,\n response: { 200: ChatListItem, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return chats.chat(req.params.chatId, actor);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/chats/:chatId/typing',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'sendChatTyping',\n tags,\n summary: 'Tell the chat you are typing',\n description: `Any active member of the organization. For a participant while the chat is open and not locked (403 otherwise). The others see you typing for 5 s; a repeat within 2 s is dropped.`,\n params: ChatIdParam,\n response: { 204: z.void(), ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n await chats.typing(req.params.chatId, actor);\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/member/communities/:communityId/message-queue',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getMemberMessageQueue',\n tags,\n summary: 'Open message flags in a community you moderate',\n description: `Requires \\`communities:moderate\\`. Needed on the community, as a member of it. The messages in its chats with open flags, with the flags and the chat each is in. Holds at most the 100 oldest open flags; working the queue brings in the next ones.`,\n params: CommunityParam,\n response: { 200: MessageQueue, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return chats.messageQueue(req.params.communityId, actor);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/chats/direct',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'startDirectChat',\n tags,\n summary: 'Start a direct chat, or return the one that already exists',\n description:\n 'For a member of the community, within its direct-message settings (403 otherwise). With the community set so a first message is a request, a new chat starts `pending` until the other person accepts it. 409 when you message yourself, send attachments without a body, or start a request without a message.',\n body: StartDirectChat,\n response: { 200: Chat, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return chats.startDirect(req.body, actor);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/chats/group',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'startGroupChat',\n tags,\n summary: 'Start a group chat',\n description:\n \"For a member of the community while group chats are on (403 otherwise). Everyone named must hold the community and be someone you may message. 409 when fewer than two others are named or the group would exceed the community's group size.\",\n body: StartGroupChat,\n response: { 201: Chat, ...refusals(403, 404, 409) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n const chat = await chats.startGroup(req.body, actor);\n return reply.code(201).send(chat);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/chats/:chatId/participants',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'addChatParticipant',\n tags,\n summary: 'Add a person to a group chat you are in',\n description:\n 'For a participant of a group chat. 409 when the chat is direct, the person is already in it, or it is full.',\n params: ChatIdParam,\n body: OrgUserBody,\n response: { 200: Chat, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return chats.addParticipant(req.params.chatId, req.body.orgUserId, actor);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/chats/:chatId/leave',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'leaveChat',\n tags,\n summary: 'Leave a chat',\n description: 'For a participant. The chat stays for the others.',\n params: ChatIdParam,\n response: { 200: Chat, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return chats.leave(req.params.chatId, actor);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/chats/:chatId/accept',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'acceptChat',\n tags,\n summary: 'Accept a message request',\n description:\n 'For the person the request was sent to. The chat opens for both sides. 409 when the chat is not a pending request.',\n params: ChatIdParam,\n response: { 200: Chat, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return chats.accept(req.params.chatId, actor);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/member/chats/:chatId/messages',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listChatMessages',\n tags,\n summary: 'Read the messages in a chat, newest first',\n description: 'For a participant of the chat.',\n params: ChatIdParam,\n querystring: PageQuery,\n response: { 200: MessagesPage, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return chats.messages(req.params.chatId, req.query, actor);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/chats/:chatId/messages',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'sendChatMessage',\n tags,\n summary: 'Send a message',\n description:\n \"For a participant while the chat is open and not locked, and nobody in it has blocked the other (403 otherwise). A request's sender cannot send more until it is accepted. Sending again with the same `clientId` returns the message already sent.\",\n params: ChatIdParam,\n body: SendMessage,\n response: { 201: MessageView, ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n const message = await chats.send(req.params.chatId, req.body, actor);\n return reply.code(201).send(message);\n },\n });\n\n r.route({\n method: 'PATCH',\n url: '/api/member/messages/:messageId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'editChatMessage',\n tags,\n summary: 'Edit your own message',\n description:\n 'Sender only, while the chat is open and not locked. 409 when the message is deleted.',\n params: MessageIdParam,\n body: EditMessage,\n response: { 200: MessageView, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return chats.editMessage(req.params.messageId, req.body.body, actor);\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/member/messages/:messageId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'deleteChatMessage',\n tags,\n summary: 'Delete your message, or one in a community you moderate',\n description:\n 'For the sender, or a moderator of the community. The message stays in the history, marked deleted. 409 when it is already deleted.',\n params: MessageIdParam,\n response: { 200: MessageView, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return chats.deleteMessage(req.params.messageId, actor);\n },\n });\n\n r.route({\n method: 'PUT',\n url: '/api/member/messages/:messageId/reaction',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'setMessageReaction',\n tags,\n summary: 'Set your reaction on a message',\n description:\n 'For a participant of the chat. Replaces any reaction you already had and returns the new counts.',\n params: MessageIdParam,\n body: SetReaction,\n response: { 200: Reactions, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return chats.setReaction(req.params.messageId, req.body.emoji, actor);\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/member/messages/:messageId/reaction',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'clearMessageReaction',\n tags,\n summary: 'Withdraw your reaction from a message',\n description: 'For a participant of the chat. Returns the new counts.',\n params: MessageIdParam,\n response: { 200: Reactions, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return chats.setReaction(req.params.messageId, null, actor);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/messages/:messageId/flags',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'flagMessage',\n tags,\n summary: 'Flag a message for the moderators',\n description:\n 'For a participant of the chat. Flagging it again while your flag is open returns that flag.',\n params: MessageIdParam,\n body: FlagReason,\n response: { 201: MessageFlag, ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n const flag = await chats.flagMessage(req.params.messageId, req.body.reason, actor);\n return reply.code(201).send(flag);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/messages/:messageId/flags/resolve',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'resolveMessageFlags',\n tags,\n summary: 'Dismiss the open flags on a message in a community you moderate',\n description:\n 'For a moderator who is a member of the community. Closes every open flag and leaves the message up.',\n params: MessageIdParam,\n body: ResolveMessageFlags,\n response: { 204: z.void(), ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n await chats.resolveMessageFlags(req.params.messageId, req.body.resolution, null, actor);\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/chats/:chatId/read',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'markChatRead',\n tags,\n summary: 'Mark a chat read up to a message',\n description: 'For a participant. The message must be in the chat (404 otherwise).',\n params: ChatIdParam,\n body: MarkRead,\n response: { 204: z.void(), ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n await chats.markRead(req.params.chatId, req.body.messageId, actor);\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'PUT',\n url: '/api/member/chats/:chatId/subscription',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'setChatSubscription',\n tags,\n summary: 'Mute a chat, or clear your mute',\n description:\n 'For a participant. `muted` stops its messages notifying you, until `mutedUntil` when given; a mention still notifies you. `none` clears the mute.',\n params: ChatIdParam,\n body: SetMute,\n response: { 204: z.void(), ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n await container.subscriptions.setChat(req.params.chatId, req.body, actor);\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/chats/:chatId/lock',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'lockChat',\n tags,\n summary: 'Lock a chat in a community you moderate',\n description:\n 'For a moderator who is a member of the community. Nobody can send or edit messages until it is unlocked; its open message flags are resolved as `locked`. Locking a locked chat returns it unchanged.',\n params: ChatIdParam,\n response: { 200: Chat, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return chats.lock(req.params.chatId, null, actor);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/chats/:chatId/unlock',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'unlockChat',\n tags,\n summary: 'Unlock a chat in a community you moderate',\n description:\n 'For a moderator who is a member of the community. Unlocking an unlocked chat returns it unchanged.',\n params: ChatIdParam,\n response: { 200: Chat, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return chats.unlock(req.params.chatId, null, actor);\n },\n });\n\n r.route({\n method: 'PUT',\n url: '/api/member/communities/:communityId/blocks/:orgUserId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'blockMember',\n tags,\n summary: 'Block a person in a community',\n description:\n 'For a member of the community. Neither of you can message the other there; a direct chat between you closes. Blocking twice is harmless. 409 when you block yourself.',\n params: BlockParam,\n response: { 204: z.void(), ...refusals(403, 404, 409) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n await chats.block(req.params.communityId, req.params.orgUserId, actor);\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/member/communities/:communityId/blocks/:orgUserId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'unblockMember',\n tags,\n summary: 'Unblock a person in a community',\n description:\n 'For a member of the community. A direct chat closed by the block reopens unless a moderator locked it. 409 when you unblock yourself.',\n params: BlockParam,\n response: { 204: z.void(), ...refusals(403, 404, 409) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n await chats.unblock(req.params.communityId, req.params.orgUserId, actor);\n return reply.code(204).send();\n },\n });\n}\n"],"mappings":"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"}
|