@headless-lms/server 0.3.0 → 0.4.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.
Files changed (73) hide show
  1. package/dist/app/community-mail.d.ts +6 -8
  2. package/dist/app/community-mail.js +13 -17
  3. package/dist/app/community-mail.js.map +1 -1
  4. package/dist/app/container.d.ts +27 -10
  5. package/dist/app/container.js +178 -22
  6. package/dist/app/container.js.map +1 -1
  7. package/dist/app/notification-channels.d.ts +47 -0
  8. package/dist/app/notification-channels.js +174 -0
  9. package/dist/app/notification-channels.js.map +1 -0
  10. package/dist/app/notification-reads.d.ts +23 -0
  11. package/dist/app/notification-reads.js +95 -0
  12. package/dist/app/notification-reads.js.map +1 -0
  13. package/dist/http/errors.d.ts +1 -0
  14. package/dist/http/errors.js +16 -1
  15. package/dist/http/errors.js.map +1 -1
  16. package/dist/http/mcp/tools/communities.js +1 -1
  17. package/dist/http/mcp/tools/communities.js.map +1 -1
  18. package/dist/http/plugins/error-handler.js +3 -1
  19. package/dist/http/plugins/error-handler.js.map +1 -1
  20. package/dist/http/routes/automations.js +3 -3
  21. package/dist/http/routes/automations.js.map +1 -1
  22. package/dist/http/routes/communities.js +67 -7
  23. package/dist/http/routes/communities.js.map +1 -1
  24. package/dist/http/routes/member/actor.d.ts +1 -1
  25. package/dist/http/routes/member/chats.js +9 -30
  26. package/dist/http/routes/member/chats.js.map +1 -1
  27. package/dist/http/routes/member/community.js +25 -1
  28. package/dist/http/routes/member/community.js.map +1 -1
  29. package/dist/http/routes/member/devices.d.ts +7 -0
  30. package/dist/http/routes/member/devices.js +98 -0
  31. package/dist/http/routes/member/devices.js.map +1 -0
  32. package/dist/http/routes/member/index.js +4 -0
  33. package/dist/http/routes/member/index.js.map +1 -1
  34. package/dist/http/routes/member/notification-settings.d.ts +7 -0
  35. package/dist/http/routes/member/notification-settings.js +108 -0
  36. package/dist/http/routes/member/notification-settings.js.map +1 -0
  37. package/dist/http/routes/member/notifications.js +66 -42
  38. package/dist/http/routes/member/notifications.js.map +1 -1
  39. package/dist/http/routes/member/posts.js +33 -33
  40. package/dist/http/routes/member/posts.js.map +1 -1
  41. package/dist/http/routes/organizations.js +122 -1
  42. package/dist/http/routes/organizations.js.map +1 -1
  43. package/dist/http/schemas/assets.d.ts +6 -6
  44. package/dist/http/schemas/automations.d.ts +0 -4
  45. package/dist/http/schemas/chats.d.ts +34 -11
  46. package/dist/http/schemas/chats.js +4 -6
  47. package/dist/http/schemas/chats.js.map +1 -1
  48. package/dist/http/schemas/community.d.ts +77 -17
  49. package/dist/http/schemas/community.js +6 -3
  50. package/dist/http/schemas/community.js.map +1 -1
  51. package/dist/http/schemas/discussion.d.ts +23 -1
  52. package/dist/http/schemas/discussion.js +14 -2
  53. package/dist/http/schemas/discussion.js.map +1 -1
  54. package/dist/http/schemas/index.d.ts +6 -6
  55. package/dist/http/schemas/index.js +6 -6
  56. package/dist/http/schemas/integrations.d.ts +4 -4
  57. package/dist/http/schemas/members.d.ts +5 -5
  58. package/dist/http/schemas/notifications.d.ts +498 -175
  59. package/dist/http/schemas/notifications.js +148 -28
  60. package/dist/http/schemas/notifications.js.map +1 -1
  61. package/dist/http/schemas/posts.d.ts +37 -3
  62. package/dist/http/schemas/profile.d.ts +2 -2
  63. package/dist/http/schemas/shared.d.ts +10 -3
  64. package/dist/http/schemas/shared.js +3 -2
  65. package/dist/http/schemas/shared.js.map +1 -1
  66. package/dist/http/schemas/students.d.ts +3 -3
  67. package/dist/http/scope.d.ts +2 -1
  68. package/dist/http/scope.js +7 -1
  69. package/dist/http/scope.js.map +1 -1
  70. package/dist/index.d.ts +2 -1
  71. package/dist/index.js.map +1 -1
  72. package/dist/packages/server/package.js +1 -1
  73. package/package.json +5 -5
@@ -1 +1 @@
1
- {"version":3,"file":"organizations.js","names":[],"sources":["../../../src/http/routes/organizations.ts"],"sourcesContent":["import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport { z } from 'zod';\nimport {\n AcceptInvite,\n AcceptInviteResult,\n CreateInvite,\n CreateOrganization,\n Invite,\n MemberIdParam,\n MemberRoleChange,\n MembersPage,\n MembersQuery,\n GetInviteResult,\n InviteTokenParam,\n Organization,\n UpdateMemberRole,\n UpdateOrganization,\n refusals,\n} from '../schemas/index.js';\nimport type { MemberWriteContext } from '@headless-lms/core/organizations';\nimport { NotFoundError } from '@headless-lms/core/shared/errors';\nimport type { Container } from '../../app/container.js';\nimport { resolveScope } from '../scope.js';\n\nexport async function organizationsRoutes(\n app: FastifyInstance,\n container: Container,\n): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n const organizations = container.organizations;\n const tags = ['Organizations'];\n\n // Create a new organization on the caller's behalf and make it their active\n // org. This is the API's own front door for org creation — it drives Better\n // Auth internally, so callers use the typed SDK, not the auth namespace. No\n // resolveScope here: the caller has no active org yet, only a session.\n r.route({\n method: 'POST',\n url: '/api/organizations',\n // Session only: a first-time signup has no active org yet, so requiring one\n // here would 401 the very call that produces it.\n preHandler: app.requireSession,\n schema: {\n operationId: 'createOrganization',\n tags,\n summary: 'Create an organization and make it active',\n description:\n 'For any signed-in person, including one with no organization yet. The caller becomes its owner.',\n body: CreateOrganization,\n response: { 201: Organization },\n },\n handler: async (req, reply) => {\n const org = await container.orgProvider.createOrganization(req.headers, req.body);\n return reply.code(201).send({\n name: org.name,\n slug: org.slug,\n id: org.id,\n createdAt: org.createdAt.toISOString(),\n });\n },\n });\n\n // Update the caller's active organization (name/slug). Writes go through Better\n // Auth, which enforces the caller's org-update permission (owner/admin).\n r.route({\n method: 'PATCH',\n url: '/api/organizations',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'updateOrganization',\n tags,\n summary: 'Update the active organization (staff)',\n description: 'Owner or admin. Changes its name or slug; 409 when the slug is taken.',\n body: UpdateOrganization,\n response: { 200: Organization, ...refusals(403, 409) },\n },\n handler: async (req, reply) => {\n const scope = await resolveScope(container, req);\n const org = await container.orgProvider.updateOrganization(\n req.headers,\n scope.authOrgId,\n req.body,\n );\n return reply.send({\n id: org.id,\n name: org.name,\n slug: org.slug,\n createdAt: org.createdAt.toISOString(),\n });\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/organizations/members',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listMembers',\n tags,\n summary: \"List the organization's team members (staff)\",\n description:\n 'Staff only (owner, admin, instructor). The team: everyone in the organization who is not a student.',\n querystring: MembersQuery,\n response: { 200: MembersPage, ...refusals(403) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return organizations.listMembers(scope.orgId, req.query);\n },\n });\n\n r.route({\n method: 'PATCH',\n url: '/api/organizations/members/:id/role',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'updateMemberRole',\n tags,\n summary: \"Change a member's role (staff)\",\n description:\n 'Owner or admin only. The owner role can be neither granted nor changed (409), and only a moderator can become a student.',\n params: MemberIdParam,\n body: UpdateMemberRole,\n response: { 200: MemberRoleChange, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n const ctx: MemberWriteContext = {\n orgId: scope.orgId,\n authOrgId: scope.authOrgId,\n headers: req.headers,\n };\n const member = await organizations.updateMemberRole(\n ctx,\n { id: scope.orgUserId, role: scope.role },\n req.params.id,\n req.body.role,\n );\n if (!member) {\n throw new NotFoundError('Member', req.params.id);\n }\n return member;\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/organizations/members/:id',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'removeMember',\n tags,\n summary: 'Remove an organization member (staff)',\n description:\n 'Owner or admin only. Removing a pending member cancels their invite. The owner cannot be removed (409).',\n params: MemberIdParam,\n response: { 204: z.void(), ...refusals(403, 404, 409) },\n },\n handler: async (req, reply) => {\n const scope = await resolveScope(container, req);\n const ctx: MemberWriteContext = {\n orgId: scope.orgId,\n authOrgId: scope.authOrgId,\n headers: req.headers,\n };\n const removed = await organizations.removeMember(\n ctx,\n { id: scope.orgUserId, role: scope.role },\n req.params.id,\n );\n if (!removed) {\n throw new NotFoundError('Member', req.params.id);\n }\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/organizations/invites',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'createInvite',\n tags,\n summary: 'Invite a member or student into the active organization (staff)',\n description:\n 'Owner or admin only. A student is created by this call, so their access can be granted before they accept. 409 when a student with that email is already in the organization.',\n body: CreateInvite,\n response: { 201: Invite, ...refusals(403, 409) },\n },\n handler: async (req, reply) => {\n // Domain ids, not the session's auth ids: invites FK to organizations.id\n // and users.id.\n const scope = await resolveScope(container, req);\n const invite = await organizations.createInvite(\n { id: scope.orgUserId, role: scope.role },\n {\n orgId: scope.orgId,\n inviterUserId: scope.userId,\n email: req.body.email,\n role: req.body.role,\n ...(req.body.firstName !== undefined && { firstName: req.body.firstName }),\n ...(req.body.lastName !== undefined && { lastName: req.body.lastName }),\n sendEmail: req.body.sendEmail,\n },\n );\n\n req.log.debug({ inviteId: invite.id }, 'created invite');\n return reply.code(201).send({\n id: invite.id,\n email: invite.email,\n role: invite.role,\n status: invite.status,\n expiresAt: invite.expiresAt,\n createdAt: invite.createdAt,\n });\n },\n });\n\n // The invite landing page's first call, made before the invitee has any\n // session — so no guard. It turns the emailed token into the two facts the\n // page needs: who the invitation is for, and whether that address already has\n // an account. The email comes from the invitation row rather than the URL, so\n // it cannot be steered by editing the link.\n r.route({\n method: 'GET',\n url: '/api/organizations/invites/:token',\n schema: {\n operationId: 'getInvite',\n tags,\n summary: 'Read an invite by its token',\n description:\n 'Public: no session needed. The same 404 answers forged, expired and accepted tokens, so a probe learns nothing.',\n params: InviteTokenParam,\n response: { 200: GetInviteResult, ...refusals(404) },\n },\n handler: async (req) => {\n const invite = await organizations.peekInvite(req.params.token);\n if (!invite) {\n // Same answer for forged, expired, and already-accepted tokens: a\n // probe learns nothing about which invitations exist.\n throw new NotFoundError('Invite', 'token');\n }\n // Whether the address already has a login is deliberately not answered\n // here. The mirror cannot say — an admin's student is a person long\n // before they are an account — and asking the auth engine would mean\n // reading its tables for one boolean. The sign-up form discovers it\n // instead: a duplicate signup comes back 422 and the page flips to\n // sign-in.\n const person = await container.identity.getUserByEmail(invite.email);\n return {\n email: invite.email,\n firstName: person?.firstName ?? null,\n lastName: person?.lastName ?? null,\n };\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/organizations/invites/accept',\n preHandler: app.requireSession,\n schema: {\n operationId: 'acceptInvite',\n tags,\n summary: 'Accept an invite with the signed-in account',\n description:\n \"For any signed-in person whose email matches the invitation. Makes the invite's organization the session's active one. 400 when the token is invalid or expired, or the email does not match.\",\n body: AcceptInvite,\n response: { 200: AcceptInviteResult, ...refusals(400, 404) },\n },\n handler: async (req) => {\n // No active org yet, so no resolveScope — but acceptInvite links a domain\n // users.id, never the auth account id.\n const user = await container.identity.getUserByExternalId(req.authUser.id);\n if (!user) {\n throw new NotFoundError('User', req.authUser.id);\n }\n const accepted = await container.organizations.acceptInvite({\n token: req.body.token,\n userId: user.id,\n email: req.authUser.email,\n });\n\n // The session predates this grant, so it carries no active org and every\n // org-scoped read would 401. Students are never org members, so the org\n // plugin's set-active cannot do it — stamp the session row directly.\n const org = await container.organizations.getById(accepted.orgId);\n if (!org) {\n throw new NotFoundError('Organization', accepted.orgId);\n }\n const stamped = await container.sessions.stampActiveOrganization(req.headers, org.id);\n\n req.log.info({ accepted, stamped }, 'accepted invite');\n return {};\n },\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"organizations.js","names":[],"sources":["../../../src/http/routes/organizations.ts"],"sourcesContent":["import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport { z } from 'zod';\nimport {\n AcceptInvite,\n AcceptInviteResult,\n CreateInvite,\n CreateOrganization,\n Invite,\n MemberIdParam,\n NotificationCategoryDefaults,\n NotificationCategoryList,\n NotificationChannelInfos,\n NotificationListScopeQuery,\n NotificationTypeInfos,\n ReplaceNotificationCategories,\n MemberRoleChange,\n MembersPage,\n MembersQuery,\n GetInviteResult,\n InviteTokenParam,\n Organization,\n UpdateMemberRole,\n UpdateOrganization,\n refusals,\n} from '../schemas/index.js';\nimport type { MemberWriteContext } from '@headless-lms/core/organizations';\nimport { NotFoundError } from '@headless-lms/core/shared/errors';\nimport type { Container } from '../../app/container.js';\nimport { resolveConfiguratorScope, resolveScope } from '../scope.js';\nimport { typesForList } from '@headless-lms/core/shared/notification-categories';\n\nexport async function organizationsRoutes(\n app: FastifyInstance,\n container: Container,\n): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n const organizations = container.organizations;\n const tags = ['Organizations'];\n\n // Create a new organization on the caller's behalf and make it their active\n // org. This is the API's own front door for org creation — it drives Better\n // Auth internally, so callers use the typed SDK, not the auth namespace. No\n // resolveScope here: the caller has no active org yet, only a session.\n r.route({\n method: 'POST',\n url: '/api/organizations',\n // Session only: a first-time signup has no active org yet, so requiring one\n // here would 401 the very call that produces it.\n preHandler: app.requireSession,\n schema: {\n operationId: 'createOrganization',\n tags,\n summary: 'Create an organization and make it active',\n description:\n 'For any signed-in person, including one with no organization yet. The caller becomes its owner.',\n body: CreateOrganization,\n response: { 201: Organization },\n },\n handler: async (req, reply) => {\n const org = await container.orgProvider.createOrganization(req.headers, req.body);\n return reply.code(201).send({\n name: org.name,\n slug: org.slug,\n id: org.id,\n createdAt: org.createdAt.toISOString(),\n });\n },\n });\n\n // Update the caller's active organization (name/slug). Writes go through Better\n // Auth, which enforces the caller's org-update permission (owner/admin).\n r.route({\n method: 'PATCH',\n url: '/api/organizations',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'updateOrganization',\n tags,\n summary: 'Update the active organization (staff)',\n description: 'Owner or admin. Changes its name or slug; 409 when the slug is taken.',\n body: UpdateOrganization,\n response: { 200: Organization, ...refusals(403, 409) },\n },\n handler: async (req, reply) => {\n const scope = await resolveScope(container, req);\n const org = await container.orgProvider.updateOrganization(\n req.headers,\n scope.authOrgId,\n req.body,\n );\n return reply.send({\n id: org.id,\n name: org.name,\n slug: org.slug,\n createdAt: org.createdAt.toISOString(),\n });\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/organizations/members',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listMembers',\n tags,\n summary: \"List the organization's team members (staff)\",\n description:\n 'Staff only (owner, admin, instructor). The team: everyone in the organization who is not a student.',\n querystring: MembersQuery,\n response: { 200: MembersPage, ...refusals(403) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return organizations.listMembers(scope.orgId, req.query);\n },\n });\n\n r.route({\n method: 'PATCH',\n url: '/api/organizations/members/:id/role',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'updateMemberRole',\n tags,\n summary: \"Change a member's role (staff)\",\n description:\n 'Owner or admin only. The owner role can be neither granted nor changed (409), and only a moderator can become a student.',\n params: MemberIdParam,\n body: UpdateMemberRole,\n response: { 200: MemberRoleChange, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n const ctx: MemberWriteContext = {\n orgId: scope.orgId,\n authOrgId: scope.authOrgId,\n headers: req.headers,\n };\n const member = await organizations.updateMemberRole(\n ctx,\n { id: scope.orgUserId, role: scope.role },\n req.params.id,\n req.body.role,\n );\n if (!member) {\n throw new NotFoundError('Member', req.params.id);\n }\n return member;\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/organizations/members/:id',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'removeMember',\n tags,\n summary: 'Remove an organization member (staff)',\n description:\n 'Owner or admin only. Removing a pending member cancels their invite. The owner cannot be removed (409).',\n params: MemberIdParam,\n response: { 204: z.void(), ...refusals(403, 404, 409) },\n },\n handler: async (req, reply) => {\n const scope = await resolveScope(container, req);\n const ctx: MemberWriteContext = {\n orgId: scope.orgId,\n authOrgId: scope.authOrgId,\n headers: req.headers,\n };\n const removed = await organizations.removeMember(\n ctx,\n { id: scope.orgUserId, role: scope.role },\n req.params.id,\n );\n if (!removed) {\n throw new NotFoundError('Member', req.params.id);\n }\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/organizations/invites',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'createInvite',\n tags,\n summary: 'Invite a member or student into the active organization (staff)',\n description:\n 'Owner or admin only. A student is created by this call, so their access can be granted before they accept. 409 when a student with that email is already in the organization.',\n body: CreateInvite,\n response: { 201: Invite, ...refusals(403, 409) },\n },\n handler: async (req, reply) => {\n // Domain ids, not the session's auth ids: invites FK to organizations.id\n // and users.id.\n const scope = await resolveScope(container, req);\n const invite = await organizations.createInvite(\n { id: scope.orgUserId, role: scope.role },\n {\n orgId: scope.orgId,\n inviterUserId: scope.userId,\n email: req.body.email,\n role: req.body.role,\n ...(req.body.firstName !== undefined && { firstName: req.body.firstName }),\n ...(req.body.lastName !== undefined && { lastName: req.body.lastName }),\n sendEmail: req.body.sendEmail,\n },\n );\n\n req.log.debug({ inviteId: invite.id }, 'created invite');\n return reply.code(201).send({\n id: invite.id,\n email: invite.email,\n role: invite.role,\n status: invite.status,\n expiresAt: invite.expiresAt,\n createdAt: invite.createdAt,\n });\n },\n });\n\n // The invite landing page's first call, made before the invitee has any\n // session — so no guard. It turns the emailed token into the two facts the\n // page needs: who the invitation is for, and whether that address already has\n // an account. The email comes from the invitation row rather than the URL, so\n // it cannot be steered by editing the link.\n r.route({\n method: 'GET',\n url: '/api/organizations/invites/:token',\n schema: {\n operationId: 'getInvite',\n tags,\n summary: 'Read an invite by its token',\n description:\n 'Public: no session needed. The same 404 answers forged, expired and accepted tokens, so a probe learns nothing.',\n params: InviteTokenParam,\n response: { 200: GetInviteResult, ...refusals(404) },\n },\n handler: async (req) => {\n const invite = await organizations.peekInvite(req.params.token);\n if (!invite) {\n // Same answer for forged, expired, and already-accepted tokens: a\n // probe learns nothing about which invitations exist.\n throw new NotFoundError('Invite', 'token');\n }\n // Whether the address already has a login is deliberately not answered\n // here. The mirror cannot say — an admin's student is a person long\n // before they are an account — and asking the auth engine would mean\n // reading its tables for one boolean. The sign-up form discovers it\n // instead: a duplicate signup comes back 422 and the page flips to\n // sign-in.\n const person = await container.identity.getUserByEmail(invite.email);\n return {\n email: invite.email,\n firstName: person?.firstName ?? null,\n lastName: person?.lastName ?? null,\n };\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/organizations/invites/accept',\n preHandler: app.requireSession,\n schema: {\n operationId: 'acceptInvite',\n tags,\n summary: 'Accept an invite with the signed-in account',\n description:\n \"For any signed-in person whose email matches the invitation. Makes the invite's organization the session's active one. 400 when the token is invalid or expired, or the email does not match.\",\n body: AcceptInvite,\n response: { 200: AcceptInviteResult, ...refusals(400, 404) },\n },\n handler: async (req) => {\n // No active org yet, so no resolveScope — but acceptInvite links a domain\n // users.id, never the auth account id.\n const user = await container.identity.getUserByExternalId(req.authUser.id);\n if (!user) {\n throw new NotFoundError('User', req.authUser.id);\n }\n const accepted = await container.organizations.acceptInvite({\n token: req.body.token,\n userId: user.id,\n email: req.authUser.email,\n });\n\n // The session predates this grant, so it carries no active org and every\n // org-scoped read would 401. Students are never org members, so the org\n // plugin's set-active cannot do it — stamp the session row directly.\n const org = await container.organizations.getById(accepted.orgId);\n if (!org) {\n throw new NotFoundError('Organization', accepted.orgId);\n }\n const stamped = await container.sessions.stampActiveOrganization(req.headers, org.id);\n\n req.log.info({ accepted, stamped }, 'accepted invite');\n return {};\n },\n });\n\n const notificationTags = ['Notifications'];\n\n r.route({\n method: 'GET',\n url: '/api/notification-types',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listNotificationTypes',\n tags: notificationTags,\n summary: 'List the notification types a category list can cover (staff)',\n description:\n 'Owner or admin only. `scope=org` lists the types the org list can cover, `scope=community` those a community list can cover. Each type carries all its scopes, so an editor can tell which types can be per space.',\n querystring: NotificationListScopeQuery,\n response: { 200: NotificationTypeInfos, ...refusals(403) },\n },\n handler: async (req) => {\n await resolveConfiguratorScope(container, req);\n return typesForList(container.notificationTypes, req.query.scope);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/notification-channels',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listNotificationChannels',\n tags: notificationTags,\n summary: 'List the notification channels this deployment can deliver on (staff)',\n description: 'Owner or admin only. `inApp` is always first.',\n response: { 200: NotificationChannelInfos, ...refusals(403) },\n },\n handler: async (req) => {\n await resolveConfiguratorScope(container, req);\n return container.notificationChannels.list().map((channel) => ({ channel }));\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/notification-categories',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getOrgNotificationCategories',\n tags: notificationTags,\n summary: \"Get the organization's notification categories (staff)\",\n description:\n 'Owner or admin only. The list in use for notifications outside any community, with `source` saying whether it is the default or a stored list.',\n response: { 200: NotificationCategoryList, ...refusals(403) },\n },\n handler: async (req) => {\n const scope = await resolveConfiguratorScope(container, req);\n return container.notificationCategories.org.get(scope.orgId, scope.orgId);\n },\n });\n\n r.route({\n method: 'PUT',\n url: '/api/notification-categories',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'replaceOrgNotificationCategories',\n tags: notificationTags,\n summary: \"Replace the organization's notification categories (staff)\",\n description:\n 'Owner or admin only. Stores the whole list. 422 when a key repeats, a type cannot be in the org list, a reason is not allowed for its type, a channel is not configured, or earlier categories already cover everything a category covers.',\n body: ReplaceNotificationCategories,\n response: { 200: NotificationCategoryList, ...refusals(400, 403, 422) },\n },\n handler: async (req) => {\n const scope = await resolveConfiguratorScope(container, req);\n return container.notificationCategories.org.replace(\n scope.orgId,\n scope.orgId,\n req.body.categories,\n );\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/notification-categories',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'resetOrgNotificationCategories',\n tags: notificationTags,\n summary: 'Go back to the default notification categories for the organization (staff)',\n description: 'Owner or admin only. Removes the stored list; the default applies again.',\n response: { 204: z.void(), ...refusals(403) },\n },\n handler: async (req, reply) => {\n const scope = await resolveConfiguratorScope(container, req);\n await container.notificationCategories.org.reset(scope.orgId, scope.orgId);\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/notification-categories/defaults',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getDefaultNotificationCategories',\n tags: notificationTags,\n summary: 'Get the default notification categories (staff)',\n description:\n 'Owner or admin only. The default org list (`scope=org`) or community list (`scope=community`), offering only the configured channels.',\n querystring: NotificationListScopeQuery,\n response: { 200: NotificationCategoryDefaults, ...refusals(403) },\n },\n handler: async (req) => {\n await resolveConfiguratorScope(container, req);\n const service =\n req.query.scope === 'org'\n ? container.notificationCategories.org\n : container.notificationCategories.community;\n return { categories: service.defaults() };\n },\n });\n}\n"],"mappings":"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"}
@@ -18,13 +18,13 @@ declare const AssetStatus: z.ZodEnum<{
18
18
  }>;
19
19
  type AssetStatus = z.infer<typeof AssetStatus>;
20
20
  declare const Asset: z.ZodObject<{
21
- orgId: z.ZodString;
22
21
  id: z.ZodString;
22
+ createdAt: z.ZodCoercedDate<unknown>;
23
23
  status: z.ZodEnum<{
24
24
  pending: "pending";
25
25
  ready: "ready";
26
26
  }>;
27
- createdAt: z.ZodCoercedDate<unknown>;
27
+ orgId: z.ZodString;
28
28
  updatedAt: z.ZodCoercedDate<unknown>;
29
29
  uploadedBy: z.ZodString;
30
30
  filename: z.ZodString;
@@ -63,13 +63,13 @@ declare const AssetsQuery: z.ZodObject<{
63
63
  type AssetsQuery = z.infer<typeof AssetsQuery>;
64
64
  declare const AssetsPage: z.ZodObject<{
65
65
  rows: z.ZodArray<z.ZodObject<{
66
- orgId: z.ZodString;
67
66
  id: z.ZodString;
67
+ createdAt: z.ZodCoercedDate<unknown>;
68
68
  status: z.ZodEnum<{
69
69
  pending: "pending";
70
70
  ready: "ready";
71
71
  }>;
72
- createdAt: z.ZodCoercedDate<unknown>;
72
+ orgId: z.ZodString;
73
73
  updatedAt: z.ZodCoercedDate<unknown>;
74
74
  uploadedBy: z.ZodString;
75
75
  filename: z.ZodString;
@@ -113,13 +113,13 @@ declare const UploadTicket: z.ZodObject<{
113
113
  expiresInSeconds: z.ZodNumber;
114
114
  headers: z.ZodRecord<z.ZodString, z.ZodString>;
115
115
  asset: z.ZodObject<{
116
- orgId: z.ZodString;
117
116
  id: z.ZodString;
117
+ createdAt: z.ZodCoercedDate<unknown>;
118
118
  status: z.ZodEnum<{
119
119
  pending: "pending";
120
120
  ready: "ready";
121
121
  }>;
122
- createdAt: z.ZodCoercedDate<unknown>;
122
+ orgId: z.ZodString;
123
123
  updatedAt: z.ZodCoercedDate<unknown>;
124
124
  uploadedBy: z.ZodString;
125
125
  filename: z.ZodString;
@@ -30,10 +30,6 @@ declare const Automation: z.ZodObject<{
30
30
  }, z.core.$strict>>;
31
31
  enabled: z.ZodBoolean;
32
32
  filter: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodType<import("@headless-lms/core/types").JsonValue, unknown, z.core.$ZodTypeInternals<import("@headless-lms/core/types").JsonValue, unknown>>>>;
33
- source: z.ZodEnum<{
34
- system: "system";
35
- user: "user";
36
- }>;
37
33
  createdAt: z.ZodCoercedDate<unknown>;
38
34
  updatedAt: z.ZodCoercedDate<unknown>;
39
35
  }, z.core.$strict>;
@@ -28,9 +28,9 @@ declare const MessageFlag: z.ZodObject<{
28
28
  reason: z.ZodString;
29
29
  resolvedAt: z.ZodNullable<z.ZodCoercedDate<unknown>>;
30
30
  resolution: z.ZodNullable<z.ZodEnum<{
31
+ locked: "locked";
31
32
  dismissed: "dismissed";
32
33
  deleted: "deleted";
33
- locked: "locked";
34
34
  }>>;
35
35
  resolvedBy: z.ZodNullable<z.ZodString>;
36
36
  createdAt: z.ZodCoercedDate<unknown>;
@@ -71,6 +71,10 @@ declare const MessageView: z.ZodObject<{
71
71
  }, z.core.$strict>>;
72
72
  reactions: z.ZodRecord<z.ZodString, z.ZodNumber>;
73
73
  viewerReaction: z.ZodNullable<z.ZodString>;
74
+ mentions: z.ZodArray<z.ZodObject<{
75
+ orgUserId: z.ZodString;
76
+ name: z.ZodString;
77
+ }, z.core.$strict>>;
74
78
  }, z.core.$strict>;
75
79
  declare const MessagesPage: z.ZodObject<{
76
80
  rows: z.ZodArray<z.ZodObject<{
@@ -108,6 +112,10 @@ declare const MessagesPage: z.ZodObject<{
108
112
  }, z.core.$strict>>;
109
113
  reactions: z.ZodRecord<z.ZodString, z.ZodNumber>;
110
114
  viewerReaction: z.ZodNullable<z.ZodString>;
115
+ mentions: z.ZodArray<z.ZodObject<{
116
+ orgUserId: z.ZodString;
117
+ name: z.ZodString;
118
+ }, z.core.$strict>>;
111
119
  }, z.core.$strict>>;
112
120
  total: z.ZodNumber;
113
121
  page: z.ZodNumber;
@@ -135,8 +143,13 @@ declare const ChatListItem: z.ZodObject<{
135
143
  }, z.core.$strict>;
136
144
  participantIds: z.ZodArray<z.ZodString>;
137
145
  lastReadMessageId: z.ZodNullable<z.ZodString>;
138
- muted: z.ZodBoolean;
139
- mutedUntil: z.ZodNullable<z.ZodCoercedDate<unknown>>;
146
+ subscription: z.ZodNullable<z.ZodObject<{
147
+ state: z.ZodEnum<{
148
+ following: "following";
149
+ muted: "muted";
150
+ }>;
151
+ mutedUntil: z.ZodNullable<z.ZodCoercedDate<unknown>>;
152
+ }, z.core.$strict>>;
140
153
  unread: z.ZodNumber;
141
154
  lastMessage: z.ZodNullable<z.ZodObject<{
142
155
  id: z.ZodString;
@@ -169,8 +182,13 @@ declare const ChatsPage: z.ZodObject<{
169
182
  }, z.core.$strict>;
170
183
  participantIds: z.ZodArray<z.ZodString>;
171
184
  lastReadMessageId: z.ZodNullable<z.ZodString>;
172
- muted: z.ZodBoolean;
173
- mutedUntil: z.ZodNullable<z.ZodCoercedDate<unknown>>;
185
+ subscription: z.ZodNullable<z.ZodObject<{
186
+ state: z.ZodEnum<{
187
+ following: "following";
188
+ muted: "muted";
189
+ }>;
190
+ mutedUntil: z.ZodNullable<z.ZodCoercedDate<unknown>>;
191
+ }, z.core.$strict>>;
174
192
  unread: z.ZodNumber;
175
193
  lastMessage: z.ZodNullable<z.ZodObject<{
176
194
  id: z.ZodString;
@@ -220,6 +238,10 @@ declare const MessageQueueEntry: z.ZodObject<{
220
238
  }, z.core.$strict>>;
221
239
  reactions: z.ZodRecord<z.ZodString, z.ZodNumber>;
222
240
  viewerReaction: z.ZodNullable<z.ZodString>;
241
+ mentions: z.ZodArray<z.ZodObject<{
242
+ orgUserId: z.ZodString;
243
+ name: z.ZodString;
244
+ }, z.core.$strict>>;
223
245
  }, z.core.$strict>;
224
246
  flags: z.ZodArray<z.ZodObject<{
225
247
  orgId: z.ZodString;
@@ -230,9 +252,9 @@ declare const MessageQueueEntry: z.ZodObject<{
230
252
  reason: z.ZodString;
231
253
  resolvedAt: z.ZodNullable<z.ZodCoercedDate<unknown>>;
232
254
  resolution: z.ZodNullable<z.ZodEnum<{
255
+ locked: "locked";
233
256
  dismissed: "dismissed";
234
257
  deleted: "deleted";
235
- locked: "locked";
236
258
  }>>;
237
259
  resolvedBy: z.ZodNullable<z.ZodString>;
238
260
  createdAt: z.ZodCoercedDate<unknown>;
@@ -296,6 +318,10 @@ declare const MessageQueue: z.ZodObject<{
296
318
  }, z.core.$strict>>;
297
319
  reactions: z.ZodRecord<z.ZodString, z.ZodNumber>;
298
320
  viewerReaction: z.ZodNullable<z.ZodString>;
321
+ mentions: z.ZodArray<z.ZodObject<{
322
+ orgUserId: z.ZodString;
323
+ name: z.ZodString;
324
+ }, z.core.$strict>>;
299
325
  }, z.core.$strict>;
300
326
  flags: z.ZodArray<z.ZodObject<{
301
327
  orgId: z.ZodString;
@@ -306,9 +332,9 @@ declare const MessageQueue: z.ZodObject<{
306
332
  reason: z.ZodString;
307
333
  resolvedAt: z.ZodNullable<z.ZodCoercedDate<unknown>>;
308
334
  resolution: z.ZodNullable<z.ZodEnum<{
335
+ locked: "locked";
309
336
  dismissed: "dismissed";
310
337
  deleted: "deleted";
311
- locked: "locked";
312
338
  }>>;
313
339
  resolvedBy: z.ZodNullable<z.ZodString>;
314
340
  createdAt: z.ZodCoercedDate<unknown>;
@@ -357,9 +383,6 @@ declare const EditMessage: z.ZodObject<{
357
383
  declare const MarkRead: z.ZodObject<{
358
384
  messageId: z.ZodString;
359
385
  }, z.core.$strict>;
360
- declare const MuteChat: z.ZodObject<{
361
- until: z.ZodOptional<z.ZodPipe<z.ZodISODateTime, z.ZodCoercedDate<string>>>;
362
- }, z.core.$strict>;
363
386
  declare const OrgUserBody: z.ZodObject<{
364
387
  orgUserId: z.ZodString;
365
388
  }, z.core.$strict>;
@@ -382,5 +405,5 @@ declare const BlockParam: z.ZodObject<{
382
405
  orgUserId: z.ZodString;
383
406
  }, z.core.$strip>;
384
407
  //#endregion
385
- export { BlockParam, Chat, ChatIdParam, ChatListItem, ChatsPage, CommunityParam, EditMessage, MarkRead, MessageFlag, MessageIdParam, MessageQueue, MessageQueueEntry, MessageView, MessagesPage, MuteChat, OrgUserBody, ResolveMessageFlags, SendMessage, StartDirectChat, StartGroupChat };
408
+ export { BlockParam, Chat, ChatIdParam, ChatListItem, ChatsPage, CommunityParam, EditMessage, MarkRead, MessageFlag, MessageIdParam, MessageQueue, MessageQueueEntry, MessageView, MessagesPage, OrgUserBody, ResolveMessageFlags, SendMessage, StartDirectChat, StartGroupChat };
386
409
  //# sourceMappingURL=chats.d.ts.map
@@ -1,6 +1,6 @@
1
- import { DateTimeInput, paginated } from "./shared.js";
1
+ import { paginated } from "./shared.js";
2
2
  import { z } from "zod";
3
- import { chatLastMessageSchema, chatSchema, idSchema, messageFlagResolutionSchema, messageFlagSchema, messageViewSchema } from "@headless-lms/core/schemas";
3
+ import { chatLastMessageSchema, chatSchema, idSchema, messageFlagResolutionSchema, messageFlagSchema, messageViewSchema, subscriptionViewSchema } from "@headless-lms/core/schemas";
4
4
  //#region src/http/schemas/chats.ts
5
5
  const Chat = chatSchema;
6
6
  const MessageFlag = messageFlagSchema;
@@ -10,8 +10,7 @@ const ChatListItem = z.object({
10
10
  chat: Chat,
11
11
  participantIds: z.array(z.string()),
12
12
  lastReadMessageId: z.string().nullable(),
13
- muted: z.boolean(),
14
- mutedUntil: z.coerce.date().nullable(),
13
+ subscription: subscriptionViewSchema.nullable().describe("Your mute on this chat while it applies; null when none"),
15
14
  unread: z.number().int(),
16
15
  lastMessage: chatLastMessageSchema.nullable()
17
16
  });
@@ -42,7 +41,6 @@ const SendMessage = z.object({
42
41
  }).strict();
43
42
  const EditMessage = z.object({ body: MessageBody }).strict();
44
43
  const MarkRead = z.object({ messageId: idSchema.describe("The newest message you have read in this chat") }).strict();
45
- const MuteChat = z.object({ until: DateTimeInput.optional().describe("When the mute ends. Omit to mute until you unmute") }).strict();
46
44
  const OrgUserBody = z.object({ orgUserId: idSchema }).strict();
47
45
  const ResolveMessageFlags = z.object({ resolution: messageFlagResolutionSchema.extract(["dismissed"]).describe("`dismissed` closes the open flags and leaves the message up. Deleting the message or locking the chat resolves its flags as `deleted` or `locked` instead.") }).strict();
48
46
  const ChatIdParam = z.object({ chatId: z.string() });
@@ -53,6 +51,6 @@ const BlockParam = z.object({
53
51
  orgUserId: z.string()
54
52
  });
55
53
  //#endregion
56
- export { BlockParam, Chat, ChatIdParam, ChatListItem, ChatsPage, CommunityParam, EditMessage, MarkRead, MessageFlag, MessageIdParam, MessageQueue, MessageQueueEntry, MessageView, MessagesPage, MuteChat, OrgUserBody, ResolveMessageFlags, SendMessage, StartDirectChat, StartGroupChat };
54
+ export { BlockParam, Chat, ChatIdParam, ChatListItem, ChatsPage, CommunityParam, EditMessage, MarkRead, MessageFlag, MessageIdParam, MessageQueue, MessageQueueEntry, MessageView, MessagesPage, OrgUserBody, ResolveMessageFlags, SendMessage, StartDirectChat, StartGroupChat };
57
55
 
58
56
  //# sourceMappingURL=chats.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"chats.js","names":[],"sources":["../../../src/http/schemas/chats.ts"],"sourcesContent":["import { z } from 'zod';\nimport {\n chatLastMessageSchema,\n chatSchema,\n idSchema,\n messageFlagResolutionSchema,\n messageFlagSchema,\n messageViewSchema,\n} from '@headless-lms/core/schemas';\nimport { DateTimeInput, paginated } from './shared.js';\n\nexport const Chat = chatSchema;\nexport const MessageFlag = messageFlagSchema;\nexport const MessageView = messageViewSchema;\nexport const MessagesPage = paginated(MessageView);\n\nexport const ChatListItem = z.object({\n chat: Chat,\n participantIds: z.array(z.string()),\n lastReadMessageId: z.string().nullable(),\n muted: z.boolean(),\n mutedUntil: z.coerce.date().nullable(),\n unread: z.number().int(),\n lastMessage: chatLastMessageSchema.nullable(),\n});\nexport const ChatsPage = paginated(ChatListItem);\n\nexport const MessageQueueEntry = z.object({\n message: MessageView,\n flags: z.array(MessageFlag),\n chat: Chat,\n participantIds: z.array(z.string()),\n});\n\nexport const MessageQueue = z.object({\n entries: z.array(MessageQueueEntry),\n});\n\nconst MessageBody = z.string().trim().min(1).max(10_000);\nconst Attachments = z\n .array(idSchema)\n .max(10)\n .default([])\n .describe('Up to 10 finalized images you uploaded through `requestMemberUpload`');\n\nexport const StartDirectChat = z\n .object({\n communityId: idSchema,\n orgUserId: idSchema.describe('The person to talk to'),\n body: MessageBody.nullable().describe(\n 'The first message. Null opens the chat without one; a new chat that starts as a message request needs one, and attachments need one.',\n ),\n assetIds: Attachments,\n })\n .strict();\n\nexport const StartGroupChat = z\n .object({\n communityId: idSchema,\n orgUserIds: z\n .array(idSchema)\n .min(2)\n .max(99)\n .describe(\n \"The people to add besides you. The chat may not exceed the community's group size.\",\n ),\n })\n .strict();\n\nexport const SendMessage = z\n .object({\n body: MessageBody,\n replyToId: idSchema\n .nullable()\n .default(null)\n .describe('A message in the same chat this one answers'),\n assetIds: Attachments,\n })\n .strict();\n\nexport const EditMessage = z.object({ body: MessageBody }).strict();\nexport const MarkRead = z\n .object({ messageId: idSchema.describe('The newest message you have read in this chat') })\n .strict();\nexport const MuteChat = z\n .object({\n until: DateTimeInput.optional().describe('When the mute ends. Omit to mute until you unmute'),\n })\n .strict();\nexport const OrgUserBody = z.object({ orgUserId: idSchema }).strict();\nexport const ResolveMessageFlags = z\n .object({\n resolution: messageFlagResolutionSchema\n .extract(['dismissed'])\n .describe(\n '`dismissed` closes the open flags and leaves the message up. Deleting the message or locking the chat resolves its flags as `deleted` or `locked` instead.',\n ),\n })\n .strict();\n\nexport const ChatIdParam = z.object({ chatId: z.string() });\nexport const MessageIdParam = z.object({ messageId: z.string() });\nexport const CommunityParam = z.object({ communityId: z.string() });\nexport const BlockParam = z.object({ communityId: z.string(), orgUserId: z.string() });\n"],"mappings":";;;;AAWA,MAAa,OAAO;AACpB,MAAa,cAAc;AAC3B,MAAa,cAAc;AAC3B,MAAa,eAAe,UAAU,WAAW;AAEjD,MAAa,eAAe,EAAE,OAAO;CACnC,MAAM;CACN,gBAAgB,EAAE,MAAM,EAAE,OAAO,CAAC;CAClC,mBAAmB,EAAE,OAAO,CAAC,CAAC,SAAS;CACvC,OAAO,EAAE,QAAQ;CACjB,YAAY,EAAE,OAAO,KAAK,CAAC,CAAC,SAAS;CACrC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI;CACvB,aAAa,sBAAsB,SAAS;AAC9C,CAAC;AACD,MAAa,YAAY,UAAU,YAAY;AAE/C,MAAa,oBAAoB,EAAE,OAAO;CACxC,SAAS;CACT,OAAO,EAAE,MAAM,WAAW;CAC1B,MAAM;CACN,gBAAgB,EAAE,MAAM,EAAE,OAAO,CAAC;AACpC,CAAC;AAED,MAAa,eAAe,EAAE,OAAO,EACnC,SAAS,EAAE,MAAM,iBAAiB,EACpC,CAAC;AAED,MAAM,cAAc,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAM;AACvD,MAAM,cAAc,EACjB,MAAM,QAAQ,CAAC,CACf,IAAI,EAAE,CAAC,CACP,QAAQ,CAAC,CAAC,CAAC,CACX,SAAS,sEAAsE;AAElF,MAAa,kBAAkB,EAC5B,OAAO;CACN,aAAa;CACb,WAAW,SAAS,SAAS,uBAAuB;CACpD,MAAM,YAAY,SAAS,CAAC,CAAC,SAC3B,sIACF;CACA,UAAU;AACZ,CAAC,CAAC,CACD,OAAO;AAEV,MAAa,iBAAiB,EAC3B,OAAO;CACN,aAAa;CACb,YAAY,EACT,MAAM,QAAQ,CAAC,CACf,IAAI,CAAC,CAAC,CACN,IAAI,EAAE,CAAC,CACP,SACC,oFACF;AACJ,CAAC,CAAC,CACD,OAAO;AAEV,MAAa,cAAc,EACxB,OAAO;CACN,MAAM;CACN,WAAW,SACR,SAAS,CAAC,CACV,QAAQ,IAAI,CAAC,CACb,SAAS,6CAA6C;CACzD,UAAU;AACZ,CAAC,CAAC,CACD,OAAO;AAEV,MAAa,cAAc,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC,CAAC,CAAC,OAAO;AAClE,MAAa,WAAW,EACrB,OAAO,EAAE,WAAW,SAAS,SAAS,+CAA+C,EAAE,CAAC,CAAC,CACzF,OAAO;AACV,MAAa,WAAW,EACrB,OAAO,EACN,OAAO,cAAc,SAAS,CAAC,CAAC,SAAS,mDAAmD,EAC9F,CAAC,CAAC,CACD,OAAO;AACV,MAAa,cAAc,EAAE,OAAO,EAAE,WAAW,SAAS,CAAC,CAAC,CAAC,OAAO;AACpE,MAAa,sBAAsB,EAChC,OAAO,EACN,YAAY,4BACT,QAAQ,CAAC,WAAW,CAAC,CAAC,CACtB,SACC,4JACF,EACJ,CAAC,CAAC,CACD,OAAO;AAEV,MAAa,cAAc,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AAC1D,MAAa,iBAAiB,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;AAChE,MAAa,iBAAiB,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC;AAClE,MAAa,aAAa,EAAE,OAAO;CAAE,aAAa,EAAE,OAAO;CAAG,WAAW,EAAE,OAAO;AAAE,CAAC"}
1
+ {"version":3,"file":"chats.js","names":[],"sources":["../../../src/http/schemas/chats.ts"],"sourcesContent":["import { z } from 'zod';\nimport {\n chatLastMessageSchema,\n chatSchema,\n idSchema,\n messageFlagResolutionSchema,\n messageFlagSchema,\n messageViewSchema,\n subscriptionViewSchema,\n} from '@headless-lms/core/schemas';\nimport { paginated } from './shared.js';\n\nexport const Chat = chatSchema;\nexport const MessageFlag = messageFlagSchema;\nexport const MessageView = messageViewSchema;\nexport const MessagesPage = paginated(MessageView);\n\nexport const ChatListItem = z.object({\n chat: Chat,\n participantIds: z.array(z.string()),\n lastReadMessageId: z.string().nullable(),\n subscription: subscriptionViewSchema\n .nullable()\n .describe('Your mute on this chat while it applies; null when none'),\n unread: z.number().int(),\n lastMessage: chatLastMessageSchema.nullable(),\n});\nexport const ChatsPage = paginated(ChatListItem);\n\nexport const MessageQueueEntry = z.object({\n message: MessageView,\n flags: z.array(MessageFlag),\n chat: Chat,\n participantIds: z.array(z.string()),\n});\n\nexport const MessageQueue = z.object({\n entries: z.array(MessageQueueEntry),\n});\n\nconst MessageBody = z.string().trim().min(1).max(10_000);\nconst Attachments = z\n .array(idSchema)\n .max(10)\n .default([])\n .describe('Up to 10 finalized images you uploaded through `requestMemberUpload`');\n\nexport const StartDirectChat = z\n .object({\n communityId: idSchema,\n orgUserId: idSchema.describe('The person to talk to'),\n body: MessageBody.nullable().describe(\n 'The first message. Null opens the chat without one; a new chat that starts as a message request needs one, and attachments need one.',\n ),\n assetIds: Attachments,\n })\n .strict();\n\nexport const StartGroupChat = z\n .object({\n communityId: idSchema,\n orgUserIds: z\n .array(idSchema)\n .min(2)\n .max(99)\n .describe(\n \"The people to add besides you. The chat may not exceed the community's group size.\",\n ),\n })\n .strict();\n\nexport const SendMessage = z\n .object({\n body: MessageBody,\n replyToId: idSchema\n .nullable()\n .default(null)\n .describe('A message in the same chat this one answers'),\n assetIds: Attachments,\n })\n .strict();\n\nexport const EditMessage = z.object({ body: MessageBody }).strict();\nexport const MarkRead = z\n .object({ messageId: idSchema.describe('The newest message you have read in this chat') })\n .strict();\nexport const OrgUserBody = z.object({ orgUserId: idSchema }).strict();\nexport const ResolveMessageFlags = z\n .object({\n resolution: messageFlagResolutionSchema\n .extract(['dismissed'])\n .describe(\n '`dismissed` closes the open flags and leaves the message up. Deleting the message or locking the chat resolves its flags as `deleted` or `locked` instead.',\n ),\n })\n .strict();\n\nexport const ChatIdParam = z.object({ chatId: z.string() });\nexport const MessageIdParam = z.object({ messageId: z.string() });\nexport const CommunityParam = z.object({ communityId: z.string() });\nexport const BlockParam = z.object({ communityId: z.string(), orgUserId: z.string() });\n"],"mappings":";;;;AAYA,MAAa,OAAO;AACpB,MAAa,cAAc;AAC3B,MAAa,cAAc;AAC3B,MAAa,eAAe,UAAU,WAAW;AAEjD,MAAa,eAAe,EAAE,OAAO;CACnC,MAAM;CACN,gBAAgB,EAAE,MAAM,EAAE,OAAO,CAAC;CAClC,mBAAmB,EAAE,OAAO,CAAC,CAAC,SAAS;CACvC,cAAc,uBACX,SAAS,CAAC,CACV,SAAS,yDAAyD;CACrE,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI;CACvB,aAAa,sBAAsB,SAAS;AAC9C,CAAC;AACD,MAAa,YAAY,UAAU,YAAY;AAE/C,MAAa,oBAAoB,EAAE,OAAO;CACxC,SAAS;CACT,OAAO,EAAE,MAAM,WAAW;CAC1B,MAAM;CACN,gBAAgB,EAAE,MAAM,EAAE,OAAO,CAAC;AACpC,CAAC;AAED,MAAa,eAAe,EAAE,OAAO,EACnC,SAAS,EAAE,MAAM,iBAAiB,EACpC,CAAC;AAED,MAAM,cAAc,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAM;AACvD,MAAM,cAAc,EACjB,MAAM,QAAQ,CAAC,CACf,IAAI,EAAE,CAAC,CACP,QAAQ,CAAC,CAAC,CAAC,CACX,SAAS,sEAAsE;AAElF,MAAa,kBAAkB,EAC5B,OAAO;CACN,aAAa;CACb,WAAW,SAAS,SAAS,uBAAuB;CACpD,MAAM,YAAY,SAAS,CAAC,CAAC,SAC3B,sIACF;CACA,UAAU;AACZ,CAAC,CAAC,CACD,OAAO;AAEV,MAAa,iBAAiB,EAC3B,OAAO;CACN,aAAa;CACb,YAAY,EACT,MAAM,QAAQ,CAAC,CACf,IAAI,CAAC,CAAC,CACN,IAAI,EAAE,CAAC,CACP,SACC,oFACF;AACJ,CAAC,CAAC,CACD,OAAO;AAEV,MAAa,cAAc,EACxB,OAAO;CACN,MAAM;CACN,WAAW,SACR,SAAS,CAAC,CACV,QAAQ,IAAI,CAAC,CACb,SAAS,6CAA6C;CACzD,UAAU;AACZ,CAAC,CAAC,CACD,OAAO;AAEV,MAAa,cAAc,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC,CAAC,CAAC,OAAO;AAClE,MAAa,WAAW,EACrB,OAAO,EAAE,WAAW,SAAS,SAAS,+CAA+C,EAAE,CAAC,CAAC,CACzF,OAAO;AACV,MAAa,cAAc,EAAE,OAAO,EAAE,WAAW,SAAS,CAAC,CAAC,CAAC,OAAO;AACpE,MAAa,sBAAsB,EAChC,OAAO,EACN,YAAY,4BACT,QAAQ,CAAC,WAAW,CAAC,CAAC,CACtB,SACC,4JACF,EACJ,CAAC,CAAC,CACD,OAAO;AAEV,MAAa,cAAc,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AAC1D,MAAa,iBAAiB,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;AAChE,MAAa,iBAAiB,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC;AAClE,MAAa,aAAa,EAAE,OAAO;CAAE,aAAa,EAAE,OAAO;CAAG,WAAW,EAAE,OAAO;AAAE,CAAC"}
@@ -22,6 +22,15 @@ declare const Community: z.ZodObject<{
22
22
  groupChats: z.ZodBoolean;
23
23
  groupSize: z.ZodNumber;
24
24
  }, z.core.$strict>;
25
+ digest: z.ZodNullable<z.ZodObject<{
26
+ cadence: z.ZodEnum<{
27
+ daily: "daily";
28
+ weekly: "weekly";
29
+ }>;
30
+ weekday: z.ZodNumber;
31
+ hour: z.ZodNumber;
32
+ timeZone: z.ZodString;
33
+ }, z.core.$strict>>;
25
34
  }, z.core.$strict>;
26
35
  createdAt: z.ZodCoercedDate<unknown>;
27
36
  updatedAt: z.ZodCoercedDate<unknown>;
@@ -60,6 +69,15 @@ declare const CommunitiesPage: z.ZodObject<{
60
69
  groupChats: z.ZodBoolean;
61
70
  groupSize: z.ZodNumber;
62
71
  }, z.core.$strict>;
72
+ digest: z.ZodNullable<z.ZodObject<{
73
+ cadence: z.ZodEnum<{
74
+ daily: "daily";
75
+ weekly: "weekly";
76
+ }>;
77
+ weekday: z.ZodNumber;
78
+ hour: z.ZodNumber;
79
+ timeZone: z.ZodString;
80
+ }, z.core.$strict>>;
63
81
  }, z.core.$strict>;
64
82
  createdAt: z.ZodCoercedDate<unknown>;
65
83
  updatedAt: z.ZodCoercedDate<unknown>;
@@ -91,6 +109,24 @@ declare const PatchDmSettings: z.ZodObject<{
91
109
  groupChats: z.ZodOptional<z.ZodBoolean>;
92
110
  groupSize: z.ZodOptional<z.ZodNumber>;
93
111
  }, z.core.$strict>;
112
+ declare const PatchCommunitySettings: z.ZodObject<{
113
+ enabled: z.ZodOptional<z.ZodBoolean>;
114
+ memberToMember: z.ZodOptional<z.ZodBoolean>;
115
+ memberToStaff: z.ZodOptional<z.ZodBoolean>;
116
+ staffToAnyone: z.ZodOptional<z.ZodBoolean>;
117
+ firstMessageIsRequest: z.ZodOptional<z.ZodBoolean>;
118
+ groupChats: z.ZodOptional<z.ZodBoolean>;
119
+ groupSize: z.ZodOptional<z.ZodNumber>;
120
+ digest: z.ZodOptional<z.ZodNullable<z.ZodObject<{
121
+ cadence: z.ZodEnum<{
122
+ daily: "daily";
123
+ weekly: "weekly";
124
+ }>;
125
+ weekday: z.ZodNumber;
126
+ hour: z.ZodNumber;
127
+ timeZone: z.ZodString;
128
+ }, z.core.$strict>>>;
129
+ }, z.core.$strict>;
94
130
  declare const DmSettings: z.ZodObject<{
95
131
  enabled: z.ZodBoolean;
96
132
  memberToMember: z.ZodBoolean;
@@ -146,9 +182,9 @@ declare const SpaceMember: z.ZodObject<{
146
182
  spaceId: z.ZodString;
147
183
  orgUserId: z.ZodString;
148
184
  status: z.ZodEnum<{
149
- requested: "requested";
150
- invited: "invited";
151
185
  active: "active";
186
+ invited: "invited";
187
+ requested: "requested";
152
188
  revoked: "revoked";
153
189
  }>;
154
190
  source: z.ZodEnum<{
@@ -167,9 +203,9 @@ declare const SpaceMembersPage: z.ZodObject<{
167
203
  spaceId: z.ZodString;
168
204
  orgUserId: z.ZodString;
169
205
  status: z.ZodEnum<{
170
- requested: "requested";
171
- invited: "invited";
172
206
  active: "active";
207
+ invited: "invited";
208
+ requested: "requested";
173
209
  revoked: "revoked";
174
210
  }>;
175
211
  source: z.ZodEnum<{
@@ -233,6 +269,9 @@ declare const CommunitySpaceParam: z.ZodObject<{
233
269
  communityId: z.ZodString;
234
270
  spaceId: z.ZodString;
235
271
  }, z.core.$strip>;
272
+ declare const SpaceIdParam: z.ZodObject<{
273
+ spaceId: z.ZodString;
274
+ }, z.core.$strip>;
236
275
  declare const SpaceLinkParam: z.ZodObject<{
237
276
  communityId: z.ZodString;
238
277
  spaceId: z.ZodString;
@@ -335,10 +374,10 @@ declare const LockedCommunitySpace: z.ZodObject<{
335
374
  by_invite: "by_invite";
336
375
  }>;
337
376
  standing: z.ZodEnum<{
338
- open: "open";
377
+ invited: "invited";
339
378
  member: "member";
379
+ open: "open";
340
380
  requested: "requested";
341
- invited: "invited";
342
381
  full: "full";
343
382
  none: "none";
344
383
  }>;
@@ -354,10 +393,10 @@ declare const OpenCommunitySpace: z.ZodObject<{
354
393
  by_invite: "by_invite";
355
394
  }>;
356
395
  standing: z.ZodEnum<{
357
- open: "open";
396
+ invited: "invited";
358
397
  member: "member";
398
+ open: "open";
359
399
  requested: "requested";
360
- invited: "invited";
361
400
  full: "full";
362
401
  none: "none";
363
402
  }>;
@@ -383,6 +422,13 @@ declare const OpenCommunitySpace: z.ZodObject<{
383
422
  }>;
384
423
  title: z.ZodString;
385
424
  }, z.core.$strip>>;
425
+ subscription: z.ZodNullable<z.ZodObject<{
426
+ state: z.ZodEnum<{
427
+ following: "following";
428
+ muted: "muted";
429
+ }>;
430
+ mutedUntil: z.ZodNullable<z.ZodCoercedDate<unknown>>;
431
+ }, z.core.$strict>>;
386
432
  }, z.core.$strip>;
387
433
  declare const CommunityHomeSpace: z.ZodDiscriminatedUnion<[z.ZodObject<{
388
434
  id: z.ZodString;
@@ -394,10 +440,10 @@ declare const CommunityHomeSpace: z.ZodDiscriminatedUnion<[z.ZodObject<{
394
440
  by_invite: "by_invite";
395
441
  }>;
396
442
  standing: z.ZodEnum<{
397
- open: "open";
443
+ invited: "invited";
398
444
  member: "member";
445
+ open: "open";
399
446
  requested: "requested";
400
- invited: "invited";
401
447
  full: "full";
402
448
  none: "none";
403
449
  }>;
@@ -412,10 +458,10 @@ declare const CommunityHomeSpace: z.ZodDiscriminatedUnion<[z.ZodObject<{
412
458
  by_invite: "by_invite";
413
459
  }>;
414
460
  standing: z.ZodEnum<{
415
- open: "open";
461
+ invited: "invited";
416
462
  member: "member";
463
+ open: "open";
417
464
  requested: "requested";
418
- invited: "invited";
419
465
  full: "full";
420
466
  none: "none";
421
467
  }>;
@@ -441,6 +487,13 @@ declare const CommunityHomeSpace: z.ZodDiscriminatedUnion<[z.ZodObject<{
441
487
  }>;
442
488
  title: z.ZodString;
443
489
  }, z.core.$strip>>;
490
+ subscription: z.ZodNullable<z.ZodObject<{
491
+ state: z.ZodEnum<{
492
+ following: "following";
493
+ muted: "muted";
494
+ }>;
495
+ mutedUntil: z.ZodNullable<z.ZodCoercedDate<unknown>>;
496
+ }, z.core.$strict>>;
444
497
  }, z.core.$strip>], "locked">;
445
498
  declare const CommunityHome: z.ZodObject<{
446
499
  communityId: z.ZodString;
@@ -466,10 +519,10 @@ declare const CommunityHome: z.ZodObject<{
466
519
  by_invite: "by_invite";
467
520
  }>;
468
521
  standing: z.ZodEnum<{
469
- open: "open";
522
+ invited: "invited";
470
523
  member: "member";
524
+ open: "open";
471
525
  requested: "requested";
472
- invited: "invited";
473
526
  full: "full";
474
527
  none: "none";
475
528
  }>;
@@ -484,10 +537,10 @@ declare const CommunityHome: z.ZodObject<{
484
537
  by_invite: "by_invite";
485
538
  }>;
486
539
  standing: z.ZodEnum<{
487
- open: "open";
540
+ invited: "invited";
488
541
  member: "member";
542
+ open: "open";
489
543
  requested: "requested";
490
- invited: "invited";
491
544
  full: "full";
492
545
  none: "none";
493
546
  }>;
@@ -513,6 +566,13 @@ declare const CommunityHome: z.ZodObject<{
513
566
  }>;
514
567
  title: z.ZodString;
515
568
  }, z.core.$strip>>;
569
+ subscription: z.ZodNullable<z.ZodObject<{
570
+ state: z.ZodEnum<{
571
+ following: "following";
572
+ muted: "muted";
573
+ }>;
574
+ mutedUntil: z.ZodNullable<z.ZodCoercedDate<unknown>>;
575
+ }, z.core.$strict>>;
516
576
  }, z.core.$strip>], "locked">>;
517
577
  }, z.core.$strip>;
518
578
  declare const CommunityAnalytics: z.ZodObject<{
@@ -533,5 +593,5 @@ declare const CommunityAnalytics: z.ZodObject<{
533
593
  grantsRenewed: z.ZodNumber;
534
594
  }, z.core.$strip>;
535
595
  //#endregion
536
- export { CommunitiesPage, CommunitiesQuery, Community, CommunityAnalytics, CommunityChatParam, CommunityCommentParam, CommunityHome, CommunityHomeSpace, CommunityIdParam, CommunityMember, CommunityMembersPage, CommunityMembersQuery, CommunityMessageParam, CommunityPostParam, CommunitySpaceParam, CreateCommunity, CreateSpace, DirectoryEntry, DirectoryPage, DirectoryQuery, DmSettings, LockedCommunitySpace, OpenCommunitySpace, OrderedIds, PatchDmSettings, SetSpaceTopics, SpaceDetail, SpaceLinkBody, SpaceLinkParam, SpaceMember, SpaceMemberParam, SpaceMembersPage, UpdateCommunity, UpdateSpace };
596
+ export { CommunitiesPage, CommunitiesQuery, Community, CommunityAnalytics, CommunityChatParam, CommunityCommentParam, CommunityHome, CommunityHomeSpace, CommunityIdParam, CommunityMember, CommunityMembersPage, CommunityMembersQuery, CommunityMessageParam, CommunityPostParam, CommunitySpaceParam, CreateCommunity, CreateSpace, DirectoryEntry, DirectoryPage, DirectoryQuery, DmSettings, LockedCommunitySpace, OpenCommunitySpace, OrderedIds, PatchCommunitySettings, PatchDmSettings, SetSpaceTopics, SpaceDetail, SpaceIdParam, SpaceLinkBody, SpaceLinkParam, SpaceMember, SpaceMemberParam, SpaceMembersPage, UpdateCommunity, UpdateSpace };
537
597
  //# sourceMappingURL=community.d.ts.map
@@ -1,6 +1,6 @@
1
1
  import { ListQuery, OrgUserProfileSchema, PageQuery, paginated } from "./shared.js";
2
2
  import { z } from "zod";
3
- import { communityStatusSchema, communityViewSchema, createCommunityInputSchema, createSpaceInputSchema, dmSettingsSchema, idSchema, patchDmSettingsInputSchema, roleSchema, setSpaceTopicsInputSchema, spaceDetailSchema, spaceMemberSchema, updateCommunityInputSchema, updateSpaceInputSchema } from "@headless-lms/core/schemas";
3
+ import { communityStatusSchema, communityViewSchema, createCommunityInputSchema, createSpaceInputSchema, dmSettingsSchema, idSchema, patchCommunitySettingsInputSchema, patchDmSettingsInputSchema, roleSchema, setSpaceTopicsInputSchema, spaceDetailSchema, spaceMemberSchema, subscriptionViewSchema, updateCommunityInputSchema, updateSpaceInputSchema } from "@headless-lms/core/schemas";
4
4
  //#region src/http/schemas/community.ts
5
5
  const Community = communityViewSchema;
6
6
  const CommunitiesQuery = ListQuery.extend({ status: communityStatusSchema.optional() });
@@ -8,6 +8,7 @@ const CommunitiesPage = paginated(Community);
8
8
  const CreateCommunity = createCommunityInputSchema;
9
9
  const UpdateCommunity = updateCommunityInputSchema;
10
10
  const PatchDmSettings = patchDmSettingsInputSchema;
11
+ const PatchCommunitySettings = patchCommunitySettingsInputSchema;
11
12
  const DmSettings = dmSettingsSchema;
12
13
  const SpaceDetail = spaceDetailSchema;
13
14
  const SpaceMember = spaceMemberSchema;
@@ -22,6 +23,7 @@ const CommunitySpaceParam = z.object({
22
23
  communityId: z.string(),
23
24
  spaceId: z.string()
24
25
  });
26
+ const SpaceIdParam = z.object({ spaceId: z.string() });
25
27
  const SpaceLinkParam = CommunitySpaceParam.extend({ linkId: z.string() });
26
28
  const SpaceMemberParam = CommunitySpaceParam.extend({ orgUserId: z.string() });
27
29
  const CommunityPostParam = z.object({
@@ -95,7 +97,8 @@ const OpenCommunitySpace = CommunityHomeSpaceBase.extend({
95
97
  "community"
96
98
  ]),
97
99
  title: z.string()
98
- })).describe("Linked content that is published; staff also see unpublished targets")
100
+ })).describe("Linked content that is published; staff also see unpublished targets"),
101
+ subscription: subscriptionViewSchema.nullable().describe("Your mute on this space while it applies; null when none")
99
102
  });
100
103
  const CommunityHomeSpace = z.discriminatedUnion("locked", [LockedCommunitySpace, OpenCommunitySpace]).describe("A space as the viewer sees it. A by-invite space the viewer is not invited to or a member of is never served");
101
104
  const CommunityHome = z.object({
@@ -124,6 +127,6 @@ const CommunityAnalytics = z.object({
124
127
  grantsRenewed: z.number().int()
125
128
  });
126
129
  //#endregion
127
- export { CommunitiesPage, CommunitiesQuery, Community, CommunityAnalytics, CommunityChatParam, CommunityCommentParam, CommunityHome, CommunityHomeSpace, CommunityIdParam, CommunityMember, CommunityMembersPage, CommunityMembersQuery, CommunityMessageParam, CommunityPostParam, CommunitySpaceParam, CreateCommunity, CreateSpace, DirectoryEntry, DirectoryPage, DirectoryQuery, DmSettings, LockedCommunitySpace, OpenCommunitySpace, OrderedIds, PatchDmSettings, SetSpaceTopics, SpaceDetail, SpaceLinkBody, SpaceLinkParam, SpaceMember, SpaceMemberParam, SpaceMembersPage, UpdateCommunity, UpdateSpace };
130
+ export { CommunitiesPage, CommunitiesQuery, Community, CommunityAnalytics, CommunityChatParam, CommunityCommentParam, CommunityHome, CommunityHomeSpace, CommunityIdParam, CommunityMember, CommunityMembersPage, CommunityMembersQuery, CommunityMessageParam, CommunityPostParam, CommunitySpaceParam, CreateCommunity, CreateSpace, DirectoryEntry, DirectoryPage, DirectoryQuery, DmSettings, LockedCommunitySpace, OpenCommunitySpace, OrderedIds, PatchCommunitySettings, PatchDmSettings, SetSpaceTopics, SpaceDetail, SpaceIdParam, SpaceLinkBody, SpaceLinkParam, SpaceMember, SpaceMemberParam, SpaceMembersPage, UpdateCommunity, UpdateSpace };
128
131
 
129
132
  //# sourceMappingURL=community.js.map