@headless-lms/server 0.2.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.
- package/dist/_virtual/_rolldown/runtime.js +5 -0
- package/dist/app/community-mail.d.ts +24 -0
- package/dist/app/community-mail.js +92 -0
- package/dist/app/community-mail.js.map +1 -0
- package/dist/app/container.d.ts +40 -19
- package/dist/app/container.js +294 -45
- package/dist/app/container.js.map +1 -1
- package/dist/app/mcp-endpoints.d.ts +13 -0
- package/dist/app/mcp-endpoints.js +25 -0
- package/dist/app/mcp-endpoints.js.map +1 -0
- package/dist/app/notification-channels.d.ts +47 -0
- package/dist/app/notification-channels.js +174 -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 +95 -0
- package/dist/app/notification-reads.js.map +1 -0
- package/dist/http/config.d.ts +2 -1
- package/dist/http/errors.d.ts +15 -0
- package/dist/http/errors.js +162 -0
- package/dist/http/errors.js.map +1 -0
- package/dist/http/mcp/catalogue.d.ts +37 -0
- package/dist/http/mcp/catalogue.js +69 -0
- package/dist/http/mcp/catalogue.js.map +1 -0
- package/dist/http/mcp/challenge.d.ts +7 -0
- package/dist/http/mcp/challenge.js +35 -0
- package/dist/http/mcp/challenge.js.map +1 -0
- package/dist/http/mcp/input-schema.d.ts +7 -0
- package/dist/http/mcp/input-schema.js +28 -0
- package/dist/http/mcp/input-schema.js.map +1 -0
- package/dist/http/mcp/route.d.ts +8 -0
- package/dist/http/mcp/route.js +75 -0
- package/dist/http/mcp/route.js.map +1 -0
- package/dist/http/mcp/server.d.ts +8 -0
- package/dist/http/mcp/server.js +31 -0
- package/dist/http/mcp/server.js.map +1 -0
- package/dist/http/mcp/test-support.d.ts +55 -0
- package/dist/http/mcp/test-support.js +151 -0
- package/dist/http/mcp/test-support.js.map +1 -0
- package/dist/http/mcp/tool.d.ts +48 -0
- package/dist/http/mcp/tool.js +58 -0
- package/dist/http/mcp/tool.js.map +1 -0
- package/dist/http/mcp/tools/automations.d.ts +6 -0
- package/dist/http/mcp/tools/automations.js +120 -0
- package/dist/http/mcp/tools/automations.js.map +1 -0
- package/dist/http/mcp/tools/catalog.d.ts +6 -0
- package/dist/http/mcp/tools/catalog.js +200 -0
- package/dist/http/mcp/tools/catalog.js.map +1 -0
- package/dist/http/mcp/tools/comments.d.ts +6 -0
- package/dist/http/mcp/tools/comments.js +70 -0
- package/dist/http/mcp/tools/comments.js.map +1 -0
- package/dist/http/mcp/tools/communities.d.ts +6 -0
- package/dist/http/mcp/tools/communities.js +175 -0
- package/dist/http/mcp/tools/communities.js.map +1 -0
- package/dist/http/mcp/tools/community-members.d.ts +6 -0
- package/dist/http/mcp/tools/community-members.js +89 -0
- package/dist/http/mcp/tools/community-members.js.map +1 -0
- package/dist/http/mcp/tools/community-moderation.d.ts +6 -0
- package/dist/http/mcp/tools/community-moderation.js +144 -0
- package/dist/http/mcp/tools/community-moderation.js.map +1 -0
- package/dist/http/mcp/tools/courses.d.ts +6 -0
- package/dist/http/mcp/tools/courses.js +121 -0
- package/dist/http/mcp/tools/courses.js.map +1 -0
- package/dist/http/mcp/tools/index.d.ts +6 -0
- package/dist/http/mcp/tools/index.js +23 -0
- package/dist/http/mcp/tools/index.js.map +1 -0
- package/dist/http/mcp/tools/people.d.ts +6 -0
- package/dist/http/mcp/tools/people.js +145 -0
- package/dist/http/mcp/tools/people.js.map +1 -0
- package/dist/http/plugins/auth.js +13 -5
- package/dist/http/plugins/auth.js.map +1 -1
- package/dist/http/plugins/error-handler.d.ts +2 -1
- package/dist/http/plugins/error-handler.js +51 -65
- package/dist/http/plugins/error-handler.js.map +1 -1
- package/dist/http/plugins/openapi.js +49 -2
- package/dist/http/plugins/openapi.js.map +1 -1
- package/dist/http/routes/access.d.ts +7 -0
- package/dist/http/routes/access.js +140 -0
- package/dist/http/routes/access.js.map +1 -0
- package/dist/http/routes/activities.js +68 -23
- package/dist/http/routes/activities.js.map +1 -1
- package/dist/http/routes/assets.js +60 -55
- package/dist/http/routes/assets.js.map +1 -1
- package/dist/http/routes/automations.js +44 -24
- package/dist/http/routes/automations.js.map +1 -1
- package/dist/http/routes/bundles.js +29 -18
- package/dist/http/routes/bundles.js.map +1 -1
- package/dist/http/routes/communities.d.ts +7 -0
- package/dist/http/routes/communities.js +522 -0
- package/dist/http/routes/communities.js.map +1 -0
- package/dist/http/routes/community-moderation.d.ts +7 -0
- package/dist/http/routes/community-moderation.js +425 -0
- package/dist/http/routes/community-moderation.js.map +1 -0
- package/dist/http/routes/course-analytics.js +9 -7
- package/dist/http/routes/course-analytics.js.map +1 -1
- package/dist/http/routes/courses.js +30 -15
- package/dist/http/routes/courses.js.map +1 -1
- package/dist/http/routes/dashboard.js +15 -6
- package/dist/http/routes/dashboard.js.map +1 -1
- package/dist/http/routes/discussion.js +34 -26
- package/dist/http/routes/discussion.js.map +1 -1
- package/dist/http/routes/downloads.js +48 -30
- package/dist/http/routes/downloads.js.map +1 -1
- package/dist/http/routes/entitlements.js +16 -7
- package/dist/http/routes/entitlements.js.map +1 -1
- package/dist/http/routes/integrations.js +38 -41
- package/dist/http/routes/integrations.js.map +1 -1
- package/dist/http/routes/member/actor.d.ts +14 -0
- package/dist/http/routes/member/actor.js +11 -0
- package/dist/http/routes/member/actor.js.map +1 -0
- package/dist/http/routes/member/assets.d.ts +7 -0
- package/dist/http/routes/member/assets.js +79 -0
- package/dist/http/routes/member/assets.js.map +1 -0
- package/dist/http/routes/member/chats.d.ts +7 -0
- package/dist/http/routes/member/chats.js +435 -0
- package/dist/http/routes/member/chats.js.map +1 -0
- package/dist/http/routes/member/comments.d.ts +7 -0
- package/dist/http/routes/member/comments.js +187 -0
- package/dist/http/routes/member/comments.js.map +1 -0
- package/dist/http/routes/member/community.d.ts +7 -0
- package/dist/http/routes/member/community.js +312 -0
- package/dist/http/routes/member/community.js.map +1 -0
- package/dist/http/routes/member/courses.d.ts +7 -0
- package/dist/http/routes/member/courses.js +101 -0
- package/dist/http/routes/member/courses.js.map +1 -0
- package/dist/http/routes/member/devices.d.ts +7 -0
- package/dist/http/routes/member/devices.js +98 -0
- package/dist/http/routes/member/devices.js.map +1 -0
- package/dist/http/routes/member/downloads.d.ts +7 -0
- package/dist/http/routes/member/downloads.js +56 -0
- package/dist/http/routes/member/downloads.js.map +1 -0
- package/dist/http/routes/member/files.d.ts +7 -0
- package/dist/http/routes/member/files.js +184 -0
- package/dist/http/routes/member/files.js.map +1 -0
- package/dist/http/routes/member/index.d.ts +7 -0
- package/dist/http/routes/member/index.js +35 -0
- package/dist/http/routes/member/index.js.map +1 -0
- package/dist/http/routes/member/notification-settings.d.ts +7 -0
- package/dist/http/routes/member/notification-settings.js +108 -0
- package/dist/http/routes/member/notification-settings.js.map +1 -0
- package/dist/http/routes/member/notifications.d.ts +7 -0
- package/dist/http/routes/member/notifications.js +125 -0
- package/dist/http/routes/member/notifications.js.map +1 -0
- package/dist/http/routes/member/org.d.ts +7 -0
- package/dist/http/routes/member/org.js +56 -0
- package/dist/http/routes/member/org.js.map +1 -0
- package/dist/http/routes/member/posts.d.ts +7 -0
- package/dist/http/routes/member/posts.js +612 -0
- package/dist/http/routes/member/posts.js.map +1 -0
- package/dist/http/routes/member/profile.d.ts +7 -0
- package/dist/http/routes/member/profile.js +48 -0
- package/dist/http/routes/member/profile.js.map +1 -0
- package/dist/http/routes/member/progress.d.ts +7 -0
- package/dist/http/routes/member/progress.js +60 -0
- package/dist/http/routes/member/progress.js.map +1 -0
- package/dist/http/routes/organizations.js +171 -25
- package/dist/http/routes/organizations.js.map +1 -1
- package/dist/http/routes/students.js +32 -47
- package/dist/http/routes/students.js.map +1 -1
- package/dist/http/routes/webhooks.js +26 -18
- package/dist/http/routes/webhooks.js.map +1 -1
- package/dist/http/routes.js +8 -2
- package/dist/http/routes.js.map +1 -1
- package/dist/http/schemas/access.d.ts +146 -0
- package/dist/http/schemas/access.js +36 -0
- package/dist/http/schemas/access.js.map +1 -0
- package/dist/http/schemas/activities.d.ts +3 -1
- package/dist/http/schemas/activities.js +4 -4
- package/dist/http/schemas/activities.js.map +1 -1
- package/dist/http/schemas/assets.d.ts +79 -80
- package/dist/http/schemas/assets.js +23 -13
- package/dist/http/schemas/assets.js.map +1 -1
- package/dist/http/schemas/automations.d.ts +6 -0
- package/dist/http/schemas/bundles.js +6 -6
- package/dist/http/schemas/bundles.js.map +1 -1
- package/dist/http/schemas/chats.d.ts +409 -0
- package/dist/http/schemas/chats.js +56 -0
- package/dist/http/schemas/chats.js.map +1 -0
- package/dist/http/schemas/community.d.ts +597 -0
- package/dist/http/schemas/community.js +132 -0
- package/dist/http/schemas/community.js.map +1 -0
- package/dist/http/schemas/content.d.ts +4 -2
- package/dist/http/schemas/content.js +11 -8
- package/dist/http/schemas/content.js.map +1 -1
- package/dist/http/schemas/discussion.d.ts +98 -14
- package/dist/http/schemas/discussion.js +25 -12
- package/dist/http/schemas/discussion.js.map +1 -1
- package/dist/http/schemas/downloads.d.ts +11 -5
- package/dist/http/schemas/downloads.js +14 -11
- package/dist/http/schemas/downloads.js.map +1 -1
- package/dist/http/schemas/entitlements.d.ts +6 -6
- package/dist/http/schemas/entitlements.js +6 -6
- package/dist/http/schemas/entitlements.js.map +1 -1
- package/dist/http/schemas/files.d.ts +45 -0
- package/dist/http/schemas/files.js +25 -0
- package/dist/http/schemas/files.js.map +1 -0
- package/dist/http/schemas/index.d.ts +15 -8
- package/dist/http/schemas/index.js +15 -8
- package/dist/http/schemas/integrations.d.ts +4 -4
- package/dist/http/schemas/invites.d.ts +4 -0
- package/dist/http/schemas/invites.js +1 -0
- package/dist/http/schemas/invites.js.map +1 -1
- package/dist/http/schemas/{learn.d.ts → member.d.ts} +31 -18
- package/dist/http/schemas/{learn.js → member.js} +17 -13
- package/dist/http/schemas/member.js.map +1 -0
- package/dist/http/schemas/members.d.ts +35 -2
- package/dist/http/schemas/members.js +17 -3
- package/dist/http/schemas/members.js.map +1 -1
- package/dist/http/schemas/notifications.d.ts +550 -0
- package/dist/http/schemas/notifications.js +164 -0
- package/dist/http/schemas/notifications.js.map +1 -0
- package/dist/http/schemas/posts.d.ts +350 -0
- package/dist/http/schemas/posts.js +47 -0
- package/dist/http/schemas/posts.js.map +1 -0
- package/dist/http/schemas/profile.d.ts +23 -0
- package/dist/http/schemas/profile.js +15 -0
- package/dist/http/schemas/profile.js.map +1 -0
- package/dist/http/schemas/shared.d.ts +32 -1
- package/dist/http/schemas/shared.js +20 -2
- package/dist/http/schemas/shared.js.map +1 -1
- package/dist/http/schemas/students.d.ts +1 -7
- package/dist/http/schemas/students.js +1 -7
- package/dist/http/schemas/students.js.map +1 -1
- package/dist/http/scope.d.ts +3 -1
- package/dist/http/scope.js +26 -4
- package/dist/http/scope.js.map +1 -1
- package/dist/http/server.js +6 -1
- package/dist/http/server.js.map +1 -1
- package/dist/http/web-bridge.d.ts +1 -1
- package/dist/http/web-bridge.js +2 -2
- package/dist/http/web-bridge.js.map +1 -1
- package/dist/http/well-known.d.ts +7 -0
- package/dist/http/well-known.js +22 -0
- package/dist/http/well-known.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/node_modules/.pnpm/@jridgewell_sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.js +78 -0
- package/dist/node_modules/.pnpm/@jridgewell_sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.js.map +1 -0
- package/dist/node_modules/.pnpm/@vitest_expect@2.1.9/node_modules/@vitest/expect/dist/index.js +1267 -0
- package/dist/node_modules/.pnpm/@vitest_expect@2.1.9/node_modules/@vitest/expect/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/@vitest_pretty-format@2.1.9/node_modules/@vitest/pretty-format/dist/index.js +814 -0
- package/dist/node_modules/.pnpm/@vitest_pretty-format@2.1.9/node_modules/@vitest/pretty-format/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/@vitest_runner@2.1.9/node_modules/@vitest/runner/dist/chunk-tasks.js +43 -0
- package/dist/node_modules/.pnpm/@vitest_runner@2.1.9/node_modules/@vitest/runner/dist/chunk-tasks.js.map +1 -0
- package/dist/node_modules/.pnpm/@vitest_runner@2.1.9/node_modules/@vitest/runner/dist/index.js +527 -0
- package/dist/node_modules/.pnpm/@vitest_runner@2.1.9/node_modules/@vitest/runner/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/@vitest_runner@2.1.9/node_modules/@vitest/runner/dist/utils.js +2 -0
- package/dist/node_modules/.pnpm/@vitest_snapshot@2.1.9/node_modules/@vitest/snapshot/dist/index.js +1737 -0
- package/dist/node_modules/.pnpm/@vitest_snapshot@2.1.9/node_modules/@vitest/snapshot/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/@vitest_spy@2.1.9/node_modules/@vitest/spy/dist/index.js +137 -0
- package/dist/node_modules/.pnpm/@vitest_spy@2.1.9/node_modules/@vitest/spy/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/chunk-_commonjsHelpers.js +118 -0
- package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/chunk-_commonjsHelpers.js.map +1 -0
- package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/diff.js +1222 -0
- package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/diff.js.map +1 -0
- package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/error.js +91 -0
- package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/error.js.map +1 -0
- package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/helpers.js +113 -0
- package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/helpers.js.map +1 -0
- package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/index.js +449 -0
- package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/source-map.js +163 -0
- package/dist/node_modules/.pnpm/@vitest_utils@2.1.9/node_modules/@vitest/utils/dist/source-map.js.map +1 -0
- package/dist/node_modules/.pnpm/chai@5.3.3/node_modules/chai/index.js +3187 -0
- package/dist/node_modules/.pnpm/chai@5.3.3/node_modules/chai/index.js.map +1 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/arguments.js +11 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/arguments.js.map +1 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/array.js +16 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/array.js.map +1 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/bigint.js +11 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/bigint.js.map +1 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/class.js +15 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/class.js.map +1 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/date.js +13 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/date.js.map +1 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/error.js +34 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/error.js.map +1 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/function.js +12 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/function.js.map +1 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/helpers.js +122 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/helpers.js.map +1 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/html.js +39 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/html.js.map +1 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/index.js +99 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/index.js.map +1 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/map.js +25 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/map.js.map +1 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/number.js +14 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/number.js.map +1 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/object.js +21 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/object.js.map +1 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/promise.js +6 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/promise.js.map +1 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/regexp.js +12 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/regexp.js.map +1 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/set.js +18 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/set.js.map +1 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/string.js +24 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/string.js.map +1 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/symbol.js +9 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/symbol.js.map +1 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/typedarray.js +30 -0
- package/dist/node_modules/.pnpm/loupe@3.2.1/node_modules/loupe/lib/typedarray.js.map +1 -0
- package/dist/node_modules/.pnpm/magic-string@0.30.21/node_modules/magic-string/dist/magic-string.es.js +939 -0
- package/dist/node_modules/.pnpm/magic-string@0.30.21/node_modules/magic-string/dist/magic-string.es.js.map +1 -0
- package/dist/node_modules/.pnpm/pathe@1.1.2/node_modules/pathe/dist/shared/pathe.ff20891b.js +82 -0
- package/dist/node_modules/.pnpm/pathe@1.1.2/node_modules/pathe/dist/shared/pathe.ff20891b.js.map +1 -0
- package/dist/node_modules/.pnpm/tinyrainbow@1.2.0/node_modules/tinyrainbow/dist/chunk-BVHSVHOK.js +82 -0
- package/dist/node_modules/.pnpm/tinyrainbow@1.2.0/node_modules/tinyrainbow/dist/chunk-BVHSVHOK.js.map +1 -0
- package/dist/node_modules/.pnpm/tinyrainbow@1.2.0/node_modules/tinyrainbow/dist/node.js +8 -0
- package/dist/node_modules/.pnpm/tinyrainbow@1.2.0/node_modules/tinyrainbow/dist/node.js.map +1 -0
- package/dist/node_modules/.pnpm/tinyspy@3.0.2/node_modules/tinyspy/dist/index.js +83 -0
- package/dist/node_modules/.pnpm/tinyspy@3.0.2/node_modules/tinyspy/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/vitest@2.1.9_@types_node@22.20.0_jsdom@25.0.1_lightningcss@1.32.0/node_modules/vitest/dist/chunks/_commonjsHelpers.BFTU3MAI.js +9 -0
- package/dist/node_modules/.pnpm/vitest@2.1.9_@types_node@22.20.0_jsdom@25.0.1_lightningcss@1.32.0/node_modules/vitest/dist/chunks/_commonjsHelpers.BFTU3MAI.js.map +1 -0
- package/dist/node_modules/.pnpm/vitest@2.1.9_@types_node@22.20.0_jsdom@25.0.1_lightningcss@1.32.0/node_modules/vitest/dist/chunks/date.W2xKR2qe.js +51 -0
- package/dist/node_modules/.pnpm/vitest@2.1.9_@types_node@22.20.0_jsdom@25.0.1_lightningcss@1.32.0/node_modules/vitest/dist/chunks/date.W2xKR2qe.js.map +1 -0
- package/dist/node_modules/.pnpm/vitest@2.1.9_@types_node@22.20.0_jsdom@25.0.1_lightningcss@1.32.0/node_modules/vitest/dist/chunks/utils.C8RiOc4B.js +48 -0
- package/dist/node_modules/.pnpm/vitest@2.1.9_@types_node@22.20.0_jsdom@25.0.1_lightningcss@1.32.0/node_modules/vitest/dist/chunks/utils.C8RiOc4B.js.map +1 -0
- package/dist/node_modules/.pnpm/vitest@2.1.9_@types_node@22.20.0_jsdom@25.0.1_lightningcss@1.32.0/node_modules/vitest/dist/chunks/vi.DgezovHB.js +2426 -0
- package/dist/node_modules/.pnpm/vitest@2.1.9_@types_node@22.20.0_jsdom@25.0.1_lightningcss@1.32.0/node_modules/vitest/dist/chunks/vi.DgezovHB.js.map +1 -0
- package/dist/packages/server/package.js +6 -0
- package/dist/packages/server/package.js.map +1 -0
- package/package.json +9 -7
- package/dist/app/notifications.d.ts +0 -7
- package/dist/app/notifications.js +0 -26
- package/dist/app/notifications.js.map +0 -1
- package/dist/http/routes/learn/assets.d.ts +0 -8
- package/dist/http/routes/learn/assets.js +0 -32
- package/dist/http/routes/learn/assets.js.map +0 -1
- package/dist/http/routes/learn/comments.d.ts +0 -7
- package/dist/http/routes/learn/comments.js +0 -175
- package/dist/http/routes/learn/comments.js.map +0 -1
- package/dist/http/routes/learn/courses.d.ts +0 -7
- package/dist/http/routes/learn/courses.js +0 -98
- package/dist/http/routes/learn/courses.js.map +0 -1
- package/dist/http/routes/learn/downloads.d.ts +0 -7
- package/dist/http/routes/learn/downloads.js +0 -76
- package/dist/http/routes/learn/downloads.js.map +0 -1
- package/dist/http/routes/learn/index.d.ts +0 -7
- package/dist/http/routes/learn/index.js +0 -19
- package/dist/http/routes/learn/index.js.map +0 -1
- package/dist/http/routes/learn/org.d.ts +0 -7
- package/dist/http/routes/learn/org.js +0 -50
- package/dist/http/routes/learn/org.js.map +0 -1
- package/dist/http/routes/learn/progress.d.ts +0 -7
- package/dist/http/routes/learn/progress.js +0 -63
- package/dist/http/routes/learn/progress.js.map +0 -1
- package/dist/http/schemas/learn.js.map +0 -1
- package/dist/package.js +0 -6
- package/dist/package.js.map +0 -1
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { CoursesQuery, CreateCourse, PatchCourseSettings, UpdateCourse } from "../../schemas/content.js";
|
|
2
|
+
import { CourseIdPathParam, CreateModule, ModulePathParam, ReorderInput, UpdateModule } from "../../schemas/activities.js";
|
|
3
|
+
import "../../schemas/index.js";
|
|
4
|
+
import { actor, defineTool } from "../tool.js";
|
|
5
|
+
//#region src/http/mcp/tools/courses.ts
|
|
6
|
+
const courseTools = [
|
|
7
|
+
defineTool({
|
|
8
|
+
name: "list_courses",
|
|
9
|
+
title: "List courses",
|
|
10
|
+
description: "Search and page through the courses, each with its status and settings. Filter by status or category.",
|
|
11
|
+
scope: "courses:read",
|
|
12
|
+
kind: "read",
|
|
13
|
+
idempotent: true,
|
|
14
|
+
openWorld: false,
|
|
15
|
+
input: CoursesQuery,
|
|
16
|
+
call: (input, { container, scope }) => container.content.listCourses(scope.orgId, input)
|
|
17
|
+
}),
|
|
18
|
+
defineTool({
|
|
19
|
+
name: "list_modules",
|
|
20
|
+
title: "List modules",
|
|
21
|
+
description: "The modules of a course, in order.",
|
|
22
|
+
scope: "courses:read",
|
|
23
|
+
kind: "read",
|
|
24
|
+
idempotent: true,
|
|
25
|
+
openWorld: false,
|
|
26
|
+
input: CourseIdPathParam,
|
|
27
|
+
call: ({ courseId }, { container, scope }) => container.content.listCourseModules(scope.orgId, courseId)
|
|
28
|
+
}),
|
|
29
|
+
defineTool({
|
|
30
|
+
name: "create_course",
|
|
31
|
+
title: "Create course",
|
|
32
|
+
description: "Create a draft course. Publish it with update_course.",
|
|
33
|
+
scope: "courses:write",
|
|
34
|
+
kind: "write",
|
|
35
|
+
idempotent: false,
|
|
36
|
+
openWorld: false,
|
|
37
|
+
input: CreateCourse,
|
|
38
|
+
call: (input, { container, scope }) => container.content.createCourse(scope.orgId, input)
|
|
39
|
+
}),
|
|
40
|
+
defineTool({
|
|
41
|
+
name: "update_course",
|
|
42
|
+
title: "Update course",
|
|
43
|
+
description: "Change a course title, description, category or cover image, or publish and unpublish it with status. Fields left out stay as they are.",
|
|
44
|
+
scope: "courses:write",
|
|
45
|
+
kind: "write",
|
|
46
|
+
idempotent: true,
|
|
47
|
+
openWorld: false,
|
|
48
|
+
input: UpdateCourse.extend(CourseIdPathParam.shape),
|
|
49
|
+
call: ({ courseId, ...patch }, { container, scope }) => container.content.updateCourse(scope.orgId, courseId, patch)
|
|
50
|
+
}),
|
|
51
|
+
defineTool({
|
|
52
|
+
name: "update_course_settings",
|
|
53
|
+
title: "Update course settings",
|
|
54
|
+
description: "Change course settings such as transcript downloads and comments. Settings left out stay as they are.",
|
|
55
|
+
scope: "courses:write",
|
|
56
|
+
kind: "write",
|
|
57
|
+
idempotent: true,
|
|
58
|
+
openWorld: false,
|
|
59
|
+
input: PatchCourseSettings.extend(CourseIdPathParam.shape),
|
|
60
|
+
call: ({ courseId, ...settings }, { container, scope }) => container.content.patchCourseSettings(scope.orgId, courseId, settings)
|
|
61
|
+
}),
|
|
62
|
+
defineTool({
|
|
63
|
+
name: "create_module",
|
|
64
|
+
title: "Create module",
|
|
65
|
+
description: "Add a module at the end of a course. Returns the course modules in order.",
|
|
66
|
+
scope: "courses:write",
|
|
67
|
+
kind: "write",
|
|
68
|
+
idempotent: false,
|
|
69
|
+
openWorld: false,
|
|
70
|
+
input: CreateModule.extend(CourseIdPathParam.shape),
|
|
71
|
+
call: ({ courseId, title }, { container, scope }) => container.content.createModule(scope.orgId, courseId, title)
|
|
72
|
+
}),
|
|
73
|
+
defineTool({
|
|
74
|
+
name: "rename_module",
|
|
75
|
+
title: "Rename module",
|
|
76
|
+
description: "Rename a module. Returns the course modules in order.",
|
|
77
|
+
scope: "courses:write",
|
|
78
|
+
kind: "write",
|
|
79
|
+
idempotent: true,
|
|
80
|
+
openWorld: false,
|
|
81
|
+
input: UpdateModule.extend(ModulePathParam.shape),
|
|
82
|
+
call: ({ courseId, moduleId, title }, { container, scope }) => container.content.updateModule(scope.orgId, courseId, moduleId, title)
|
|
83
|
+
}),
|
|
84
|
+
defineTool({
|
|
85
|
+
name: "reorder_modules",
|
|
86
|
+
title: "Reorder modules",
|
|
87
|
+
description: "Set the module order of a course. Pass every module id of the course in the new order.",
|
|
88
|
+
scope: "courses:write",
|
|
89
|
+
kind: "write",
|
|
90
|
+
idempotent: true,
|
|
91
|
+
openWorld: false,
|
|
92
|
+
input: ReorderInput.extend(CourseIdPathParam.shape),
|
|
93
|
+
call: ({ courseId, orderedIds }, { container, scope }) => container.content.reorderModules(scope.orgId, courseId, orderedIds)
|
|
94
|
+
}),
|
|
95
|
+
defineTool({
|
|
96
|
+
name: "delete_course",
|
|
97
|
+
title: "Delete course",
|
|
98
|
+
description: "Permanently delete a course with its modules and activities.",
|
|
99
|
+
scope: "courses:delete",
|
|
100
|
+
kind: "destructive",
|
|
101
|
+
idempotent: true,
|
|
102
|
+
openWorld: false,
|
|
103
|
+
input: CourseIdPathParam,
|
|
104
|
+
call: ({ courseId }, { container, scope }) => container.content.deleteCourse(scope.orgId, courseId, actor(scope))
|
|
105
|
+
}),
|
|
106
|
+
defineTool({
|
|
107
|
+
name: "delete_module",
|
|
108
|
+
title: "Delete module",
|
|
109
|
+
description: "Permanently delete a module with its activities. Returns the remaining modules in order.",
|
|
110
|
+
scope: "courses:delete",
|
|
111
|
+
kind: "destructive",
|
|
112
|
+
idempotent: true,
|
|
113
|
+
openWorld: false,
|
|
114
|
+
input: ModulePathParam,
|
|
115
|
+
call: ({ courseId, moduleId }, { container, scope }) => container.content.deleteModule(scope.orgId, courseId, moduleId)
|
|
116
|
+
})
|
|
117
|
+
];
|
|
118
|
+
//#endregion
|
|
119
|
+
export { courseTools };
|
|
120
|
+
|
|
121
|
+
//# sourceMappingURL=courses.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"courses.js","names":[],"sources":["../../../../src/http/mcp/tools/courses.ts"],"sourcesContent":["import {\n CourseIdPathParam,\n CoursesQuery,\n CreateCourse,\n CreateModule,\n ModulePathParam,\n PatchCourseSettings,\n ReorderInput,\n UpdateCourse,\n UpdateModule,\n} from '../../schemas/index.js';\nimport { actor, defineTool, type Tool } from '../tool.js';\n\nexport const courseTools: Tool[] = [\n defineTool({\n name: 'list_courses',\n title: 'List courses',\n description:\n 'Search and page through the courses, each with its status and settings. Filter by status or category.',\n scope: 'courses:read',\n kind: 'read',\n idempotent: true,\n openWorld: false,\n input: CoursesQuery,\n call: (input, { container, scope }) => container.content.listCourses(scope.orgId, input),\n }),\n defineTool({\n name: 'list_modules',\n title: 'List modules',\n description: 'The modules of a course, in order.',\n scope: 'courses:read',\n kind: 'read',\n idempotent: true,\n openWorld: false,\n input: CourseIdPathParam,\n call: ({ courseId }, { container, scope }) =>\n container.content.listCourseModules(scope.orgId, courseId),\n }),\n defineTool({\n name: 'create_course',\n title: 'Create course',\n description: 'Create a draft course. Publish it with update_course.',\n scope: 'courses:write',\n kind: 'write',\n idempotent: false,\n openWorld: false,\n input: CreateCourse,\n call: (input, { container, scope }) => container.content.createCourse(scope.orgId, input),\n }),\n defineTool({\n name: 'update_course',\n title: 'Update course',\n description:\n 'Change a course title, description, category or cover image, or publish and unpublish it with status. Fields left out stay as they are.',\n scope: 'courses:write',\n kind: 'write',\n idempotent: true,\n openWorld: false,\n input: UpdateCourse.extend(CourseIdPathParam.shape),\n call: ({ courseId, ...patch }, { container, scope }) =>\n container.content.updateCourse(scope.orgId, courseId, patch),\n }),\n defineTool({\n name: 'update_course_settings',\n title: 'Update course settings',\n description:\n 'Change course settings such as transcript downloads and comments. Settings left out stay as they are.',\n scope: 'courses:write',\n kind: 'write',\n idempotent: true,\n openWorld: false,\n input: PatchCourseSettings.extend(CourseIdPathParam.shape),\n call: ({ courseId, ...settings }, { container, scope }) =>\n container.content.patchCourseSettings(scope.orgId, courseId, settings),\n }),\n defineTool({\n name: 'create_module',\n title: 'Create module',\n description: 'Add a module at the end of a course. Returns the course modules in order.',\n scope: 'courses:write',\n kind: 'write',\n idempotent: false,\n openWorld: false,\n input: CreateModule.extend(CourseIdPathParam.shape),\n call: ({ courseId, title }, { container, scope }) =>\n container.content.createModule(scope.orgId, courseId, title),\n }),\n defineTool({\n name: 'rename_module',\n title: 'Rename module',\n description: 'Rename a module. Returns the course modules in order.',\n scope: 'courses:write',\n kind: 'write',\n idempotent: true,\n openWorld: false,\n input: UpdateModule.extend(ModulePathParam.shape),\n call: ({ courseId, moduleId, title }, { container, scope }) =>\n container.content.updateModule(scope.orgId, courseId, moduleId, title),\n }),\n defineTool({\n name: 'reorder_modules',\n title: 'Reorder modules',\n description:\n 'Set the module order of a course. Pass every module id of the course in the new order.',\n scope: 'courses:write',\n kind: 'write',\n idempotent: true,\n openWorld: false,\n input: ReorderInput.extend(CourseIdPathParam.shape),\n call: ({ courseId, orderedIds }, { container, scope }) =>\n container.content.reorderModules(scope.orgId, courseId, orderedIds),\n }),\n defineTool({\n name: 'delete_course',\n title: 'Delete course',\n description: 'Permanently delete a course with its modules and activities.',\n scope: 'courses:delete',\n kind: 'destructive',\n idempotent: true,\n openWorld: false,\n input: CourseIdPathParam,\n call: ({ courseId }, { container, scope }) =>\n container.content.deleteCourse(scope.orgId, courseId, actor(scope)),\n }),\n defineTool({\n name: 'delete_module',\n title: 'Delete module',\n description:\n 'Permanently delete a module with its activities. Returns the remaining modules in order.',\n scope: 'courses:delete',\n kind: 'destructive',\n idempotent: true,\n openWorld: false,\n input: ModulePathParam,\n call: ({ courseId, moduleId }, { container, scope }) =>\n container.content.deleteModule(scope.orgId, courseId, moduleId),\n }),\n];\n"],"mappings":";;;;;AAaA,MAAa,cAAsB;CACjC,WAAW;EACT,MAAM;EACN,OAAO;EACP,aACE;EACF,OAAO;EACP,MAAM;EACN,YAAY;EACZ,WAAW;EACX,OAAO;EACP,OAAO,OAAO,EAAE,WAAW,YAAY,UAAU,QAAQ,YAAY,MAAM,OAAO,KAAK;CACzF,CAAC;CACD,WAAW;EACT,MAAM;EACN,OAAO;EACP,aAAa;EACb,OAAO;EACP,MAAM;EACN,YAAY;EACZ,WAAW;EACX,OAAO;EACP,OAAO,EAAE,YAAY,EAAE,WAAW,YAChC,UAAU,QAAQ,kBAAkB,MAAM,OAAO,QAAQ;CAC7D,CAAC;CACD,WAAW;EACT,MAAM;EACN,OAAO;EACP,aAAa;EACb,OAAO;EACP,MAAM;EACN,YAAY;EACZ,WAAW;EACX,OAAO;EACP,OAAO,OAAO,EAAE,WAAW,YAAY,UAAU,QAAQ,aAAa,MAAM,OAAO,KAAK;CAC1F,CAAC;CACD,WAAW;EACT,MAAM;EACN,OAAO;EACP,aACE;EACF,OAAO;EACP,MAAM;EACN,YAAY;EACZ,WAAW;EACX,OAAO,aAAa,OAAO,kBAAkB,KAAK;EAClD,OAAO,EAAE,UAAU,GAAG,SAAS,EAAE,WAAW,YAC1C,UAAU,QAAQ,aAAa,MAAM,OAAO,UAAU,KAAK;CAC/D,CAAC;CACD,WAAW;EACT,MAAM;EACN,OAAO;EACP,aACE;EACF,OAAO;EACP,MAAM;EACN,YAAY;EACZ,WAAW;EACX,OAAO,oBAAoB,OAAO,kBAAkB,KAAK;EACzD,OAAO,EAAE,UAAU,GAAG,YAAY,EAAE,WAAW,YAC7C,UAAU,QAAQ,oBAAoB,MAAM,OAAO,UAAU,QAAQ;CACzE,CAAC;CACD,WAAW;EACT,MAAM;EACN,OAAO;EACP,aAAa;EACb,OAAO;EACP,MAAM;EACN,YAAY;EACZ,WAAW;EACX,OAAO,aAAa,OAAO,kBAAkB,KAAK;EAClD,OAAO,EAAE,UAAU,SAAS,EAAE,WAAW,YACvC,UAAU,QAAQ,aAAa,MAAM,OAAO,UAAU,KAAK;CAC/D,CAAC;CACD,WAAW;EACT,MAAM;EACN,OAAO;EACP,aAAa;EACb,OAAO;EACP,MAAM;EACN,YAAY;EACZ,WAAW;EACX,OAAO,aAAa,OAAO,gBAAgB,KAAK;EAChD,OAAO,EAAE,UAAU,UAAU,SAAS,EAAE,WAAW,YACjD,UAAU,QAAQ,aAAa,MAAM,OAAO,UAAU,UAAU,KAAK;CACzE,CAAC;CACD,WAAW;EACT,MAAM;EACN,OAAO;EACP,aACE;EACF,OAAO;EACP,MAAM;EACN,YAAY;EACZ,WAAW;EACX,OAAO,aAAa,OAAO,kBAAkB,KAAK;EAClD,OAAO,EAAE,UAAU,cAAc,EAAE,WAAW,YAC5C,UAAU,QAAQ,eAAe,MAAM,OAAO,UAAU,UAAU;CACtE,CAAC;CACD,WAAW;EACT,MAAM;EACN,OAAO;EACP,aAAa;EACb,OAAO;EACP,MAAM;EACN,YAAY;EACZ,WAAW;EACX,OAAO;EACP,OAAO,EAAE,YAAY,EAAE,WAAW,YAChC,UAAU,QAAQ,aAAa,MAAM,OAAO,UAAU,MAAM,KAAK,CAAC;CACtE,CAAC;CACD,WAAW;EACT,MAAM;EACN,OAAO;EACP,aACE;EACF,OAAO;EACP,MAAM;EACN,YAAY;EACZ,WAAW;EACX,OAAO;EACP,OAAO,EAAE,UAAU,YAAY,EAAE,WAAW,YAC1C,UAAU,QAAQ,aAAa,MAAM,OAAO,UAAU,QAAQ;CAClE,CAAC;AACH"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { automationTools } from "./automations.js";
|
|
2
|
+
import { catalogTools } from "./catalog.js";
|
|
3
|
+
import { commentTools } from "./comments.js";
|
|
4
|
+
import { communityMemberTools } from "./community-members.js";
|
|
5
|
+
import { communityModerationTools } from "./community-moderation.js";
|
|
6
|
+
import { communityTools } from "./communities.js";
|
|
7
|
+
import { courseTools } from "./courses.js";
|
|
8
|
+
import { peopleTools } from "./people.js";
|
|
9
|
+
//#region src/http/mcp/tools/index.ts
|
|
10
|
+
const TOOLS = [
|
|
11
|
+
...courseTools,
|
|
12
|
+
...catalogTools,
|
|
13
|
+
...peopleTools,
|
|
14
|
+
...automationTools,
|
|
15
|
+
...commentTools,
|
|
16
|
+
...communityTools,
|
|
17
|
+
...communityMemberTools,
|
|
18
|
+
...communityModerationTools
|
|
19
|
+
];
|
|
20
|
+
//#endregion
|
|
21
|
+
export { TOOLS };
|
|
22
|
+
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/http/mcp/tools/index.ts"],"sourcesContent":["import type { Tool } from '../tool.js';\nimport { automationTools } from './automations.js';\nimport { catalogTools } from './catalog.js';\nimport { commentTools } from './comments.js';\nimport { communityMemberTools } from './community-members.js';\nimport { communityModerationTools } from './community-moderation.js';\nimport { communityTools } from './communities.js';\nimport { courseTools } from './courses.js';\nimport { peopleTools } from './people.js';\n\nexport const TOOLS: Tool[] = [\n ...courseTools,\n ...catalogTools,\n ...peopleTools,\n ...automationTools,\n ...commentTools,\n ...communityTools,\n ...communityMemberTools,\n ...communityModerationTools,\n];\n"],"mappings":";;;;;;;;;AAUA,MAAa,QAAgB;CAC3B,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;CACH,GAAG;AACL"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { CourseIdPathParam } from "../../schemas/activities.js";
|
|
2
|
+
import { StudentIdParam, StudentsQuery } from "../../schemas/students.js";
|
|
3
|
+
import { EntitlementIdParam, EntitlementsQuery, GrantEntitlement, SetEntitlementStatus } from "../../schemas/entitlements.js";
|
|
4
|
+
import { CreateInvite, Invite } from "../../schemas/invites.js";
|
|
5
|
+
import { EnrollmentSeriesQuery } from "../../schemas/dashboard.js";
|
|
6
|
+
import "../../schemas/index.js";
|
|
7
|
+
import { actor, defineTool, noInput } from "../tool.js";
|
|
8
|
+
//#region src/http/mcp/tools/people.ts
|
|
9
|
+
const peopleTools = [
|
|
10
|
+
defineTool({
|
|
11
|
+
name: "list_students",
|
|
12
|
+
title: "List students",
|
|
13
|
+
description: "Search and page through the students with their access count, average progress, status and last activity.",
|
|
14
|
+
scope: "students:read",
|
|
15
|
+
kind: "read",
|
|
16
|
+
idempotent: true,
|
|
17
|
+
openWorld: false,
|
|
18
|
+
input: StudentsQuery,
|
|
19
|
+
call: (input, { container, scope }) => container.reporting.admin.listStudents(scope.orgId, input)
|
|
20
|
+
}),
|
|
21
|
+
defineTool({
|
|
22
|
+
name: "invite_student",
|
|
23
|
+
title: "Invite student",
|
|
24
|
+
description: "Invite someone by email as a student. They exist as an invited student at once. sendEmail false skips the email.",
|
|
25
|
+
scope: "students:invite",
|
|
26
|
+
kind: "write",
|
|
27
|
+
idempotent: false,
|
|
28
|
+
openWorld: true,
|
|
29
|
+
input: CreateInvite.omit({ role: true }),
|
|
30
|
+
output: Invite,
|
|
31
|
+
call: (input, { container, scope }) => container.organizations.createInvite(actor(scope), {
|
|
32
|
+
orgId: scope.orgId,
|
|
33
|
+
inviterUserId: scope.userId,
|
|
34
|
+
role: "student",
|
|
35
|
+
...input
|
|
36
|
+
})
|
|
37
|
+
}),
|
|
38
|
+
defineTool({
|
|
39
|
+
name: "resend_student_invite",
|
|
40
|
+
title: "Resend student invite",
|
|
41
|
+
description: "Send a pending student's invite email again.",
|
|
42
|
+
scope: "students:invite",
|
|
43
|
+
kind: "write",
|
|
44
|
+
idempotent: false,
|
|
45
|
+
openWorld: true,
|
|
46
|
+
input: StudentIdParam,
|
|
47
|
+
call: ({ id }, { container, scope }) => container.organizations.resendStudentInvite(actor(scope), {
|
|
48
|
+
orgId: scope.orgId,
|
|
49
|
+
orgUserId: id,
|
|
50
|
+
inviterUserId: scope.userId
|
|
51
|
+
})
|
|
52
|
+
}),
|
|
53
|
+
defineTool({
|
|
54
|
+
name: "list_access",
|
|
55
|
+
title: "List access",
|
|
56
|
+
description: "Who has access to what. Filter by student (orgUserId), content, type or status.",
|
|
57
|
+
scope: "access:read",
|
|
58
|
+
kind: "read",
|
|
59
|
+
idempotent: true,
|
|
60
|
+
openWorld: false,
|
|
61
|
+
input: EntitlementsQuery,
|
|
62
|
+
call: (input, { container, scope }) => container.entitlements.list(scope.orgId, input)
|
|
63
|
+
}),
|
|
64
|
+
defineTool({
|
|
65
|
+
name: "grant_access",
|
|
66
|
+
title: "Grant access",
|
|
67
|
+
description: "Give a student access to one course, download or community (contentId) or to a bundle (bundleId), never both. expiresAt is a date-time, or null for no expiry.",
|
|
68
|
+
scope: "access:write",
|
|
69
|
+
kind: "write",
|
|
70
|
+
idempotent: false,
|
|
71
|
+
openWorld: false,
|
|
72
|
+
input: GrantEntitlement,
|
|
73
|
+
call: (input, { container, scope }) => container.entitlements.grant(scope.orgId, input)
|
|
74
|
+
}),
|
|
75
|
+
defineTool({
|
|
76
|
+
name: "set_access_status",
|
|
77
|
+
title: "Revoke or reinstate access",
|
|
78
|
+
description: "Revoke an access grant, or reinstate a revoked one.",
|
|
79
|
+
scope: "access:write",
|
|
80
|
+
kind: "destructive",
|
|
81
|
+
idempotent: true,
|
|
82
|
+
openWorld: false,
|
|
83
|
+
input: SetEntitlementStatus.extend(EntitlementIdParam.shape),
|
|
84
|
+
call: ({ id, status }, { container, scope }) => container.entitlements.setStatus(scope.orgId, id, status)
|
|
85
|
+
}),
|
|
86
|
+
defineTool({
|
|
87
|
+
name: "get_dashboard",
|
|
88
|
+
title: "Get dashboard",
|
|
89
|
+
description: "Published and draft course counts, active students, and access grants expiring soon.",
|
|
90
|
+
scope: "analytics:read",
|
|
91
|
+
kind: "read",
|
|
92
|
+
idempotent: true,
|
|
93
|
+
openWorld: false,
|
|
94
|
+
input: noInput,
|
|
95
|
+
call: (_input, { container, scope }) => container.reporting.admin.overview(scope.orgId)
|
|
96
|
+
}),
|
|
97
|
+
defineTool({
|
|
98
|
+
name: "get_enrollment_trend",
|
|
99
|
+
title: "Get enrollment trend",
|
|
100
|
+
description: "Daily enrollments across the organization for the last days (default 30, at most 365).",
|
|
101
|
+
scope: "analytics:read",
|
|
102
|
+
kind: "read",
|
|
103
|
+
idempotent: true,
|
|
104
|
+
openWorld: false,
|
|
105
|
+
input: EnrollmentSeriesQuery,
|
|
106
|
+
call: ({ days }, { container, scope }) => container.reporting.admin.enrollments(scope.orgId, days)
|
|
107
|
+
}),
|
|
108
|
+
defineTool({
|
|
109
|
+
name: "get_course_analytics",
|
|
110
|
+
title: "Get course analytics",
|
|
111
|
+
description: "Enrolled, started and completed counts, average progress and per-activity engagement for one course.",
|
|
112
|
+
scope: "analytics:read",
|
|
113
|
+
kind: "read",
|
|
114
|
+
idempotent: true,
|
|
115
|
+
openWorld: false,
|
|
116
|
+
input: CourseIdPathParam,
|
|
117
|
+
call: ({ courseId }, { container, scope }) => container.reporting.admin.courseAnalytics(scope.orgId, courseId)
|
|
118
|
+
}),
|
|
119
|
+
defineTool({
|
|
120
|
+
name: "get_course_enrollment_trend",
|
|
121
|
+
title: "Get course enrollment trend",
|
|
122
|
+
description: "Daily enrollments in one course for the last days (default 30, at most 365).",
|
|
123
|
+
scope: "analytics:read",
|
|
124
|
+
kind: "read",
|
|
125
|
+
idempotent: true,
|
|
126
|
+
openWorld: false,
|
|
127
|
+
input: EnrollmentSeriesQuery.extend(CourseIdPathParam.shape),
|
|
128
|
+
call: ({ courseId, days }, { container, scope }) => container.reporting.admin.courseEnrollments(scope.orgId, courseId, days)
|
|
129
|
+
}),
|
|
130
|
+
defineTool({
|
|
131
|
+
name: "get_student_analytics",
|
|
132
|
+
title: "Get student analytics",
|
|
133
|
+
description: "One student's enrolled, started and completed counts, average progress and progress in each course.",
|
|
134
|
+
scope: "analytics:read",
|
|
135
|
+
kind: "read",
|
|
136
|
+
idempotent: true,
|
|
137
|
+
openWorld: false,
|
|
138
|
+
input: StudentIdParam,
|
|
139
|
+
call: ({ id }, { container, scope }) => container.reporting.admin.studentAnalytics(scope.orgId, id)
|
|
140
|
+
})
|
|
141
|
+
];
|
|
142
|
+
//#endregion
|
|
143
|
+
export { peopleTools };
|
|
144
|
+
|
|
145
|
+
//# sourceMappingURL=people.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"people.js","names":[],"sources":["../../../../src/http/mcp/tools/people.ts"],"sourcesContent":["import {\n CourseIdPathParam,\n CreateInvite,\n EnrollmentSeriesQuery,\n EntitlementIdParam,\n EntitlementsQuery,\n GrantEntitlement,\n Invite,\n SetEntitlementStatus,\n StudentIdParam,\n StudentsQuery,\n} from '../../schemas/index.js';\nimport { actor, defineTool, noInput, type Tool } from '../tool.js';\n\nexport const peopleTools: Tool[] = [\n defineTool({\n name: 'list_students',\n title: 'List students',\n description:\n 'Search and page through the students with their access count, average progress, status and last activity.',\n scope: 'students:read',\n kind: 'read',\n idempotent: true,\n openWorld: false,\n input: StudentsQuery,\n call: (input, { container, scope }) =>\n container.reporting.admin.listStudents(scope.orgId, input),\n }),\n defineTool({\n name: 'invite_student',\n title: 'Invite student',\n description:\n 'Invite someone by email as a student. They exist as an invited student at once. sendEmail false skips the email.',\n scope: 'students:invite',\n kind: 'write',\n idempotent: false,\n openWorld: true,\n input: CreateInvite.omit({ role: true }),\n output: Invite,\n call: (input, { container, scope }) =>\n container.organizations.createInvite(actor(scope), {\n orgId: scope.orgId,\n inviterUserId: scope.userId,\n role: 'student',\n ...input,\n }),\n }),\n defineTool({\n name: 'resend_student_invite',\n title: 'Resend student invite',\n description: \"Send a pending student's invite email again.\",\n scope: 'students:invite',\n kind: 'write',\n idempotent: false,\n openWorld: true,\n input: StudentIdParam,\n call: ({ id }, { container, scope }) =>\n container.organizations.resendStudentInvite(actor(scope), {\n orgId: scope.orgId,\n orgUserId: id,\n inviterUserId: scope.userId,\n }),\n }),\n defineTool({\n name: 'list_access',\n title: 'List access',\n description: 'Who has access to what. Filter by student (orgUserId), content, type or status.',\n scope: 'access:read',\n kind: 'read',\n idempotent: true,\n openWorld: false,\n input: EntitlementsQuery,\n call: (input, { container, scope }) => container.entitlements.list(scope.orgId, input),\n }),\n defineTool({\n name: 'grant_access',\n title: 'Grant access',\n description:\n 'Give a student access to one course, download or community (contentId) or to a bundle (bundleId), never both. expiresAt is a date-time, or null for no expiry.',\n scope: 'access:write',\n kind: 'write',\n idempotent: false,\n openWorld: false,\n input: GrantEntitlement,\n call: (input, { container, scope }) => container.entitlements.grant(scope.orgId, input),\n }),\n defineTool({\n name: 'set_access_status',\n title: 'Revoke or reinstate access',\n description: 'Revoke an access grant, or reinstate a revoked one.',\n scope: 'access:write',\n kind: 'destructive',\n idempotent: true,\n openWorld: false,\n input: SetEntitlementStatus.extend(EntitlementIdParam.shape),\n call: ({ id, status }, { container, scope }) =>\n container.entitlements.setStatus(scope.orgId, id, status),\n }),\n defineTool({\n name: 'get_dashboard',\n title: 'Get dashboard',\n description:\n 'Published and draft course counts, active students, and access grants expiring soon.',\n scope: 'analytics:read',\n kind: 'read',\n idempotent: true,\n openWorld: false,\n input: noInput,\n call: (_input, { container, scope }) => container.reporting.admin.overview(scope.orgId),\n }),\n defineTool({\n name: 'get_enrollment_trend',\n title: 'Get enrollment trend',\n description:\n 'Daily enrollments across the organization for the last days (default 30, at most 365).',\n scope: 'analytics:read',\n kind: 'read',\n idempotent: true,\n openWorld: false,\n input: EnrollmentSeriesQuery,\n call: ({ days }, { container, scope }) =>\n container.reporting.admin.enrollments(scope.orgId, days),\n }),\n defineTool({\n name: 'get_course_analytics',\n title: 'Get course analytics',\n description:\n 'Enrolled, started and completed counts, average progress and per-activity engagement for one course.',\n scope: 'analytics:read',\n kind: 'read',\n idempotent: true,\n openWorld: false,\n input: CourseIdPathParam,\n call: ({ courseId }, { container, scope }) =>\n container.reporting.admin.courseAnalytics(scope.orgId, courseId),\n }),\n defineTool({\n name: 'get_course_enrollment_trend',\n title: 'Get course enrollment trend',\n description: 'Daily enrollments in one course for the last days (default 30, at most 365).',\n scope: 'analytics:read',\n kind: 'read',\n idempotent: true,\n openWorld: false,\n input: EnrollmentSeriesQuery.extend(CourseIdPathParam.shape),\n call: ({ courseId, days }, { container, scope }) =>\n container.reporting.admin.courseEnrollments(scope.orgId, courseId, days),\n }),\n defineTool({\n name: 'get_student_analytics',\n title: 'Get student analytics',\n description:\n \"One student's enrolled, started and completed counts, average progress and progress in each course.\",\n scope: 'analytics:read',\n kind: 'read',\n idempotent: true,\n openWorld: false,\n input: StudentIdParam,\n call: ({ id }, { container, scope }) =>\n container.reporting.admin.studentAnalytics(scope.orgId, id),\n }),\n];\n"],"mappings":";;;;;;;;AAcA,MAAa,cAAsB;CACjC,WAAW;EACT,MAAM;EACN,OAAO;EACP,aACE;EACF,OAAO;EACP,MAAM;EACN,YAAY;EACZ,WAAW;EACX,OAAO;EACP,OAAO,OAAO,EAAE,WAAW,YACzB,UAAU,UAAU,MAAM,aAAa,MAAM,OAAO,KAAK;CAC7D,CAAC;CACD,WAAW;EACT,MAAM;EACN,OAAO;EACP,aACE;EACF,OAAO;EACP,MAAM;EACN,YAAY;EACZ,WAAW;EACX,OAAO,aAAa,KAAK,EAAE,MAAM,KAAK,CAAC;EACvC,QAAQ;EACR,OAAO,OAAO,EAAE,WAAW,YACzB,UAAU,cAAc,aAAa,MAAM,KAAK,GAAG;GACjD,OAAO,MAAM;GACb,eAAe,MAAM;GACrB,MAAM;GACN,GAAG;EACL,CAAC;CACL,CAAC;CACD,WAAW;EACT,MAAM;EACN,OAAO;EACP,aAAa;EACb,OAAO;EACP,MAAM;EACN,YAAY;EACZ,WAAW;EACX,OAAO;EACP,OAAO,EAAE,MAAM,EAAE,WAAW,YAC1B,UAAU,cAAc,oBAAoB,MAAM,KAAK,GAAG;GACxD,OAAO,MAAM;GACb,WAAW;GACX,eAAe,MAAM;EACvB,CAAC;CACL,CAAC;CACD,WAAW;EACT,MAAM;EACN,OAAO;EACP,aAAa;EACb,OAAO;EACP,MAAM;EACN,YAAY;EACZ,WAAW;EACX,OAAO;EACP,OAAO,OAAO,EAAE,WAAW,YAAY,UAAU,aAAa,KAAK,MAAM,OAAO,KAAK;CACvF,CAAC;CACD,WAAW;EACT,MAAM;EACN,OAAO;EACP,aACE;EACF,OAAO;EACP,MAAM;EACN,YAAY;EACZ,WAAW;EACX,OAAO;EACP,OAAO,OAAO,EAAE,WAAW,YAAY,UAAU,aAAa,MAAM,MAAM,OAAO,KAAK;CACxF,CAAC;CACD,WAAW;EACT,MAAM;EACN,OAAO;EACP,aAAa;EACb,OAAO;EACP,MAAM;EACN,YAAY;EACZ,WAAW;EACX,OAAO,qBAAqB,OAAO,mBAAmB,KAAK;EAC3D,OAAO,EAAE,IAAI,UAAU,EAAE,WAAW,YAClC,UAAU,aAAa,UAAU,MAAM,OAAO,IAAI,MAAM;CAC5D,CAAC;CACD,WAAW;EACT,MAAM;EACN,OAAO;EACP,aACE;EACF,OAAO;EACP,MAAM;EACN,YAAY;EACZ,WAAW;EACX,OAAO;EACP,OAAO,QAAQ,EAAE,WAAW,YAAY,UAAU,UAAU,MAAM,SAAS,MAAM,KAAK;CACxF,CAAC;CACD,WAAW;EACT,MAAM;EACN,OAAO;EACP,aACE;EACF,OAAO;EACP,MAAM;EACN,YAAY;EACZ,WAAW;EACX,OAAO;EACP,OAAO,EAAE,QAAQ,EAAE,WAAW,YAC5B,UAAU,UAAU,MAAM,YAAY,MAAM,OAAO,IAAI;CAC3D,CAAC;CACD,WAAW;EACT,MAAM;EACN,OAAO;EACP,aACE;EACF,OAAO;EACP,MAAM;EACN,YAAY;EACZ,WAAW;EACX,OAAO;EACP,OAAO,EAAE,YAAY,EAAE,WAAW,YAChC,UAAU,UAAU,MAAM,gBAAgB,MAAM,OAAO,QAAQ;CACnE,CAAC;CACD,WAAW;EACT,MAAM;EACN,OAAO;EACP,aAAa;EACb,OAAO;EACP,MAAM;EACN,YAAY;EACZ,WAAW;EACX,OAAO,sBAAsB,OAAO,kBAAkB,KAAK;EAC3D,OAAO,EAAE,UAAU,QAAQ,EAAE,WAAW,YACtC,UAAU,UAAU,MAAM,kBAAkB,MAAM,OAAO,UAAU,IAAI;CAC3E,CAAC;CACD,WAAW;EACT,MAAM;EACN,OAAO;EACP,aACE;EACF,OAAO;EACP,MAAM;EACN,YAAY;EACZ,WAAW;EACX,OAAO;EACP,OAAO,EAAE,MAAM,EAAE,WAAW,YAC1B,UAAU,UAAU,MAAM,iBAAiB,MAAM,OAAO,EAAE;CAC9D,CAAC;AACH"}
|
|
@@ -2,18 +2,22 @@ import { bridgeWebResponse, toWebRequest } from "../web-bridge.js";
|
|
|
2
2
|
//#region src/http/plugins/auth.ts
|
|
3
3
|
/** The request carries no session. The central error handler maps this to 401. */
|
|
4
4
|
var UnauthorizedError = class extends Error {
|
|
5
|
-
constructor(message = "
|
|
5
|
+
constructor(message = "Sign in to continue") {
|
|
6
6
|
super(message);
|
|
7
7
|
this.name = "UnauthorizedError";
|
|
8
8
|
}
|
|
9
9
|
};
|
|
10
10
|
function registerAuth(app, appServer) {
|
|
11
11
|
const { auth } = appServer;
|
|
12
|
+
const origin = new URL(appServer.mcp.issuer).origin;
|
|
13
|
+
app.addContentTypeParser("application/x-www-form-urlencoded", { parseAs: "string" }, (_request, body, done) => {
|
|
14
|
+
done(null, body);
|
|
15
|
+
});
|
|
12
16
|
app.route({
|
|
13
17
|
method: ["GET", "POST"],
|
|
14
18
|
url: "/api/auth/*",
|
|
15
19
|
async handler(request, reply) {
|
|
16
|
-
await bridgeWebResponse(await auth.handler(toWebRequest(request)), reply);
|
|
20
|
+
await bridgeWebResponse(await auth.handler(toWebRequest(request, origin)), reply);
|
|
17
21
|
}
|
|
18
22
|
});
|
|
19
23
|
app.decorate("requireSession", async (request) => {
|
|
@@ -25,19 +29,23 @@ function registerAuth(app, appServer) {
|
|
|
25
29
|
if (authOrgId) {
|
|
26
30
|
request.authOrgId = authOrgId;
|
|
27
31
|
const org = await appServer.organizations.getByExternalId(authOrgId);
|
|
28
|
-
if (org)
|
|
32
|
+
if (org) {
|
|
33
|
+
request.orgId = org.id;
|
|
34
|
+
appServer.requestContext.set({ orgId: org.id });
|
|
35
|
+
}
|
|
29
36
|
}
|
|
30
37
|
});
|
|
31
38
|
app.decorate("requireOrgSession", async (request) => {
|
|
32
39
|
const session = await appServer.auth.verify(request.headers);
|
|
33
40
|
if (!session) throw new UnauthorizedError();
|
|
34
41
|
const authOrgId = session.session.activeOrganizationId;
|
|
35
|
-
if (!authOrgId) throw new UnauthorizedError();
|
|
42
|
+
if (!authOrgId) throw new UnauthorizedError("Choose an organization to continue");
|
|
36
43
|
const org = await appServer.organizations.getByExternalId(authOrgId);
|
|
37
|
-
if (!org) throw new UnauthorizedError("session organization
|
|
44
|
+
if (!org) throw new UnauthorizedError("Your session points to an organization that no longer exists");
|
|
38
45
|
request.authUser = session.user;
|
|
39
46
|
request.userId = session.user.id;
|
|
40
47
|
request.orgId = org.id;
|
|
48
|
+
appServer.requestContext.set({ orgId: org.id });
|
|
41
49
|
request.authOrgId = authOrgId;
|
|
42
50
|
});
|
|
43
51
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","names":[],"sources":["../../../src/http/plugins/auth.ts"],"sourcesContent":["// Everything better-auth touches on the HTTP surface:\n// - the /api/auth/* catch-all bridged to better-auth's Web handler\n// - the `requireSession` / `requireOrgSession` decorators routes guard with\nimport type { FastifyInstance, FastifyRequest } from 'fastify';\nimport type { Container } from '../../app/container.js';\nimport { bridgeWebResponse, toWebRequest } from '../web-bridge.js';\n\n/** The request carries no session. The central error handler maps this to 401. */\nexport class UnauthorizedError extends Error {\n constructor(message = '
|
|
1
|
+
{"version":3,"file":"auth.js","names":[],"sources":["../../../src/http/plugins/auth.ts"],"sourcesContent":["// Everything better-auth touches on the HTTP surface:\n// - the /api/auth/* catch-all bridged to better-auth's Web handler\n// - the `requireSession` / `requireOrgSession` decorators routes guard with\nimport type { FastifyInstance, FastifyRequest } from 'fastify';\nimport type { Container } from '../../app/container.js';\nimport { bridgeWebResponse, toWebRequest } from '../web-bridge.js';\n\n/** The request carries no session. The central error handler maps this to 401. */\nexport class UnauthorizedError extends Error {\n constructor(message = 'Sign in to continue') {\n super(message);\n this.name = 'UnauthorizedError';\n }\n}\n\nexport function registerAuth(app: FastifyInstance, appServer: Container): void {\n const { auth } = appServer;\n const origin = new URL(appServer.mcp.issuer).origin;\n\n app.addContentTypeParser(\n 'application/x-www-form-urlencoded',\n { parseAs: 'string' },\n (_request, body, done) => {\n done(null, body);\n },\n );\n\n // Mount better-auth: a catch-all that bridges Fastify <-> Web Request/Response.\n app.route({\n method: ['GET', 'POST'],\n url: '/api/auth/*',\n async handler(request, reply) {\n await bridgeWebResponse(await auth.handler(toWebRequest(request, origin)), reply);\n },\n });\n\n // Session only, no active org required. For the routes a caller reaches\n // *before* they have an org: creating their first organization, and accepting\n // an invitation (which is what stamps the active org onto the session).\n app.decorate('requireSession', async (request: FastifyRequest) => {\n const session = await appServer.auth.verify(request.headers);\n if (!session) {\n throw new UnauthorizedError();\n }\n request.authUser = session.user;\n request.userId = session.user.id;\n\n const authOrgId = session.session.activeOrganizationId;\n if (authOrgId) {\n request.authOrgId = authOrgId;\n const org = await appServer.organizations.getByExternalId(authOrgId);\n if (org) {\n request.orgId = org.id;\n appServer.requestContext.set({ orgId: org.id });\n }\n }\n });\n\n // Requires a valid session with an active org set — every org-scoped route.\n app.decorate('requireOrgSession', async (request: FastifyRequest) => {\n const session = await appServer.auth.verify(request.headers);\n if (!session) {\n throw new UnauthorizedError();\n }\n const authOrgId = session.session.activeOrganizationId;\n if (!authOrgId) {\n throw new UnauthorizedError('Choose an organization to continue');\n }\n\n const org = await appServer.organizations.getByExternalId(authOrgId);\n if (!org) {\n throw new UnauthorizedError('Your session points to an organization that no longer exists');\n }\n request.authUser = session.user;\n request.userId = session.user.id;\n request.orgId = org.id;\n appServer.requestContext.set({ orgId: org.id });\n // resolveScope requires the auth-provider id too — routes that write back\n // through better-auth key on it.\n request.authOrgId = authOrgId;\n });\n}\n"],"mappings":";;;AAQA,IAAa,oBAAb,cAAuC,MAAM;CAC3C,YAAY,UAAU,uBAAuB;EAC3C,MAAM,OAAO;EACb,KAAK,OAAO;CACd;AACF;AAEA,SAAgB,aAAa,KAAsB,WAA4B;CAC7E,MAAM,EAAE,SAAS;CACjB,MAAM,SAAS,IAAI,IAAI,UAAU,IAAI,MAAM,CAAC,CAAC;CAE7C,IAAI,qBACF,qCACA,EAAE,SAAS,SAAS,IACnB,UAAU,MAAM,SAAS;EACxB,KAAK,MAAM,IAAI;CACjB,CACF;CAGA,IAAI,MAAM;EACR,QAAQ,CAAC,OAAO,MAAM;EACtB,KAAK;EACL,MAAM,QAAQ,SAAS,OAAO;GAC5B,MAAM,kBAAkB,MAAM,KAAK,QAAQ,aAAa,SAAS,MAAM,CAAC,GAAG,KAAK;EAClF;CACF,CAAC;CAKD,IAAI,SAAS,kBAAkB,OAAO,YAA4B;EAChE,MAAM,UAAU,MAAM,UAAU,KAAK,OAAO,QAAQ,OAAO;EAC3D,IAAI,CAAC,SACH,MAAM,IAAI,kBAAkB;EAE9B,QAAQ,WAAW,QAAQ;EAC3B,QAAQ,SAAS,QAAQ,KAAK;EAE9B,MAAM,YAAY,QAAQ,QAAQ;EAClC,IAAI,WAAW;GACb,QAAQ,YAAY;GACpB,MAAM,MAAM,MAAM,UAAU,cAAc,gBAAgB,SAAS;GACnE,IAAI,KAAK;IACP,QAAQ,QAAQ,IAAI;IACpB,UAAU,eAAe,IAAI,EAAE,OAAO,IAAI,GAAG,CAAC;GAChD;EACF;CACF,CAAC;CAGD,IAAI,SAAS,qBAAqB,OAAO,YAA4B;EACnE,MAAM,UAAU,MAAM,UAAU,KAAK,OAAO,QAAQ,OAAO;EAC3D,IAAI,CAAC,SACH,MAAM,IAAI,kBAAkB;EAE9B,MAAM,YAAY,QAAQ,QAAQ;EAClC,IAAI,CAAC,WACH,MAAM,IAAI,kBAAkB,oCAAoC;EAGlE,MAAM,MAAM,MAAM,UAAU,cAAc,gBAAgB,SAAS;EACnE,IAAI,CAAC,KACH,MAAM,IAAI,kBAAkB,8DAA8D;EAE5F,QAAQ,WAAW,QAAQ;EAC3B,QAAQ,SAAS,QAAQ,KAAK;EAC9B,QAAQ,QAAQ,IAAI;EACpB,UAAU,eAAe,IAAI,EAAE,OAAO,IAAI,GAAG,CAAC;EAG9C,QAAQ,YAAY;CACtB,CAAC;AACH"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { FastifyReply, FastifyRequest } from "fastify";
|
|
2
2
|
//#region src/http/plugins/error-handler.d.ts
|
|
3
3
|
declare function errorHandler(error: unknown, request: FastifyRequest, reply: FastifyReply): FastifyReply<import("fastify").RouteGenericInterface, import("fastify").RawServerDefault, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, unknown, import("fastify").FastifySchema, import("fastify").FastifyTypeProviderDefault, unknown>;
|
|
4
|
+
declare function notFoundHandler(request: FastifyRequest, reply: FastifyReply): FastifyReply<import("fastify").RouteGenericInterface, import("fastify").RawServerDefault, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, unknown, import("fastify").FastifySchema, import("fastify").FastifyTypeProviderDefault, unknown>;
|
|
4
5
|
//#endregion
|
|
5
|
-
export { errorHandler };
|
|
6
|
+
export { errorHandler, notFoundHandler };
|
|
6
7
|
//# sourceMappingURL=error-handler.d.ts.map
|
|
@@ -1,75 +1,61 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { ActionInvocationError, AlreadyConnectedError, InvalidConfigError, UnknownIntegrationError } from "@headless-lms/core/integrations";
|
|
5
|
-
import { AutomationKindMismatchError, InvalidTriggerError, ReservedActionError } from "@headless-lms/core/automations";
|
|
6
|
-
import { ConflictError, ForbiddenError, NotFoundError } from "@headless-lms/core/shared/errors";
|
|
1
|
+
import { classifyError } from "../errors.js";
|
|
2
|
+
import { ActionInvocationError } from "@headless-lms/core/integrations";
|
|
3
|
+
import { isResponseSerializationError } from "fastify-type-provider-zod";
|
|
7
4
|
//#region src/http/plugins/error-handler.ts
|
|
5
|
+
function routeOf(request) {
|
|
6
|
+
return `${request.method} ${request.routeOptions.url ?? "unmatched route"}`;
|
|
7
|
+
}
|
|
8
8
|
function errorHandler(error, request, reply) {
|
|
9
|
-
if (error instanceof
|
|
10
|
-
error
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if (
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
if (error
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
error: "invalid_trigger",
|
|
43
|
-
message: error.message
|
|
44
|
-
});
|
|
45
|
-
if (error instanceof ReservedActionError) return reply.status(400).send({
|
|
46
|
-
error: "reserved_action",
|
|
47
|
-
message: error.message
|
|
48
|
-
});
|
|
49
|
-
if (error instanceof AutomationKindMismatchError) return reply.status(409).send({
|
|
50
|
-
error: "kind_mismatch",
|
|
51
|
-
message: error.message
|
|
52
|
-
});
|
|
53
|
-
if (error instanceof NoActiveOrgError) return reply.status(403).send({
|
|
54
|
-
error: "forbidden",
|
|
55
|
-
message: error.message
|
|
56
|
-
});
|
|
57
|
-
if (error instanceof UnauthorizedError) return reply.status(401).send({
|
|
58
|
-
error: "unauthorized",
|
|
59
|
-
message: error.message
|
|
60
|
-
});
|
|
61
|
-
const err = error;
|
|
62
|
-
if (typeof err.statusCode === "number" && err.statusCode >= 400 && err.statusCode < 500) return reply.status(err.statusCode).send({
|
|
63
|
-
error: err.code ?? "bad_request",
|
|
64
|
-
message: err.message ?? "Bad request"
|
|
65
|
-
});
|
|
66
|
-
request.log.error({ err: error }, `unhandled error in ${request.method} ${request.url}`);
|
|
9
|
+
if (error instanceof ActionInvocationError) {
|
|
10
|
+
request.log.error({
|
|
11
|
+
err: error,
|
|
12
|
+
integrationId: error.integrationId,
|
|
13
|
+
actionId: error.actionId
|
|
14
|
+
}, `integration action failed in ${routeOf(request)}`);
|
|
15
|
+
return reply.status(502).send({
|
|
16
|
+
error: "action_failed",
|
|
17
|
+
message: "The integration did not respond as expected"
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
const refusal = classifyError(error);
|
|
21
|
+
if (refusal) {
|
|
22
|
+
request.log.info({
|
|
23
|
+
status: refusal.status,
|
|
24
|
+
error: refusal.error,
|
|
25
|
+
message: refusal.message,
|
|
26
|
+
...refusal.issues && { issues: refusal.issues },
|
|
27
|
+
...refusal.details && { details: refusal.details },
|
|
28
|
+
...refusal.error === "bad_request" && { cause: error.message }
|
|
29
|
+
}, `${routeOf(request)} refused`);
|
|
30
|
+
return reply.status(refusal.status).send({
|
|
31
|
+
error: refusal.error,
|
|
32
|
+
message: refusal.message,
|
|
33
|
+
...refusal.issues && { issues: refusal.issues },
|
|
34
|
+
...refusal.details && { details: refusal.details }
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
if (isResponseSerializationError(error)) request.log.error({
|
|
38
|
+
err: error,
|
|
39
|
+
issues: error.cause.issues
|
|
40
|
+
}, `response of ${routeOf(request)} does not match its schema`);
|
|
41
|
+
else request.log.error({ err: error }, `unhandled error in ${routeOf(request)}`);
|
|
67
42
|
return reply.status(500).send({
|
|
68
43
|
error: "internal_error",
|
|
44
|
+
message: "Something went wrong on our side. Quote the request id when reporting it.",
|
|
69
45
|
requestId: request.id
|
|
70
46
|
});
|
|
71
47
|
}
|
|
48
|
+
function notFoundHandler(request, reply) {
|
|
49
|
+
request.log.info({
|
|
50
|
+
status: 404,
|
|
51
|
+
error: "not_found"
|
|
52
|
+
}, `${request.method} unmatched route refused`);
|
|
53
|
+
return reply.status(404).send({
|
|
54
|
+
error: "not_found",
|
|
55
|
+
message: `No route for ${request.method} ${request.url}`
|
|
56
|
+
});
|
|
57
|
+
}
|
|
72
58
|
//#endregion
|
|
73
|
-
export { errorHandler };
|
|
59
|
+
export { errorHandler, notFoundHandler };
|
|
74
60
|
|
|
75
61
|
//# sourceMappingURL=error-handler.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-handler.js","names":[],"sources":["../../../src/http/plugins/error-handler.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"error-handler.js","names":[],"sources":["../../../src/http/plugins/error-handler.ts"],"sourcesContent":["import type { FastifyReply, FastifyRequest } from 'fastify';\nimport { ActionInvocationError } from '@headless-lms/core/integrations';\nimport { isResponseSerializationError } from 'fastify-type-provider-zod';\nimport { classifyError } from '../errors.js';\n\nfunction routeOf(request: FastifyRequest): string {\n return `${request.method} ${request.routeOptions.url ?? 'unmatched route'}`;\n}\n\nexport function errorHandler(error: unknown, request: FastifyRequest, reply: FastifyReply) {\n if (error instanceof ActionInvocationError) {\n request.log.error(\n { err: error, integrationId: error.integrationId, actionId: error.actionId },\n `integration action failed in ${routeOf(request)}`,\n );\n return reply.status(502).send({\n error: 'action_failed',\n message: 'The integration did not respond as expected',\n });\n }\n const refusal = classifyError(error);\n if (refusal) {\n request.log.info(\n {\n status: refusal.status,\n error: refusal.error,\n message: refusal.message,\n ...(refusal.issues && { issues: refusal.issues }),\n ...(refusal.details && { details: refusal.details }),\n ...(refusal.error === 'bad_request' && { cause: (error as Error).message }),\n },\n `${routeOf(request)} refused`,\n );\n return reply.status(refusal.status).send({\n error: refusal.error,\n message: refusal.message,\n ...(refusal.issues && { issues: refusal.issues }),\n ...(refusal.details && { details: refusal.details }),\n });\n }\n if (isResponseSerializationError(error)) {\n request.log.error(\n { err: error, issues: error.cause.issues },\n `response of ${routeOf(request)} does not match its schema`,\n );\n } else {\n request.log.error({ err: error }, `unhandled error in ${routeOf(request)}`);\n }\n return reply.status(500).send({\n error: 'internal_error',\n message: 'Something went wrong on our side. Quote the request id when reporting it.',\n requestId: request.id,\n });\n}\n\nexport function notFoundHandler(request: FastifyRequest, reply: FastifyReply) {\n request.log.info(\n { status: 404, error: 'not_found' },\n `${request.method} unmatched route refused`,\n );\n return reply\n .status(404)\n .send({ error: 'not_found', message: `No route for ${request.method} ${request.url}` });\n}\n"],"mappings":";;;;AAKA,SAAS,QAAQ,SAAiC;CAChD,OAAO,GAAG,QAAQ,OAAO,GAAG,QAAQ,aAAa,OAAO;AAC1D;AAEA,SAAgB,aAAa,OAAgB,SAAyB,OAAqB;CACzF,IAAI,iBAAiB,uBAAuB;EAC1C,QAAQ,IAAI,MACV;GAAE,KAAK;GAAO,eAAe,MAAM;GAAe,UAAU,MAAM;EAAS,GAC3E,gCAAgC,QAAQ,OAAO,GACjD;EACA,OAAO,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK;GAC5B,OAAO;GACP,SAAS;EACX,CAAC;CACH;CACA,MAAM,UAAU,cAAc,KAAK;CACnC,IAAI,SAAS;EACX,QAAQ,IAAI,KACV;GACE,QAAQ,QAAQ;GAChB,OAAO,QAAQ;GACf,SAAS,QAAQ;GACjB,GAAI,QAAQ,UAAU,EAAE,QAAQ,QAAQ,OAAO;GAC/C,GAAI,QAAQ,WAAW,EAAE,SAAS,QAAQ,QAAQ;GAClD,GAAI,QAAQ,UAAU,iBAAiB,EAAE,OAAQ,MAAgB,QAAQ;EAC3E,GACA,GAAG,QAAQ,OAAO,EAAE,SACtB;EACA,OAAO,MAAM,OAAO,QAAQ,MAAM,CAAC,CAAC,KAAK;GACvC,OAAO,QAAQ;GACf,SAAS,QAAQ;GACjB,GAAI,QAAQ,UAAU,EAAE,QAAQ,QAAQ,OAAO;GAC/C,GAAI,QAAQ,WAAW,EAAE,SAAS,QAAQ,QAAQ;EACpD,CAAC;CACH;CACA,IAAI,6BAA6B,KAAK,GACpC,QAAQ,IAAI,MACV;EAAE,KAAK;EAAO,QAAQ,MAAM,MAAM;CAAO,GACzC,eAAe,QAAQ,OAAO,EAAE,2BAClC;MAEA,QAAQ,IAAI,MAAM,EAAE,KAAK,MAAM,GAAG,sBAAsB,QAAQ,OAAO,GAAG;CAE5E,OAAO,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK;EAC5B,OAAO;EACP,SAAS;EACT,WAAW,QAAQ;CACrB,CAAC;AACH;AAEA,SAAgB,gBAAgB,SAAyB,OAAqB;CAC5E,QAAQ,IAAI,KACV;EAAE,QAAQ;EAAK,OAAO;CAAY,GAClC,GAAG,QAAQ,OAAO,yBACpB;CACA,OAAO,MACJ,OAAO,GAAG,CAAC,CACX,KAAK;EAAE,OAAO;EAAa,SAAS,gBAAgB,QAAQ,OAAO,GAAG,QAAQ;CAAM,CAAC;AAC1F"}
|