@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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activities.js","names":[],"sources":["../../../src/http/routes/activities.ts"],"sourcesContent":["// HTTP routes for course modules + activities. Write operations return the\n// course's full, reordered module list (how the editor re-renders). Nested under\n// courses. All require a session with an active organization; handlers resolve\n// the session's active org to the domain org id and scope every call by it.\nimport type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport {\n ActivityAssetList,\n ActivityList,\n ActivityPathParam,\n CourseIdPathParam,\n CreateModule,\n ModuleList,\n ModulePathParam,\n ReorderInput,\n SaveActivity,\n UpdateModule,\n refusals,\n} from '../schemas/index.js';\nimport type { Container } from '../../app/container.js';\nimport { resolveScope } from '../scope.js';\n\nexport async function activitiesRoutes(app: FastifyInstance, container: Container): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n // Modules/activities are part of the content aggregate; grouped under the Courses tag.\n const content = container.content;\n const tags = ['Content'];\n\n r.route({\n method: 'GET',\n url: '/api/courses/:courseId/modules',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listModules',\n tags,\n summary: \"List a course's modules (staff)\",\n description:\n 'Staff only (owner, admin, instructor). Modules in order, each with its activities.',\n params: CourseIdPathParam,\n response: { 200: ModuleList, ...refusals(403) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.listCourseModules(scope.orgId, req.params.courseId);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/courses/:courseId/activities',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listActivities',\n tags,\n summary: \"List a course's activities (staff)\",\n description: 'Staff only (owner, admin, instructor). Every activity, published or not.',\n params: CourseIdPathParam,\n response: { 200: ActivityList, ...refusals(403) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.listCourseActivityViews(scope.orgId, req.params.courseId);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/courses/:courseId/activity-assets',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listActivityAssets',\n tags,\n summary: 'List the library files each activity of a course uses (staff)',\n description:\n 'Staff only (owner, admin, instructor). One row per activity and file, as recorded when the activity was saved.',\n params: CourseIdPathParam,\n response: { 200: ActivityAssetList, ...refusals(403) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.listCourseActivityAssets(scope.orgId, req.params.courseId);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/courses/:courseId/modules',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'createModule',\n tags,\n summary: 'Add a module (staff)',\n description:\n \"Staff only (owner, admin, instructor). Added last. Returns the course's modules.\",\n params: CourseIdPathParam,\n body: CreateModule,\n response: { 200: ModuleList, ...refusals(403) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.createModule(scope.orgId, req.params.courseId, req.body.title);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/courses/:courseId/modules/reorder',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'reorderModules',\n tags,\n summary: \"Reorder a course's modules (staff)\",\n description:\n \"Staff only (owner, admin, instructor). Ids that are not modules of the course are ignored. Returns the course's modules.\",\n params: CourseIdPathParam,\n body: ReorderInput,\n response: { 200: ModuleList, ...refusals(403) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.reorderModules(scope.orgId, req.params.courseId, req.body.orderedIds);\n },\n });\n\n r.route({\n method: 'PATCH',\n url: '/api/courses/:courseId/modules/:moduleId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'updateModule',\n tags,\n summary: 'Rename a module (staff)',\n description: \"Staff only (owner, admin, instructor). Returns the course's modules.\",\n params: ModulePathParam,\n body: UpdateModule,\n response: { 200: ModuleList, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.updateModule(\n scope.orgId,\n req.params.courseId,\n req.params.moduleId,\n req.body.title,\n );\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/courses/:courseId/modules/:moduleId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'deleteModule',\n tags,\n summary: 'Delete a module (staff)',\n description: \"Staff only (owner, admin, instructor). Returns the course's modules.\",\n params: ModulePathParam,\n response: { 200: ModuleList, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.deleteModule(scope.orgId, req.params.courseId, req.params.moduleId);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/courses/:courseId/modules/:moduleId/activities/reorder',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'reorderActivities',\n tags,\n summary: 'Reorder the activities in a module (staff)',\n description:\n \"Staff only (owner, admin, instructor). Send every activity id of the module once (409 otherwise). Returns the course's modules.\",\n params: ModulePathParam,\n body: ReorderInput,\n response: { 200: ModuleList, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.reorderActivities(\n scope.orgId,\n req.params.courseId,\n req.params.moduleId,\n req.body.orderedIds,\n );\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/courses/:courseId/modules/:moduleId/activities',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'createActivity',\n tags,\n summary: 'Add an activity (staff)',\n description:\n \"Staff only (owner, admin, instructor). Records the library files the activity uses; each must be a ready library file (409 otherwise). Returns the course's modules.\",\n params: ModulePathParam,\n body: SaveActivity,\n response: { 200: ModuleList, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.saveActivity(scope.orgId, req.params.courseId, req.params.moduleId, req.body);\n },\n });\n\n r.route({\n method: 'PATCH',\n url: '/api/courses/:courseId/modules/:moduleId/activities/:activityId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'updateActivity',\n tags,\n summary: 'Update an activity (staff)',\n description:\n \"Staff only (owner, admin, instructor). Replaces its content and records the library files it uses; each must be a ready library file (409 otherwise). Returns the course's modules.\",\n params: ActivityPathParam,\n body: SaveActivity,\n response: { 200: ModuleList, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.saveActivity(\n scope.orgId,\n req.params.courseId,\n req.params.moduleId,\n req.body,\n req.params.activityId,\n );\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/courses/:courseId/modules/:moduleId/activities/:activityId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'deleteActivity',\n tags,\n summary: 'Delete an activity (staff)',\n description: \"Staff only (owner, admin, instructor). Returns the course's modules.\",\n params: ActivityPathParam,\n response: { 200: ModuleList, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.deleteActivity(\n scope.orgId,\n req.params.courseId,\n req.params.moduleId,\n req.params.activityId,\n );\n },\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"activities.js","names":[],"sources":["../../../src/http/routes/activities.ts"],"sourcesContent":["// HTTP routes for course modules + activities. Write operations return the\n// course's full, reordered module list (how the editor re-renders). Nested under\n// courses. All require a session with an active organization.\nimport type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport {\n ActivityAssetList,\n ActivityList,\n ActivityPathParam,\n CourseIdPathParam,\n CreateModule,\n ModuleList,\n ModulePathParam,\n ReorderInput,\n SaveActivity,\n UpdateModule,\n refusals,\n} from '../schemas/index.js';\nimport type { Container } from '../../app/container.js';\nimport { resolveActor } from '../scope.js';\n\nexport async function activitiesRoutes(app: FastifyInstance, container: Container): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n // Modules/activities are part of the content aggregate; grouped under the Courses tag.\n const content = container.content;\n const tags = ['Content'];\n\n r.route({\n method: 'GET',\n url: '/api/courses/:courseId/modules',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listModules',\n tags,\n summary: \"List a course's modules\",\n description: `Requires \\`courses:read\\`. Modules in order, each with its activities.`,\n params: CourseIdPathParam,\n response: { 200: ModuleList, ...refusals(403) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return content.listCourseModules(req.params.courseId, actor);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/courses/:courseId/activities',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listActivities',\n tags,\n summary: \"List a course's activities\",\n description: `Requires \\`courses:read\\`. Every activity, published or not.`,\n params: CourseIdPathParam,\n response: { 200: ActivityList, ...refusals(403) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return content.listCourseActivityViews(req.params.courseId, actor);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/courses/:courseId/activity-assets',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listActivityAssets',\n tags,\n summary: 'List the library files each activity of a course uses',\n description: `Requires \\`courses:read\\`. One row per activity and file, as recorded when the activity was saved.`,\n params: CourseIdPathParam,\n response: { 200: ActivityAssetList, ...refusals(403) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return content.listCourseActivityAssets(req.params.courseId, actor);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/courses/:courseId/modules',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'createModule',\n tags,\n summary: 'Add a module',\n description: `Requires \\`courses:write\\`. Added last. Returns the course's modules.`,\n params: CourseIdPathParam,\n body: CreateModule,\n response: { 200: ModuleList, ...refusals(403) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return content.createModule(req.params.courseId, req.body.title, actor);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/courses/:courseId/modules/reorder',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'reorderModules',\n tags,\n summary: \"Reorder a course's modules\",\n description: `Requires \\`courses:write\\`. Ids that are not modules of the course are ignored. Returns the course's modules.`,\n params: CourseIdPathParam,\n body: ReorderInput,\n response: { 200: ModuleList, ...refusals(403) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return content.reorderModules(req.params.courseId, req.body.orderedIds, actor);\n },\n });\n\n r.route({\n method: 'PATCH',\n url: '/api/courses/:courseId/modules/:moduleId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'updateModule',\n tags,\n summary: 'Rename a module',\n description: `Requires \\`courses:write\\`. Returns the course's modules.`,\n params: ModulePathParam,\n body: UpdateModule,\n response: { 200: ModuleList, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return content.updateModule(req.params.courseId, req.params.moduleId, req.body.title, actor);\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/courses/:courseId/modules/:moduleId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'deleteModule',\n tags,\n summary: 'Delete a module',\n description: `Requires \\`courses:write\\`. Returns the course's modules.`,\n params: ModulePathParam,\n response: { 200: ModuleList, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return content.deleteModule(req.params.courseId, req.params.moduleId, actor);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/courses/:courseId/modules/:moduleId/activities/reorder',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'reorderActivities',\n tags,\n summary: 'Reorder the activities in a module',\n description: `Requires \\`courses:write\\`. Send every activity id of the module once (409 otherwise). Returns the course's modules.`,\n params: ModulePathParam,\n body: ReorderInput,\n response: { 200: ModuleList, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return content.reorderActivities(\n req.params.courseId,\n req.params.moduleId,\n req.body.orderedIds,\n actor,\n );\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/courses/:courseId/modules/:moduleId/activities',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'createActivity',\n tags,\n summary: 'Add an activity',\n description: `Requires \\`courses:write\\`. Records the library files the activity uses; each must be a ready library file (409 otherwise). A file the course does not already use must be uploaded for the course, or the caller needs \\`media:read\\` (403 otherwise). Returns the course's modules.`,\n params: ModulePathParam,\n body: SaveActivity,\n response: { 200: ModuleList, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return content.saveActivity(req.params.courseId, req.params.moduleId, req.body, null, actor);\n },\n });\n\n r.route({\n method: 'PATCH',\n url: '/api/courses/:courseId/modules/:moduleId/activities/:activityId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'updateActivity',\n tags,\n summary: 'Update an activity',\n description: `Requires \\`courses:write\\`. Replaces its content and records the library files it uses; each must be a ready library file (409 otherwise). A file the course does not already use must be uploaded for the course, or the caller needs \\`media:read\\` (403 otherwise). Returns the course's modules.`,\n params: ActivityPathParam,\n body: SaveActivity,\n response: { 200: ModuleList, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return content.saveActivity(\n req.params.courseId,\n req.params.moduleId,\n req.body,\n req.params.activityId,\n actor,\n );\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/courses/:courseId/modules/:moduleId/activities/:activityId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'deleteActivity',\n tags,\n summary: 'Delete an activity',\n description: `Requires \\`courses:write\\`. Returns the course's modules.`,\n params: ActivityPathParam,\n response: { 200: ModuleList, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return content.deleteActivity(\n req.params.courseId,\n req.params.moduleId,\n req.params.activityId,\n actor,\n );\n },\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,129 +1,98 @@
|
|
|
1
1
|
import { refusals } from "../schemas/shared.js";
|
|
2
|
-
import {
|
|
2
|
+
import { resolveActor } from "../scope.js";
|
|
3
3
|
import { Asset, AssetIdParam, AssetsPage, AssetsQuery, RequestUpload, UploadTicket } from "../schemas/assets.js";
|
|
4
4
|
import "../schemas/index.js";
|
|
5
5
|
import { z } from "zod";
|
|
6
|
-
import { NotFoundError } from "@headless-lms/core/shared/errors";
|
|
7
6
|
//#region src/http/routes/assets.ts
|
|
8
|
-
/** Resolve the session's active org to the domain org id, or 400 and return null. */
|
|
9
|
-
async function resolveOrgId(req, reply) {
|
|
10
|
-
if (!req.orgId) {
|
|
11
|
-
await reply.code(400).send({
|
|
12
|
-
error: "no_active_org",
|
|
13
|
-
message: "No active organization"
|
|
14
|
-
});
|
|
15
|
-
return null;
|
|
16
|
-
}
|
|
17
|
-
return req.orgId;
|
|
18
|
-
}
|
|
19
7
|
async function assetsRoutes(app, container) {
|
|
20
8
|
const r = app.withTypeProvider();
|
|
21
9
|
const assets = container.assets;
|
|
22
10
|
const tags = ["Assets"];
|
|
23
|
-
const staff = async (req) => {
|
|
24
|
-
await resolveScope(container, req);
|
|
25
|
-
};
|
|
26
11
|
r.route({
|
|
27
12
|
method: "POST",
|
|
28
13
|
url: "/api/uploads",
|
|
29
|
-
preHandler: staff,
|
|
30
14
|
schema: {
|
|
31
15
|
operationId: "requestUpload",
|
|
32
16
|
tags,
|
|
33
|
-
summary: "Register a library asset and get a presigned upload URL
|
|
34
|
-
description:
|
|
17
|
+
summary: "Register a library asset and get a presigned upload URL",
|
|
18
|
+
description: `Requires one of \`media:write\`, \`courses:write\`, \`downloads:write\`, \`communities:write\`. \`media:write\` uploads to the library; the write permission of a content item uploads for that item when \`contentId\` names it, and the asset records it. The asset stays pending until you upload the file and confirm it. 404 when \`contentId\` is not a content item of the organization.`,
|
|
35
19
|
body: RequestUpload,
|
|
36
20
|
response: {
|
|
37
21
|
201: UploadTicket,
|
|
38
|
-
...refusals(403)
|
|
22
|
+
...refusals(403, 404)
|
|
39
23
|
}
|
|
40
24
|
},
|
|
41
25
|
handler: async (req, reply) => {
|
|
42
|
-
const
|
|
43
|
-
const ticket = await assets.requestUpload(
|
|
44
|
-
...req.body,
|
|
45
|
-
source: "library",
|
|
46
|
-
uploadedBy: scope.orgUserId
|
|
47
|
-
});
|
|
26
|
+
const actor = await resolveActor(container, req);
|
|
27
|
+
const ticket = await assets.requestUpload(req.body, actor);
|
|
48
28
|
return reply.code(201).send(ticket);
|
|
49
29
|
}
|
|
50
30
|
});
|
|
51
31
|
r.route({
|
|
52
32
|
method: "POST",
|
|
53
33
|
url: "/api/assets/:id/confirm",
|
|
54
|
-
preHandler: staff,
|
|
55
34
|
schema: {
|
|
56
35
|
operationId: "confirmAsset",
|
|
57
36
|
tags,
|
|
58
|
-
summary: "Confirm a library upload completed
|
|
59
|
-
description:
|
|
37
|
+
summary: "Confirm a library upload completed",
|
|
38
|
+
description: `Requires one of \`media:read\`, \`courses:write\`, \`downloads:write\`, \`communities:write\`. \`media:read\` reaches every file; the write permission of a content item reaches the files uploaded for it. Captures the stored size and content type: a pending library upload becomes ready; a ready one is returned unchanged. A member upload is finalized only by its uploader and is answered with 403.`,
|
|
60
39
|
params: AssetIdParam,
|
|
61
40
|
response: {
|
|
62
41
|
200: Asset,
|
|
63
42
|
...refusals(403, 404)
|
|
64
43
|
}
|
|
65
44
|
},
|
|
66
|
-
handler: async (req
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
const asset = await assets.confirm(orgId, req.params.id);
|
|
70
|
-
if (!asset) throw new NotFoundError("Asset", req.params.id);
|
|
71
|
-
return asset;
|
|
45
|
+
handler: async (req) => {
|
|
46
|
+
const actor = await resolveActor(container, req);
|
|
47
|
+
return assets.confirm(req.params.id, actor);
|
|
72
48
|
}
|
|
73
49
|
});
|
|
74
50
|
r.route({
|
|
75
51
|
method: "GET",
|
|
76
52
|
url: "/api/assets",
|
|
77
|
-
preHandler: staff,
|
|
78
53
|
schema: {
|
|
79
54
|
operationId: "listAssets",
|
|
80
55
|
tags,
|
|
81
|
-
summary: "Browse the organization's media library
|
|
82
|
-
description:
|
|
56
|
+
summary: "Browse the organization's media library",
|
|
57
|
+
description: `Requires one of \`media:read\`, \`courses:write\`, \`downloads:write\`, \`communities:write\`. \`media:read\` lists the whole library, \`source: member\` members' uploads; the write permission of a content item lists the files uploaded for it, named by \`contentId\`.`,
|
|
83
58
|
querystring: AssetsQuery,
|
|
84
59
|
response: {
|
|
85
60
|
200: AssetsPage,
|
|
86
61
|
...refusals(403)
|
|
87
62
|
}
|
|
88
63
|
},
|
|
89
|
-
handler: async (req
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
return assets.list(orgId, req.query);
|
|
64
|
+
handler: async (req) => {
|
|
65
|
+
const actor = await resolveActor(container, req);
|
|
66
|
+
return assets.list(req.query, actor);
|
|
93
67
|
}
|
|
94
68
|
});
|
|
95
69
|
r.route({
|
|
96
70
|
method: "GET",
|
|
97
71
|
url: "/api/assets/:id",
|
|
98
|
-
preHandler: staff,
|
|
99
72
|
schema: {
|
|
100
73
|
operationId: "getAsset",
|
|
101
74
|
tags,
|
|
102
|
-
summary: "Get an asset's metadata
|
|
103
|
-
description:
|
|
75
|
+
summary: "Get an asset's metadata",
|
|
76
|
+
description: `Requires one of \`media:read\`, \`courses:write\`, \`downloads:write\`, \`communities:write\`. \`media:read\` reaches every file; the write permission of a content item reaches the files uploaded for it.`,
|
|
104
77
|
params: AssetIdParam,
|
|
105
78
|
response: {
|
|
106
79
|
200: Asset,
|
|
107
80
|
...refusals(403, 404)
|
|
108
81
|
}
|
|
109
82
|
},
|
|
110
|
-
handler: async (req
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
const asset = await assets.get(orgId, req.params.id);
|
|
114
|
-
if (!asset) throw new NotFoundError("Asset", req.params.id);
|
|
115
|
-
return asset;
|
|
83
|
+
handler: async (req) => {
|
|
84
|
+
const actor = await resolveActor(container, req);
|
|
85
|
+
return assets.get(req.params.id, actor);
|
|
116
86
|
}
|
|
117
87
|
});
|
|
118
88
|
r.route({
|
|
119
89
|
method: "DELETE",
|
|
120
90
|
url: "/api/assets/:id",
|
|
121
|
-
preHandler: staff,
|
|
122
91
|
schema: {
|
|
123
92
|
operationId: "deleteAsset",
|
|
124
93
|
tags,
|
|
125
|
-
summary: "Delete an asset nothing references
|
|
126
|
-
description:
|
|
94
|
+
summary: "Delete an asset nothing references",
|
|
95
|
+
description: `Requires \`media:delete\`. Removes the row and the stored file. 409 while content still uses it.`,
|
|
127
96
|
params: AssetIdParam,
|
|
128
97
|
response: {
|
|
129
98
|
204: z.void(),
|
|
@@ -131,9 +100,8 @@ async function assetsRoutes(app, container) {
|
|
|
131
100
|
}
|
|
132
101
|
},
|
|
133
102
|
handler: async (req, reply) => {
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
if (!await assets.remove(orgId, req.params.id)) throw new NotFoundError("Asset", req.params.id);
|
|
103
|
+
const actor = await resolveActor(container, req);
|
|
104
|
+
await assets.remove(req.params.id, actor);
|
|
137
105
|
return reply.code(204).send();
|
|
138
106
|
}
|
|
139
107
|
});
|
|
@@ -141,21 +109,20 @@ async function assetsRoutes(app, container) {
|
|
|
141
109
|
suffix: "file",
|
|
142
110
|
download: false,
|
|
143
111
|
operationId: "getLibraryFile",
|
|
144
|
-
summary: "Redirect to a library file to show it
|
|
112
|
+
summary: "Redirect to a library file to show it"
|
|
145
113
|
}, {
|
|
146
114
|
suffix: "download",
|
|
147
115
|
download: true,
|
|
148
116
|
operationId: "downloadLibraryFile",
|
|
149
|
-
summary: "Redirect to a library file saved under its filename
|
|
117
|
+
summary: "Redirect to a library file saved under its filename"
|
|
150
118
|
}]) r.route({
|
|
151
119
|
method: "GET",
|
|
152
120
|
url: `/api/assets/:id/${suffix}`,
|
|
153
|
-
preHandler: staff,
|
|
154
121
|
schema: {
|
|
155
122
|
operationId,
|
|
156
123
|
tags,
|
|
157
124
|
summary,
|
|
158
|
-
description:
|
|
125
|
+
description: `Requires one of \`media:read\`, \`courses:write\`, \`downloads:write\`, \`communities:write\`. \`media:read\` reaches every file; the write permission of a content item reaches the files uploaded for it. Ready library files of the organization; member uploads and pending files answer 404.`,
|
|
159
126
|
params: AssetIdParam,
|
|
160
127
|
response: {
|
|
161
128
|
302: z.void(),
|
|
@@ -163,10 +130,8 @@ async function assetsRoutes(app, container) {
|
|
|
163
130
|
}
|
|
164
131
|
},
|
|
165
132
|
handler: async (req, reply) => {
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
const url = await assets.libraryFile(orgId, req.params.id, { download });
|
|
169
|
-
if (!url) throw new NotFoundError("Asset", req.params.id);
|
|
133
|
+
const actor = await resolveActor(container, req);
|
|
134
|
+
const url = await assets.libraryFile(req.params.id, { download }, actor);
|
|
170
135
|
return reply.header("cache-control", "no-store").header("referrer-policy", "no-referrer").redirect(url, 302);
|
|
171
136
|
}
|
|
172
137
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assets.js","names":[],"sources":["../../../src/http/routes/assets.ts"],"sourcesContent":["// HTTP routes for the assets media library.
|
|
1
|
+
{"version":3,"file":"assets.js","names":[],"sources":["../../../src/http/routes/assets.ts"],"sourcesContent":["// HTTP routes for the assets media library. Assets are stored under the org's\n// private prefix and served through stable URLs that redirect to a signed\n// storage URL.\nimport type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport { z } from 'zod';\nimport {\n Asset,\n AssetIdParam,\n AssetsPage,\n AssetsQuery,\n RequestUpload,\n UploadTicket,\n refusals,\n} from '../schemas/index.js';\nimport type { Container } from '../../app/container.js';\nimport { resolveActor } from '../scope.js';\n\nexport async function assetsRoutes(app: FastifyInstance, container: Container): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n const assets = container.assets;\n const tags = ['Assets'];\n\n r.route({\n method: 'POST',\n url: '/api/uploads',\n schema: {\n operationId: 'requestUpload',\n tags,\n summary: 'Register a library asset and get a presigned upload URL',\n description: `Requires one of \\`media:write\\`, \\`courses:write\\`, \\`downloads:write\\`, \\`communities:write\\`. \\`media:write\\` uploads to the library; the write permission of a content item uploads for that item when \\`contentId\\` names it, and the asset records it. The asset stays pending until you upload the file and confirm it. 404 when \\`contentId\\` is not a content item of the organization.`,\n body: RequestUpload,\n response: { 201: UploadTicket, ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n const ticket = await assets.requestUpload(req.body, actor);\n return reply.code(201).send(ticket);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/assets/:id/confirm',\n schema: {\n operationId: 'confirmAsset',\n tags,\n summary: 'Confirm a library upload completed',\n description: `Requires one of \\`media:read\\`, \\`courses:write\\`, \\`downloads:write\\`, \\`communities:write\\`. \\`media:read\\` reaches every file; the write permission of a content item reaches the files uploaded for it. Captures the stored size and content type: a pending library upload becomes ready; a ready one is returned unchanged. A member upload is finalized only by its uploader and is answered with 403.`,\n params: AssetIdParam,\n response: { 200: Asset, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return assets.confirm(req.params.id, actor);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/assets',\n schema: {\n operationId: 'listAssets',\n tags,\n summary: \"Browse the organization's media library\",\n description: `Requires one of \\`media:read\\`, \\`courses:write\\`, \\`downloads:write\\`, \\`communities:write\\`. \\`media:read\\` lists the whole library, \\`source: member\\` members' uploads; the write permission of a content item lists the files uploaded for it, named by \\`contentId\\`.`,\n querystring: AssetsQuery,\n response: { 200: AssetsPage, ...refusals(403) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return assets.list(req.query, actor);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/assets/:id',\n schema: {\n operationId: 'getAsset',\n tags,\n summary: \"Get an asset's metadata\",\n description: `Requires one of \\`media:read\\`, \\`courses:write\\`, \\`downloads:write\\`, \\`communities:write\\`. \\`media:read\\` reaches every file; the write permission of a content item reaches the files uploaded for it.`,\n params: AssetIdParam,\n response: { 200: Asset, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return assets.get(req.params.id, actor);\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/assets/:id',\n schema: {\n operationId: 'deleteAsset',\n tags,\n summary: 'Delete an asset nothing references',\n description: `Requires \\`media:delete\\`. Removes the row and the stored file. 409 while content 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 assets.remove(req.params.id, actor);\n return reply.code(204).send();\n },\n });\n\n for (const { suffix, download, operationId, summary } of [\n {\n suffix: 'file',\n download: false,\n operationId: 'getLibraryFile',\n summary: 'Redirect to a library file to show it',\n },\n {\n suffix: 'download',\n download: true,\n operationId: 'downloadLibraryFile',\n summary: 'Redirect to a library file saved under its filename',\n },\n ]) {\n r.route({\n method: 'GET',\n url: `/api/assets/:id/${suffix}`,\n schema: {\n operationId,\n tags,\n summary,\n description: `Requires one of \\`media:read\\`, \\`courses:write\\`, \\`downloads:write\\`, \\`communities:write\\`. \\`media:read\\` reaches every file; the write permission of a content item reaches the files uploaded for it. Ready library files of the organization; member uploads and pending files answer 404.`,\n params: AssetIdParam,\n response: { 302: z.void(), ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n const url = await assets.libraryFile(req.params.id, { download }, actor);\n return reply\n .header('cache-control', 'no-store')\n .header('referrer-policy', 'no-referrer')\n .redirect(url, 302);\n },\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { refusals } from "../schemas/shared.js";
|
|
2
|
-
import {
|
|
2
|
+
import { resolveActor } from "../scope.js";
|
|
3
3
|
import { Automation, AutomationIdParam, AutomationRun, AutomationRunParams, AutomationRunsPage, AutomationRunsQuery, AutomationsQuery, AvailableAction, AvailableTriggers, CreateAutomationBody, UpdateAutomationBody } from "../schemas/automations.js";
|
|
4
4
|
import "../schemas/index.js";
|
|
5
5
|
import { z } from "zod";
|
|
6
|
-
import { NotFoundError } from "@headless-lms/core/shared/errors";
|
|
7
6
|
//#region src/http/routes/automations.ts
|
|
8
7
|
async function automationsRoutes(app, container) {
|
|
9
8
|
const r = app.withTypeProvider();
|
|
@@ -16,8 +15,8 @@ async function automationsRoutes(app, container) {
|
|
|
16
15
|
schema: {
|
|
17
16
|
operationId: "listAutomations",
|
|
18
17
|
tags,
|
|
19
|
-
summary: "List automations
|
|
20
|
-
description:
|
|
18
|
+
summary: "List automations",
|
|
19
|
+
description: `Requires \`automations:read\`. Optionally only workflows or only webhooks.`,
|
|
21
20
|
querystring: AutomationsQuery,
|
|
22
21
|
response: {
|
|
23
22
|
200: z.array(Automation),
|
|
@@ -25,8 +24,8 @@ async function automationsRoutes(app, container) {
|
|
|
25
24
|
}
|
|
26
25
|
},
|
|
27
26
|
handler: async (req) => {
|
|
28
|
-
const
|
|
29
|
-
return automations.list(
|
|
27
|
+
const actor = await resolveActor(container, req);
|
|
28
|
+
return automations.list(req.query, actor);
|
|
30
29
|
}
|
|
31
30
|
});
|
|
32
31
|
r.route({
|
|
@@ -36,16 +35,16 @@ async function automationsRoutes(app, container) {
|
|
|
36
35
|
schema: {
|
|
37
36
|
operationId: "listAutomationActions",
|
|
38
37
|
tags,
|
|
39
|
-
summary: "List the actions automations can use
|
|
40
|
-
description: "
|
|
38
|
+
summary: "List the actions automations can use",
|
|
39
|
+
description: "Requires `automations:read`.",
|
|
41
40
|
response: {
|
|
42
41
|
200: z.array(AvailableAction),
|
|
43
42
|
...refusals(403)
|
|
44
43
|
}
|
|
45
44
|
},
|
|
46
45
|
handler: async (req) => {
|
|
47
|
-
await
|
|
48
|
-
return automations.availableActions();
|
|
46
|
+
const actor = await resolveActor(container, req);
|
|
47
|
+
return automations.availableActions(actor);
|
|
49
48
|
}
|
|
50
49
|
});
|
|
51
50
|
r.route({
|
|
@@ -55,16 +54,16 @@ async function automationsRoutes(app, container) {
|
|
|
55
54
|
schema: {
|
|
56
55
|
operationId: "listAutomationTriggers",
|
|
57
56
|
tags,
|
|
58
|
-
summary: "List the domain events automations can react to
|
|
59
|
-
description: "
|
|
57
|
+
summary: "List the domain events automations can react to",
|
|
58
|
+
description: "Requires `automations:read`.",
|
|
60
59
|
response: {
|
|
61
60
|
200: AvailableTriggers,
|
|
62
61
|
...refusals(403)
|
|
63
62
|
}
|
|
64
63
|
},
|
|
65
64
|
handler: async (req) => {
|
|
66
|
-
await
|
|
67
|
-
return automations.availableTriggers();
|
|
65
|
+
const actor = await resolveActor(container, req);
|
|
66
|
+
return automations.availableTriggers(actor);
|
|
68
67
|
}
|
|
69
68
|
});
|
|
70
69
|
r.route({
|
|
@@ -74,8 +73,8 @@ async function automationsRoutes(app, container) {
|
|
|
74
73
|
schema: {
|
|
75
74
|
operationId: "createAutomation",
|
|
76
75
|
tags,
|
|
77
|
-
summary: "Create a workflow automation
|
|
78
|
-
description:
|
|
76
|
+
summary: "Create a workflow automation",
|
|
77
|
+
description: `Requires \`automations:write\`. 400 when a trigger is reserved, not an event the system emits or an unsupported schedule, or an action is reserved for webhooks or no longer available.`,
|
|
79
78
|
body: CreateAutomationBody,
|
|
80
79
|
response: {
|
|
81
80
|
201: Automation,
|
|
@@ -83,8 +82,8 @@ async function automationsRoutes(app, container) {
|
|
|
83
82
|
}
|
|
84
83
|
},
|
|
85
84
|
handler: async (req, reply) => {
|
|
86
|
-
const
|
|
87
|
-
const automation = await automations.create(
|
|
85
|
+
const actor = await resolveActor(container, req);
|
|
86
|
+
const automation = await automations.create(req.body, actor);
|
|
88
87
|
return reply.code(201).send(automation);
|
|
89
88
|
}
|
|
90
89
|
});
|
|
@@ -95,8 +94,8 @@ async function automationsRoutes(app, container) {
|
|
|
95
94
|
schema: {
|
|
96
95
|
operationId: "getAutomation",
|
|
97
96
|
tags,
|
|
98
|
-
summary: "Get an automation
|
|
99
|
-
description:
|
|
97
|
+
summary: "Get an automation",
|
|
98
|
+
description: `Requires \`automations:read\`. Workflows and webhooks alike.`,
|
|
100
99
|
params: AutomationIdParam,
|
|
101
100
|
response: {
|
|
102
101
|
200: Automation,
|
|
@@ -104,10 +103,8 @@ async function automationsRoutes(app, container) {
|
|
|
104
103
|
}
|
|
105
104
|
},
|
|
106
105
|
handler: async (req) => {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
if (!automation) throw new NotFoundError("Automation", req.params.id);
|
|
110
|
-
return automation;
|
|
106
|
+
const actor = await resolveActor(container, req);
|
|
107
|
+
return automations.get(req.params.id, actor);
|
|
111
108
|
}
|
|
112
109
|
});
|
|
113
110
|
r.route({
|
|
@@ -117,8 +114,8 @@ async function automationsRoutes(app, container) {
|
|
|
117
114
|
schema: {
|
|
118
115
|
operationId: "updateAutomation",
|
|
119
116
|
tags,
|
|
120
|
-
summary: "Update a workflow automation
|
|
121
|
-
description:
|
|
117
|
+
summary: "Update a workflow automation",
|
|
118
|
+
description: `Requires \`automations:write\`. Webhooks change through the webhook endpoints (409). 400 when a trigger is reserved, not an event the system emits or an unsupported schedule, or an action is reserved for webhooks or no longer available.`,
|
|
122
119
|
params: AutomationIdParam,
|
|
123
120
|
body: UpdateAutomationBody,
|
|
124
121
|
response: {
|
|
@@ -127,10 +124,8 @@ async function automationsRoutes(app, container) {
|
|
|
127
124
|
}
|
|
128
125
|
},
|
|
129
126
|
handler: async (req) => {
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
if (!automation) throw new NotFoundError("Automation", req.params.id);
|
|
133
|
-
return automation;
|
|
127
|
+
const actor = await resolveActor(container, req);
|
|
128
|
+
return automations.update(req.params.id, req.body, actor);
|
|
134
129
|
}
|
|
135
130
|
});
|
|
136
131
|
r.route({
|
|
@@ -140,8 +135,8 @@ async function automationsRoutes(app, container) {
|
|
|
140
135
|
schema: {
|
|
141
136
|
operationId: "deleteAutomation",
|
|
142
137
|
tags,
|
|
143
|
-
summary: "Delete a workflow automation
|
|
144
|
-
description:
|
|
138
|
+
summary: "Delete a workflow automation",
|
|
139
|
+
description: `Requires \`automations:delete\`. Webhooks are deleted through the webhook endpoints (409). Its runs stay readable.`,
|
|
145
140
|
params: AutomationIdParam,
|
|
146
141
|
response: {
|
|
147
142
|
204: z.void(),
|
|
@@ -149,8 +144,8 @@ async function automationsRoutes(app, container) {
|
|
|
149
144
|
}
|
|
150
145
|
},
|
|
151
146
|
handler: async (req, reply) => {
|
|
152
|
-
const
|
|
153
|
-
|
|
147
|
+
const actor = await resolveActor(container, req);
|
|
148
|
+
await automations.delete(req.params.id, actor);
|
|
154
149
|
return reply.code(204).send();
|
|
155
150
|
}
|
|
156
151
|
});
|
|
@@ -161,8 +156,8 @@ async function automationsRoutes(app, container) {
|
|
|
161
156
|
schema: {
|
|
162
157
|
operationId: "listAutomationRuns",
|
|
163
158
|
tags,
|
|
164
|
-
summary: "List an automation's runs
|
|
165
|
-
description:
|
|
159
|
+
summary: "List an automation's runs",
|
|
160
|
+
description: `Requires \`automations:read\`. A deleted automation's runs remain reachable as an audit trail, so an unknown id answers an empty page rather than 404. A run's event carries the fields a webhook delivery of that event would.`,
|
|
166
161
|
params: AutomationIdParam,
|
|
167
162
|
querystring: AutomationRunsQuery,
|
|
168
163
|
response: {
|
|
@@ -171,8 +166,8 @@ async function automationsRoutes(app, container) {
|
|
|
171
166
|
}
|
|
172
167
|
},
|
|
173
168
|
handler: async (req) => {
|
|
174
|
-
const
|
|
175
|
-
return automations.listRuns(
|
|
169
|
+
const actor = await resolveActor(container, req);
|
|
170
|
+
return automations.listRuns(req.params.id, req.query, actor);
|
|
176
171
|
}
|
|
177
172
|
});
|
|
178
173
|
r.route({
|
|
@@ -182,8 +177,8 @@ async function automationsRoutes(app, container) {
|
|
|
182
177
|
schema: {
|
|
183
178
|
operationId: "rerunAutomationRun",
|
|
184
179
|
tags,
|
|
185
|
-
summary: "Run a finished run again
|
|
186
|
-
description:
|
|
180
|
+
summary: "Run a finished run again",
|
|
181
|
+
description: `Requires \`automations:write\`. Dispatches the same run again with the automation's current steps; the new outcome replaces the run's previous one. For a webhook this resends the delivery to its current URL. A run that is still running can't be rerun (409).`,
|
|
187
182
|
params: AutomationRunParams,
|
|
188
183
|
response: {
|
|
189
184
|
200: AutomationRun,
|
|
@@ -191,8 +186,8 @@ async function automationsRoutes(app, container) {
|
|
|
191
186
|
}
|
|
192
187
|
},
|
|
193
188
|
handler: async (req) => {
|
|
194
|
-
const
|
|
195
|
-
return automations.rerun(
|
|
189
|
+
const actor = await resolveActor(container, req);
|
|
190
|
+
return automations.rerun(req.params.id, req.params.runId, actor);
|
|
196
191
|
}
|
|
197
192
|
});
|
|
198
193
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"automations.js","names":[],"sources":["../../../src/http/routes/automations.ts"],"sourcesContent":["// HTTP routes for the automations context: rules that match a trigger (a\n// domain event type) against enabled automations and run an ordered list of\n// actions, plus the run history each automation accumulates.\nimport type { FastifyInstance } from 'fastify';\nimport { z } from 'zod';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport {\n Automation,\n AutomationIdParam,\n AutomationRun,\n AutomationRunParams,\n AutomationRunsPage,\n AutomationRunsQuery,\n AutomationsQuery,\n AvailableAction,\n AvailableTriggers,\n CreateAutomationBody,\n UpdateAutomationBody,\n refusals,\n} from '../schemas/index.js';\nimport { NotFoundError } from '@headless-lms/core/shared/errors';\nimport type { Container } from '../../app/container.js';\nimport { resolveScope } from '../scope.js';\n\nexport async function automationsRoutes(app: FastifyInstance, container: Container): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n const automations = container.automations;\n const tags = ['Automations'];\n\n r.route({\n method: 'GET',\n url: '/api/automations',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listAutomations',\n tags,\n summary: 'List automations (staff)',\n description:\n 'Staff only (owner, admin, instructor). Optionally only workflows or only webhooks.',\n querystring: AutomationsQuery,\n response: { 200: z.array(Automation), ...refusals(403) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return automations.list(scope.orgId, req.query);\n },\n });\n\n // Before `/api/automations/:id` — otherwise `:id` would swallow these path segments.\n r.route({\n method: 'GET',\n url: '/api/automations/actions',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listAutomationActions',\n tags,\n summary: 'List the actions automations can use (staff)',\n description: 'Staff only (owner, admin, instructor).',\n response: { 200: z.array(AvailableAction), ...refusals(403) },\n },\n handler: async (req) => {\n await resolveScope(container, req);\n return automations.availableActions();\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/automations/triggers',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listAutomationTriggers',\n tags,\n summary: 'List the domain events automations can react to (staff)',\n description: 'Staff only (owner, admin, instructor).',\n response: { 200: AvailableTriggers, ...refusals(403) },\n },\n handler: async (req) => {\n await resolveScope(container, req);\n return automations.availableTriggers();\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/automations',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'createAutomation',\n tags,\n summary: 'Create a workflow automation (staff)',\n description:\n 'Staff only (owner, admin, instructor). 400 when a trigger is reserved, not an event the system emits or an unsupported schedule, or an action is reserved for webhooks.',\n body: CreateAutomationBody,\n response: { 201: Automation, ...refusals(400, 403) },\n },\n handler: async (req, reply) => {\n const scope = await resolveScope(container, req);\n const automation = await automations.create(scope.orgId, req.body);\n return reply.code(201).send(automation);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/automations/:id',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getAutomation',\n tags,\n summary: 'Get an automation (staff)',\n description: 'Staff only (owner, admin, instructor). Workflows and webhooks alike.',\n params: AutomationIdParam,\n response: { 200: Automation, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n const automation = await automations.get(scope.orgId, req.params.id);\n if (!automation) {\n throw new NotFoundError('Automation', req.params.id);\n }\n return automation;\n },\n });\n\n r.route({\n method: 'PATCH',\n url: '/api/automations/:id',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'updateAutomation',\n tags,\n summary: 'Update a workflow automation (staff)',\n description:\n 'Staff only (owner, admin, instructor). Webhooks change through the webhook endpoints (409). 400 when a trigger is reserved, not an event the system emits or an unsupported schedule, or an action is reserved for webhooks.',\n params: AutomationIdParam,\n body: UpdateAutomationBody,\n response: { 200: Automation, ...refusals(400, 403, 404, 409) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n const automation = await automations.update(scope.orgId, req.params.id, req.body);\n if (!automation) {\n throw new NotFoundError('Automation', req.params.id);\n }\n return automation;\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/automations/:id',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'deleteAutomation',\n tags,\n summary: 'Delete a workflow automation (staff)',\n description:\n 'Staff only (owner, admin, instructor). Webhooks are deleted through the webhook endpoints, and system automations cannot be deleted (409). Its runs stay readable.',\n params: AutomationIdParam,\n response: { 204: z.void(), ...refusals(403, 404, 409) },\n },\n handler: async (req, reply) => {\n const scope = await resolveScope(container, req);\n const deleted = await automations.delete(scope.orgId, req.params.id);\n if (!deleted) {\n throw new NotFoundError('Automation', req.params.id);\n }\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/automations/:id/runs',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listAutomationRuns',\n tags,\n summary: \"List an automation's runs (staff)\",\n description:\n \"Staff only (owner, admin, instructor). A deleted automation's runs remain reachable as an audit trail, so an unknown id answers an empty page rather than 404. A run's event carries the fields a webhook delivery of that event would.\",\n params: AutomationIdParam,\n querystring: AutomationRunsQuery,\n response: { 200: AutomationRunsPage, ...refusals(403) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n // No existence pre-check: runs deliberately survive automation deletion (audit trail).\n return automations.listRuns(scope.orgId, req.params.id, req.query);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/automations/:id/runs/:runId/rerun',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'rerunAutomationRun',\n tags,\n summary: 'Run a finished run again (staff)',\n description:\n \"Staff only (owner, admin, instructor). Dispatches the same run again with the automation's current steps; the new outcome replaces the run's previous one. For a webhook this resends the delivery to its current URL. A run that is still running can't be rerun (409).\",\n params: AutomationRunParams,\n response: { 200: AutomationRun, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return automations.rerun(scope.orgId, req.params.id, req.params.runId);\n },\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"automations.js","names":[],"sources":["../../../src/http/routes/automations.ts"],"sourcesContent":["// HTTP routes for the automations context: rules that match a trigger (a\n// domain event type) against enabled automations and run an ordered list of\n// actions, plus the run history each automation accumulates.\nimport type { FastifyInstance } from 'fastify';\nimport { z } from 'zod';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport {\n Automation,\n AutomationIdParam,\n AutomationRun,\n AutomationRunParams,\n AutomationRunsPage,\n AutomationRunsQuery,\n AutomationsQuery,\n AvailableAction,\n AvailableTriggers,\n CreateAutomationBody,\n UpdateAutomationBody,\n refusals,\n} from '../schemas/index.js';\nimport type { Container } from '../../app/container.js';\nimport { resolveActor } from '../scope.js';\n\nexport async function automationsRoutes(app: FastifyInstance, container: Container): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n const automations = container.automations;\n const tags = ['Automations'];\n\n r.route({\n method: 'GET',\n url: '/api/automations',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listAutomations',\n tags,\n summary: 'List automations',\n description: `Requires \\`automations:read\\`. Optionally only workflows or only webhooks.`,\n querystring: AutomationsQuery,\n response: { 200: z.array(Automation), ...refusals(403) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return automations.list(req.query, actor);\n },\n });\n\n // Before `/api/automations/:id` — otherwise `:id` would swallow these path segments.\n r.route({\n method: 'GET',\n url: '/api/automations/actions',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listAutomationActions',\n tags,\n summary: 'List the actions automations can use',\n description: 'Requires `automations:read`.',\n response: { 200: z.array(AvailableAction), ...refusals(403) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return automations.availableActions(actor);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/automations/triggers',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listAutomationTriggers',\n tags,\n summary: 'List the domain events automations can react to',\n description: 'Requires `automations:read`.',\n response: { 200: AvailableTriggers, ...refusals(403) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return automations.availableTriggers(actor);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/automations',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'createAutomation',\n tags,\n summary: 'Create a workflow automation',\n description: `Requires \\`automations:write\\`. 400 when a trigger is reserved, not an event the system emits or an unsupported schedule, or an action is reserved for webhooks or no longer available.`,\n body: CreateAutomationBody,\n response: { 201: Automation, ...refusals(400, 403) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n const automation = await automations.create(req.body, actor);\n return reply.code(201).send(automation);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/automations/:id',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getAutomation',\n tags,\n summary: 'Get an automation',\n description: `Requires \\`automations:read\\`. Workflows and webhooks alike.`,\n params: AutomationIdParam,\n response: { 200: Automation, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return automations.get(req.params.id, actor);\n },\n });\n\n r.route({\n method: 'PATCH',\n url: '/api/automations/:id',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'updateAutomation',\n tags,\n summary: 'Update a workflow automation',\n description: `Requires \\`automations:write\\`. Webhooks change through the webhook endpoints (409). 400 when a trigger is reserved, not an event the system emits or an unsupported schedule, or an action is reserved for webhooks or no longer available.`,\n params: AutomationIdParam,\n body: UpdateAutomationBody,\n response: { 200: Automation, ...refusals(400, 403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return automations.update(req.params.id, req.body, actor);\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/automations/:id',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'deleteAutomation',\n tags,\n summary: 'Delete a workflow automation',\n description: `Requires \\`automations:delete\\`. Webhooks are deleted through the webhook endpoints (409). Its runs stay readable.`,\n params: AutomationIdParam,\n response: { 204: z.void(), ...refusals(403, 404, 409) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n await automations.delete(req.params.id, actor);\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/automations/:id/runs',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listAutomationRuns',\n tags,\n summary: \"List an automation's runs\",\n description: `Requires \\`automations:read\\`. A deleted automation's runs remain reachable as an audit trail, so an unknown id answers an empty page rather than 404. A run's event carries the fields a webhook delivery of that event would.`,\n params: AutomationIdParam,\n querystring: AutomationRunsQuery,\n response: { 200: AutomationRunsPage, ...refusals(403) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n // No existence pre-check: runs deliberately survive automation deletion (audit trail).\n return automations.listRuns(req.params.id, req.query, actor);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/automations/:id/runs/:runId/rerun',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'rerunAutomationRun',\n tags,\n summary: 'Run a finished run again',\n description: `Requires \\`automations:write\\`. Dispatches the same run again with the automation's current steps; the new outcome replaces the run's previous one. For a webhook this resends the delivery to its current URL. A run that is still running can't be rerun (409).`,\n params: AutomationRunParams,\n response: { 200: AutomationRun, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return automations.rerun(req.params.id, req.params.runId, actor);\n },\n });\n}\n"],"mappings":";;;;;;AAuBA,eAAsB,kBAAkB,KAAsB,WAAqC;CACjG,MAAM,IAAI,IAAI,iBAAkC;CAChD,MAAM,cAAc,UAAU;CAC9B,MAAM,OAAO,CAAC,aAAa;CAE3B,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb;GACA,SAAS;GACT,aAAa;GACb,aAAa;GACb,UAAU;IAAE,KAAK,EAAE,MAAM,UAAU;IAAG,GAAG,SAAS,GAAG;GAAE;EACzD;EACA,SAAS,OAAO,QAAQ;GACtB,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,OAAO,YAAY,KAAK,IAAI,OAAO,KAAK;EAC1C;CACF,CAAC;CAGD,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb;GACA,SAAS;GACT,aAAa;GACb,UAAU;IAAE,KAAK,EAAE,MAAM,eAAe;IAAG,GAAG,SAAS,GAAG;GAAE;EAC9D;EACA,SAAS,OAAO,QAAQ;GACtB,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,OAAO,YAAY,iBAAiB,KAAK;EAC3C;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb;GACA,SAAS;GACT,aAAa;GACb,UAAU;IAAE,KAAK;IAAmB,GAAG,SAAS,GAAG;GAAE;EACvD;EACA,SAAS,OAAO,QAAQ;GACtB,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,OAAO,YAAY,kBAAkB,KAAK;EAC5C;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb;GACA,SAAS;GACT,aAAa;GACb,MAAM;GACN,UAAU;IAAE,KAAK;IAAY,GAAG,SAAS,KAAK,GAAG;GAAE;EACrD;EACA,SAAS,OAAO,KAAK,UAAU;GAC7B,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,MAAM,aAAa,MAAM,YAAY,OAAO,IAAI,MAAM,KAAK;GAC3D,OAAO,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,UAAU;EACxC;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb;GACA,SAAS;GACT,aAAa;GACb,QAAQ;GACR,UAAU;IAAE,KAAK;IAAY,GAAG,SAAS,KAAK,GAAG;GAAE;EACrD;EACA,SAAS,OAAO,QAAQ;GACtB,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,OAAO,YAAY,IAAI,IAAI,OAAO,IAAI,KAAK;EAC7C;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb;GACA,SAAS;GACT,aAAa;GACb,QAAQ;GACR,MAAM;GACN,UAAU;IAAE,KAAK;IAAY,GAAG,SAAS,KAAK,KAAK,KAAK,GAAG;GAAE;EAC/D;EACA,SAAS,OAAO,QAAQ;GACtB,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,OAAO,YAAY,OAAO,IAAI,OAAO,IAAI,IAAI,MAAM,KAAK;EAC1D;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb;GACA,SAAS;GACT,aAAa;GACb,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,YAAY,OAAO,IAAI,OAAO,IAAI,KAAK;GAC7C,OAAO,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK;EAC9B;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb;GACA,SAAS;GACT,aAAa;GACb,QAAQ;GACR,aAAa;GACb,UAAU;IAAE,KAAK;IAAoB,GAAG,SAAS,GAAG;GAAE;EACxD;EACA,SAAS,OAAO,QAAQ;GACtB,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAE/C,OAAO,YAAY,SAAS,IAAI,OAAO,IAAI,IAAI,OAAO,KAAK;EAC7D;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb;GACA,SAAS;GACT,aAAa;GACb,QAAQ;GACR,UAAU;IAAE,KAAK;IAAe,GAAG,SAAS,KAAK,KAAK,GAAG;GAAE;EAC7D;EACA,SAAS,OAAO,QAAQ;GACtB,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,OAAO,YAAY,MAAM,IAAI,OAAO,IAAI,IAAI,OAAO,OAAO,KAAK;EACjE;CACF,CAAC;AACH"}
|