@headless-lms/server 0.1.0 → 0.3.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 +1 -1
- package/dist/_virtual/_rolldown/runtime.js +5 -0
- package/dist/app/community-mail.d.ts +26 -0
- package/dist/app/community-mail.js +96 -0
- package/dist/app/community-mail.js.map +1 -0
- package/dist/app/container.d.ts +22 -14
- package/dist/app/container.js +186 -62
- 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/http/config.d.ts +2 -1
- package/dist/http/errors.d.ts +14 -0
- package/dist/http/errors.js +147 -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 +3 -2
- package/dist/http/plugins/error-handler.js +52 -57
- package/dist/http/plugins/error-handler.js.map +1 -1
- package/dist/http/plugins/openapi.js +70 -20
- 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 +97 -20
- package/dist/http/routes/activities.js.map +1 -1
- package/dist/http/routes/assets.js +60 -51
- package/dist/http/routes/assets.js.map +1 -1
- package/dist/http/routes/automations.js +64 -20
- package/dist/http/routes/automations.js.map +1 -1
- package/dist/http/routes/bundles.d.ts +7 -0
- package/dist/http/routes/bundles.js +181 -0
- package/dist/http/routes/bundles.js.map +1 -0
- package/dist/http/routes/communities.d.ts +7 -0
- package/dist/http/routes/communities.js +462 -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.d.ts +7 -0
- package/dist/http/routes/course-analytics.js +60 -0
- package/dist/http/routes/course-analytics.js.map +1 -0
- package/dist/http/routes/courses.js +38 -23
- package/dist/http/routes/courses.js.map +1 -1
- package/dist/http/routes/dashboard.js +17 -8
- package/dist/http/routes/dashboard.js.map +1 -1
- package/dist/http/routes/discussion.js +35 -27
- package/dist/http/routes/discussion.js.map +1 -1
- package/dist/http/routes/downloads.js +58 -40
- 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 +456 -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 +288 -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/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 +31 -0
- package/dist/http/routes/member/index.js.map +1 -0
- package/dist/http/routes/member/notifications.d.ts +7 -0
- package/dist/http/routes/member/notifications.js +101 -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 +49 -24
- package/dist/http/routes/organizations.js.map +1 -1
- package/dist/http/routes/students.js +43 -37
- package/dist/http/routes/students.js.map +1 -1
- package/dist/http/routes/webhooks.d.ts +7 -0
- package/dist/http/routes/webhooks.js +167 -0
- package/dist/http/routes/webhooks.js.map +1 -0
- package/dist/http/routes.js +14 -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 +36 -1
- package/dist/http/schemas/activities.js +9 -4
- package/dist/http/schemas/activities.js.map +1 -1
- package/dist/http/schemas/assets.d.ts +76 -73
- package/dist/http/schemas/assets.js +23 -13
- package/dist/http/schemas/assets.js.map +1 -1
- package/dist/http/schemas/automations.d.ts +85 -8
- package/dist/http/schemas/automations.js +13 -2
- package/dist/http/schemas/automations.js.map +1 -1
- package/dist/http/schemas/bundles.d.ts +63 -0
- package/dist/http/schemas/bundles.js +23 -0
- package/dist/http/schemas/bundles.js.map +1 -0
- package/dist/http/schemas/chats.d.ts +386 -0
- package/dist/http/schemas/chats.js +58 -0
- package/dist/http/schemas/chats.js.map +1 -0
- package/dist/http/schemas/community.d.ts +537 -0
- package/dist/http/schemas/community.js +129 -0
- package/dist/http/schemas/community.js.map +1 -0
- package/dist/http/schemas/content.d.ts +22 -13
- package/dist/http/schemas/content.js +11 -9
- package/dist/http/schemas/content.js.map +1 -1
- package/dist/http/schemas/course-analytics.d.ts +29 -0
- package/dist/http/schemas/course-analytics.js +21 -0
- package/dist/http/schemas/course-analytics.js.map +1 -0
- package/dist/http/schemas/dashboard.js.map +1 -1
- package/dist/http/schemas/discussion.d.ts +85 -23
- package/dist/http/schemas/discussion.js +12 -11
- package/dist/http/schemas/discussion.js.map +1 -1
- package/dist/http/schemas/downloads.d.ts +13 -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 +14 -6
- package/dist/http/schemas/entitlements.js +8 -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 +19 -10
- package/dist/http/schemas/index.js +19 -10
- package/dist/http/schemas/integrations.d.ts +4 -4
- package/dist/http/schemas/integrations.js.map +1 -1
- package/dist/http/schemas/invites.d.ts +4 -0
- package/dist/http/schemas/invites.js +3 -1
- package/dist/http/schemas/invites.js.map +1 -1
- package/dist/http/schemas/{learn.d.ts → member.d.ts} +42 -19
- 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 +39 -6
- package/dist/http/schemas/members.js +17 -3
- package/dist/http/schemas/members.js.map +1 -1
- package/dist/http/schemas/notifications.d.ts +227 -0
- package/dist/http/schemas/notifications.js +44 -0
- package/dist/http/schemas/notifications.js.map +1 -0
- package/dist/http/schemas/organizations.js.map +1 -1
- package/dist/http/schemas/posts.d.ts +316 -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/settings.js.map +1 -1
- package/dist/http/schemas/shared.d.ts +26 -1
- package/dist/http/schemas/shared.js +22 -3
- package/dist/http/schemas/shared.js.map +1 -1
- package/dist/http/schemas/students.d.ts +32 -10
- package/dist/http/schemas/students.js +19 -6
- package/dist/http/schemas/students.js.map +1 -1
- package/dist/http/scope.d.ts +2 -1
- package/dist/http/scope.js +20 -4
- package/dist/http/scope.js.map +1 -1
- package/dist/http/server.js +10 -3
- 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 -2
- 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 -23
- 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 -75
- 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
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { refusals } from "../schemas/shared.js";
|
|
1
2
|
import { resolveScope } from "../scope.js";
|
|
2
|
-
import { ErrorBody } from "../schemas/shared.js";
|
|
3
3
|
import { Course, CourseIdParam, CourseSettings, CoursesPage, CoursesQuery, CreateCourse, PatchCourseSettings, UpdateCourse } from "../schemas/content.js";
|
|
4
4
|
import "../schemas/index.js";
|
|
5
|
-
import { NotFoundError } from "@headless-lms/core/shared/errors";
|
|
6
5
|
import { z } from "zod";
|
|
6
|
+
import { NotFoundError } from "@headless-lms/core/shared/errors";
|
|
7
7
|
//#region src/http/routes/courses.ts
|
|
8
8
|
async function coursesRoutes(app, container) {
|
|
9
9
|
const r = app.withTypeProvider();
|
|
@@ -14,14 +14,18 @@ async function coursesRoutes(app, container) {
|
|
|
14
14
|
preHandler: app.requireOrgSession,
|
|
15
15
|
schema: {
|
|
16
16
|
operationId: "listCourses",
|
|
17
|
-
tags: ["
|
|
18
|
-
summary: "List courses",
|
|
17
|
+
tags: ["Content"],
|
|
18
|
+
summary: "List courses (staff)",
|
|
19
|
+
description: "Staff only (owner, admin, instructor). Every course in the organization, drafts included, filtered by status and category and searched by title.",
|
|
19
20
|
querystring: CoursesQuery,
|
|
20
|
-
response: {
|
|
21
|
+
response: {
|
|
22
|
+
200: CoursesPage,
|
|
23
|
+
...refusals(403)
|
|
24
|
+
}
|
|
21
25
|
},
|
|
22
26
|
handler: async (req) => {
|
|
23
27
|
const scope = await resolveScope(container, req);
|
|
24
|
-
return courses.
|
|
28
|
+
return courses.listCourses(scope.orgId, req.query);
|
|
25
29
|
}
|
|
26
30
|
});
|
|
27
31
|
r.route({
|
|
@@ -30,12 +34,13 @@ async function coursesRoutes(app, container) {
|
|
|
30
34
|
preHandler: app.requireOrgSession,
|
|
31
35
|
schema: {
|
|
32
36
|
operationId: "getCourse",
|
|
33
|
-
tags: ["
|
|
34
|
-
summary: "Get a course
|
|
37
|
+
tags: ["Content"],
|
|
38
|
+
summary: "Get a course (staff)",
|
|
39
|
+
description: "Staff only (owner, admin, instructor).",
|
|
35
40
|
params: CourseIdParam,
|
|
36
41
|
response: {
|
|
37
42
|
200: Course,
|
|
38
|
-
404
|
|
43
|
+
...refusals(403, 404)
|
|
39
44
|
}
|
|
40
45
|
},
|
|
41
46
|
handler: async (req) => {
|
|
@@ -51,10 +56,14 @@ async function coursesRoutes(app, container) {
|
|
|
51
56
|
preHandler: app.requireOrgSession,
|
|
52
57
|
schema: {
|
|
53
58
|
operationId: "createCourse",
|
|
54
|
-
tags: ["
|
|
55
|
-
summary: "Create a course",
|
|
59
|
+
tags: ["Content"],
|
|
60
|
+
summary: "Create a course (staff)",
|
|
61
|
+
description: "Staff only (owner, admin, instructor). The course starts as a draft. 409 when its slug is taken.",
|
|
56
62
|
body: CreateCourse,
|
|
57
|
-
response: {
|
|
63
|
+
response: {
|
|
64
|
+
201: Course,
|
|
65
|
+
...refusals(403, 409)
|
|
66
|
+
}
|
|
58
67
|
},
|
|
59
68
|
handler: async (req, reply) => {
|
|
60
69
|
const scope = await resolveScope(container, req);
|
|
@@ -68,13 +77,14 @@ async function coursesRoutes(app, container) {
|
|
|
68
77
|
preHandler: app.requireOrgSession,
|
|
69
78
|
schema: {
|
|
70
79
|
operationId: "updateCourse",
|
|
71
|
-
tags: ["
|
|
72
|
-
summary: "Update a course",
|
|
80
|
+
tags: ["Content"],
|
|
81
|
+
summary: "Update a course (staff)",
|
|
82
|
+
description: "Staff only (owner, admin, instructor). Changes only the fields sent. `thumbnailAssetId` must be a ready library image (409 otherwise); null clears it.",
|
|
73
83
|
params: CourseIdParam,
|
|
74
84
|
body: UpdateCourse,
|
|
75
85
|
response: {
|
|
76
86
|
200: Course,
|
|
77
|
-
404
|
|
87
|
+
...refusals(403, 404, 409)
|
|
78
88
|
}
|
|
79
89
|
},
|
|
80
90
|
handler: async (req) => {
|
|
@@ -88,19 +98,20 @@ async function coursesRoutes(app, container) {
|
|
|
88
98
|
preHandler: app.requireOrgSession,
|
|
89
99
|
schema: {
|
|
90
100
|
operationId: "updateCourseSettings",
|
|
91
|
-
tags: ["
|
|
92
|
-
summary: "Update a course settings",
|
|
101
|
+
tags: ["Content"],
|
|
102
|
+
summary: "Update a course's settings (staff)",
|
|
103
|
+
description: "Staff only (owner, admin, instructor). Merges the settings sent into the current ones.",
|
|
93
104
|
params: CourseIdParam,
|
|
94
105
|
body: PatchCourseSettings,
|
|
95
106
|
response: {
|
|
96
107
|
200: CourseSettings,
|
|
97
|
-
404
|
|
108
|
+
...refusals(403, 404)
|
|
98
109
|
}
|
|
99
110
|
},
|
|
100
111
|
handler: async (req) => {
|
|
101
112
|
const scope = await resolveScope(container, req);
|
|
102
113
|
req.log.info({ body: req.body }, "update course settings");
|
|
103
|
-
return courses.
|
|
114
|
+
return courses.patchCourseSettings(scope.orgId, req.params.id, req.body);
|
|
104
115
|
}
|
|
105
116
|
});
|
|
106
117
|
r.route({
|
|
@@ -109,17 +120,21 @@ async function coursesRoutes(app, container) {
|
|
|
109
120
|
preHandler: app.requireOrgSession,
|
|
110
121
|
schema: {
|
|
111
122
|
operationId: "deleteCourse",
|
|
112
|
-
tags: ["
|
|
113
|
-
summary: "Delete a course",
|
|
123
|
+
tags: ["Content"],
|
|
124
|
+
summary: "Delete a course (staff)",
|
|
125
|
+
description: "Staff only (owner, admin, instructor).",
|
|
114
126
|
params: CourseIdParam,
|
|
115
127
|
response: {
|
|
116
128
|
204: z.void(),
|
|
117
|
-
404
|
|
129
|
+
...refusals(403, 404)
|
|
118
130
|
}
|
|
119
131
|
},
|
|
120
132
|
handler: async (req, reply) => {
|
|
121
133
|
const scope = await resolveScope(container, req);
|
|
122
|
-
await courses.deleteCourse(scope.orgId, req.params.id
|
|
134
|
+
await courses.deleteCourse(scope.orgId, req.params.id, {
|
|
135
|
+
id: scope.orgUserId,
|
|
136
|
+
role: scope.role
|
|
137
|
+
});
|
|
123
138
|
return reply.code(204).send();
|
|
124
139
|
}
|
|
125
140
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"courses.js","names":[],"sources":["../../../src/http/routes/courses.ts"],"sourcesContent":["// HTTP routes for the courses context. Request + response are validated against\n// the shared contract schemas by the Zod type provider, and @fastify/swagger\n// reads the same schemas to build the OpenAPI spec the SDK is generated from.\nimport type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport {\n Course,\n CourseIdParam,\n CourseSettings,\n CoursesPage,\n CoursesQuery,\n CreateCourse,\n
|
|
1
|
+
{"version":3,"file":"courses.js","names":[],"sources":["../../../src/http/routes/courses.ts"],"sourcesContent":["// HTTP routes for the courses context. Request + response are validated against\n// the shared contract schemas by the Zod type provider, and @fastify/swagger\n// reads the same schemas to build the OpenAPI spec the SDK is generated from.\nimport type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport {\n Course,\n CourseIdParam,\n CourseSettings,\n CoursesPage,\n CoursesQuery,\n CreateCourse,\n PatchCourseSettings,\n UpdateCourse,\n refusals,\n} from '../schemas/index.js';\nimport { z } from 'zod';\nimport type { Container } from '../../app/container.js';\nimport { NotFoundError } from '@headless-lms/core/shared/errors';\nimport { resolveScope } from '../scope.js';\n\nexport async function coursesRoutes(app: FastifyInstance, container: Container): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n const courses = container.content;\n\n r.route({\n method: 'GET',\n url: '/api/courses',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listCourses',\n tags: ['Content'],\n summary: 'List courses (staff)',\n description:\n 'Staff only (owner, admin, instructor). Every course in the organization, drafts included, filtered by status and category and searched by title.',\n querystring: CoursesQuery,\n response: { 200: CoursesPage, ...refusals(403) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return courses.listCourses(scope.orgId, req.query);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/courses/:id',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getCourse',\n tags: ['Content'],\n summary: 'Get a course (staff)',\n description: 'Staff only (owner, admin, instructor).',\n params: CourseIdParam,\n response: { 200: Course, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n const course = await courses.getCourse(scope.orgId, req.params.id);\n if (!course) {\n throw new NotFoundError('Course', req.params.id);\n }\n return course;\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/courses',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'createCourse',\n tags: ['Content'],\n summary: 'Create a course (staff)',\n description:\n 'Staff only (owner, admin, instructor). The course starts as a draft. 409 when its slug is taken.',\n body: CreateCourse,\n response: { 201: Course, ...refusals(403, 409) },\n },\n handler: async (req, reply) => {\n const scope = await resolveScope(container, req);\n const course = await courses.createCourse(scope.orgId, req.body);\n return reply.code(201).send(course);\n },\n });\n\n r.route({\n method: 'PATCH',\n url: '/api/courses/:id',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'updateCourse',\n tags: ['Content'],\n summary: 'Update a course (staff)',\n description:\n 'Staff only (owner, admin, instructor). Changes only the fields sent. `thumbnailAssetId` must be a ready library image (409 otherwise); null clears it.',\n params: CourseIdParam,\n body: UpdateCourse,\n response: { 200: Course, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return courses.updateCourse(scope.orgId, req.params.id, req.body);\n },\n });\n\n r.route({\n method: 'PATCH',\n url: '/api/courses/:id/settings',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'updateCourseSettings',\n tags: ['Content'],\n summary: \"Update a course's settings (staff)\",\n description:\n 'Staff only (owner, admin, instructor). Merges the settings sent into the current ones.',\n params: CourseIdParam,\n body: PatchCourseSettings,\n response: { 200: CourseSettings, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n req.log.info({ body: req.body }, 'update course settings');\n return courses.patchCourseSettings(scope.orgId, req.params.id, req.body);\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/courses/:id',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'deleteCourse',\n tags: ['Content'],\n summary: 'Delete a course (staff)',\n description: 'Staff only (owner, admin, instructor).',\n params: CourseIdParam,\n response: { 204: z.void(), ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const scope = await resolveScope(container, req);\n await courses.deleteCourse(scope.orgId, req.params.id, {\n id: scope.orgUserId,\n role: scope.role,\n });\n return reply.code(204).send();\n },\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { refusals } from "../schemas/shared.js";
|
|
1
2
|
import { resolveScope } from "../scope.js";
|
|
2
3
|
import { EnrollmentSeries, EnrollmentSeriesQuery, OverviewStats } from "../schemas/dashboard.js";
|
|
3
4
|
import "../schemas/index.js";
|
|
@@ -10,13 +11,17 @@ async function dashboardRoutes(app, container) {
|
|
|
10
11
|
preHandler: app.requireOrgSession,
|
|
11
12
|
schema: {
|
|
12
13
|
operationId: "getOverview",
|
|
13
|
-
tags: ["
|
|
14
|
-
summary: "Back-office overview stats",
|
|
15
|
-
|
|
14
|
+
tags: ["Reporting"],
|
|
15
|
+
summary: "Back-office overview stats (staff)",
|
|
16
|
+
description: "Staff only (owner, admin, instructor).",
|
|
17
|
+
response: {
|
|
18
|
+
200: OverviewStats,
|
|
19
|
+
...refusals(403)
|
|
20
|
+
}
|
|
16
21
|
},
|
|
17
22
|
handler: async (req) => {
|
|
18
23
|
const scope = await resolveScope(container, req);
|
|
19
|
-
return container.reporting.
|
|
24
|
+
return container.reporting.admin.overview(scope.orgId);
|
|
20
25
|
}
|
|
21
26
|
});
|
|
22
27
|
r.route({
|
|
@@ -25,14 +30,18 @@ async function dashboardRoutes(app, container) {
|
|
|
25
30
|
preHandler: app.requireOrgSession,
|
|
26
31
|
schema: {
|
|
27
32
|
operationId: "getEnrollmentSeries",
|
|
28
|
-
tags: ["
|
|
29
|
-
summary: "Enrollments granted per day over a trailing window",
|
|
33
|
+
tags: ["Reporting"],
|
|
34
|
+
summary: "Enrollments granted per day over a trailing window (staff)",
|
|
35
|
+
description: "Staff only (owner, admin, instructor).",
|
|
30
36
|
querystring: EnrollmentSeriesQuery,
|
|
31
|
-
response: {
|
|
37
|
+
response: {
|
|
38
|
+
200: EnrollmentSeries,
|
|
39
|
+
...refusals(403)
|
|
40
|
+
}
|
|
32
41
|
},
|
|
33
42
|
handler: async (req) => {
|
|
34
43
|
const scope = await resolveScope(container, req);
|
|
35
|
-
return container.reporting.
|
|
44
|
+
return container.reporting.admin.enrollments(scope.orgId, req.query.days);
|
|
36
45
|
}
|
|
37
46
|
});
|
|
38
47
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashboard.js","names":[],"sources":["../../../src/http/routes/dashboard.ts"],"sourcesContent":["// HTTP routes for the dashboard (overview) context.\nimport type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport {
|
|
1
|
+
{"version":3,"file":"dashboard.js","names":[],"sources":["../../../src/http/routes/dashboard.ts"],"sourcesContent":["// HTTP routes for the dashboard (overview) context.\nimport type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport {\n EnrollmentSeries,\n EnrollmentSeriesQuery,\n OverviewStats,\n refusals,\n} from '../schemas/index.js';\nimport type { Container } from '../../app/container.js';\nimport { resolveScope } from '../scope.js';\n\nexport async function dashboardRoutes(app: FastifyInstance, container: Container): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n\n r.route({\n method: 'GET',\n url: '/api/overview',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getOverview',\n tags: ['Reporting'],\n summary: 'Back-office overview stats (staff)',\n description: 'Staff only (owner, admin, instructor).',\n response: { 200: OverviewStats, ...refusals(403) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return container.reporting.admin.overview(scope.orgId);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/overview/enrollments',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getEnrollmentSeries',\n tags: ['Reporting'],\n summary: 'Enrollments granted per day over a trailing window (staff)',\n description: 'Staff only (owner, admin, instructor).',\n querystring: EnrollmentSeriesQuery,\n response: { 200: EnrollmentSeries, ...refusals(403) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return container.reporting.admin.enrollments(scope.orgId, req.query.days);\n },\n });\n}\n"],"mappings":";;;;;AAYA,eAAsB,gBAAgB,KAAsB,WAAqC;CAC/F,MAAM,IAAI,IAAI,iBAAkC;CAEhD,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb,MAAM,CAAC,WAAW;GAClB,SAAS;GACT,aAAa;GACb,UAAU;IAAE,KAAK;IAAe,GAAG,SAAS,GAAG;GAAE;EACnD;EACA,SAAS,OAAO,QAAQ;GACtB,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,OAAO,UAAU,UAAU,MAAM,SAAS,MAAM,KAAK;EACvD;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb,MAAM,CAAC,WAAW;GAClB,SAAS;GACT,aAAa;GACb,aAAa;GACb,UAAU;IAAE,KAAK;IAAkB,GAAG,SAAS,GAAG;GAAE;EACtD;EACA,SAAS,OAAO,QAAQ;GACtB,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,OAAO,UAAU,UAAU,MAAM,YAAY,MAAM,OAAO,IAAI,MAAM,IAAI;EAC1E;CACF,CAAC;AACH"}
|
|
@@ -1,22 +1,30 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { refusals } from "../schemas/shared.js";
|
|
2
|
+
import { resolveScope } from "../scope.js";
|
|
2
3
|
import { Comment, CommentIdParam, CommentView, CommentsPage, CommentsQuery, PatchComment, ReplyToComment } from "../schemas/discussion.js";
|
|
3
4
|
import "../schemas/index.js";
|
|
4
|
-
import { NotFoundError } from "@headless-lms/core/shared/errors";
|
|
5
5
|
import { z } from "zod";
|
|
6
|
+
import { NotFoundError } from "@headless-lms/core/shared/errors";
|
|
6
7
|
//#region src/http/routes/discussion.ts
|
|
7
8
|
async function discussionRoutes(app, container) {
|
|
8
9
|
const r = app.withTypeProvider();
|
|
9
10
|
const discussion = container.discussion;
|
|
11
|
+
const staff = async (req) => {
|
|
12
|
+
await resolveScope(container, req);
|
|
13
|
+
};
|
|
10
14
|
r.route({
|
|
11
15
|
method: "GET",
|
|
12
16
|
url: "/api/comments",
|
|
13
|
-
preHandler:
|
|
17
|
+
preHandler: staff,
|
|
14
18
|
schema: {
|
|
15
19
|
operationId: "listComments",
|
|
16
20
|
tags: ["Discussion"],
|
|
17
|
-
summary: "List
|
|
21
|
+
summary: "List course comments for moderation (staff)",
|
|
22
|
+
description: "Staff only (owner, admin, instructor). Comments on course activities, filtered by course, activity, author, status or open reports; each row carries the author's email and the open reports.",
|
|
18
23
|
querystring: CommentsQuery,
|
|
19
|
-
response: {
|
|
24
|
+
response: {
|
|
25
|
+
200: CommentsPage,
|
|
26
|
+
...refusals(403)
|
|
27
|
+
}
|
|
20
28
|
},
|
|
21
29
|
handler: async (req) => {
|
|
22
30
|
return discussion.listComments(req.orgId, req.query);
|
|
@@ -25,88 +33,88 @@ async function discussionRoutes(app, container) {
|
|
|
25
33
|
r.route({
|
|
26
34
|
method: "DELETE",
|
|
27
35
|
url: "/api/comments/:commentId",
|
|
28
|
-
preHandler:
|
|
36
|
+
preHandler: staff,
|
|
29
37
|
schema: {
|
|
30
38
|
operationId: "moderateRemoveComment",
|
|
31
39
|
tags: ["Discussion"],
|
|
32
|
-
summary: "Remove a comment
|
|
40
|
+
summary: "Remove a course comment (staff)",
|
|
41
|
+
description: "Staff only (owner, admin, instructor). Hides the comment and resolves its open reports as `removed`. Removing a removed comment returns it unchanged.",
|
|
33
42
|
params: CommentIdParam,
|
|
34
43
|
response: {
|
|
35
|
-
200:
|
|
36
|
-
403
|
|
37
|
-
404: ErrorBody
|
|
44
|
+
200: CommentView,
|
|
45
|
+
...refusals(403, 404)
|
|
38
46
|
}
|
|
39
47
|
},
|
|
40
48
|
handler: async (req) => {
|
|
41
49
|
const orgUser = await container.organizations.getOrgUser(req.orgId, req.userId);
|
|
42
|
-
return discussion.remove(req.orgId, req.params.commentId, orgUser);
|
|
50
|
+
return discussion.remove(req.orgId, req.params.commentId, orgUser, null);
|
|
43
51
|
}
|
|
44
52
|
});
|
|
45
53
|
r.route({
|
|
46
54
|
method: "PATCH",
|
|
47
55
|
url: "/api/comments/:commentId",
|
|
48
|
-
preHandler:
|
|
56
|
+
preHandler: staff,
|
|
49
57
|
schema: {
|
|
50
|
-
operationId: "
|
|
58
|
+
operationId: "publishComment",
|
|
51
59
|
tags: ["Discussion"],
|
|
52
|
-
summary: "Publish a comment
|
|
60
|
+
summary: "Publish a course comment (staff)",
|
|
61
|
+
description: "Staff only (owner, admin, instructor). Approves a pending comment or restores a removed one; a published comment is returned unchanged.",
|
|
53
62
|
params: CommentIdParam,
|
|
54
63
|
body: PatchComment,
|
|
55
64
|
response: {
|
|
56
65
|
200: Comment,
|
|
57
|
-
403
|
|
58
|
-
404: ErrorBody
|
|
66
|
+
...refusals(403, 404)
|
|
59
67
|
}
|
|
60
68
|
},
|
|
61
69
|
handler: async (req) => {
|
|
62
70
|
const orgUser = await container.organizations.getOrgUser(req.orgId, req.userId);
|
|
63
71
|
if (!orgUser) throw new NotFoundError("OrgUser", req.userId);
|
|
64
|
-
return discussion.publish(req.orgId, req.params.commentId, orgUser);
|
|
72
|
+
return discussion.publish(req.orgId, req.params.commentId, orgUser, null);
|
|
65
73
|
}
|
|
66
74
|
});
|
|
67
75
|
r.route({
|
|
68
76
|
method: "DELETE",
|
|
69
77
|
url: "/api/comments/:commentId/reports",
|
|
70
|
-
preHandler:
|
|
78
|
+
preHandler: staff,
|
|
71
79
|
schema: {
|
|
72
80
|
operationId: "dismissCommentReports",
|
|
73
81
|
tags: ["Discussion"],
|
|
74
|
-
summary: "Dismiss every open report on a comment",
|
|
82
|
+
summary: "Dismiss every open report on a course comment (staff)",
|
|
83
|
+
description: "Staff only (owner, admin, instructor). The comment stays up.",
|
|
75
84
|
params: CommentIdParam,
|
|
76
85
|
response: {
|
|
77
86
|
204: z.void(),
|
|
78
|
-
403
|
|
79
|
-
404: ErrorBody
|
|
87
|
+
...refusals(403, 404)
|
|
80
88
|
}
|
|
81
89
|
},
|
|
82
90
|
handler: async (req, reply) => {
|
|
83
91
|
const orgUser = await container.organizations.getOrgUser(req.orgId, req.userId);
|
|
84
92
|
if (!orgUser) throw new NotFoundError("OrgUser", req.userId);
|
|
85
|
-
await discussion.resolveReports(req.orgId, req.params.commentId, orgUser);
|
|
93
|
+
await discussion.resolveReports(req.orgId, req.params.commentId, orgUser, null);
|
|
86
94
|
return reply.code(204).send();
|
|
87
95
|
}
|
|
88
96
|
});
|
|
89
97
|
r.route({
|
|
90
98
|
method: "POST",
|
|
91
99
|
url: "/api/comments/:commentId/replies",
|
|
92
|
-
preHandler:
|
|
100
|
+
preHandler: staff,
|
|
93
101
|
schema: {
|
|
94
102
|
operationId: "replyToComment",
|
|
95
103
|
tags: ["Discussion"],
|
|
96
|
-
summary: "Reply to a comment from the moderation queue",
|
|
104
|
+
summary: "Reply to a course comment from the moderation queue (staff)",
|
|
105
|
+
description: "Staff only (owner, admin, instructor). Replies nest one level: answering a reply attaches to its root comment.",
|
|
97
106
|
params: CommentIdParam,
|
|
98
107
|
body: ReplyToComment,
|
|
99
108
|
response: {
|
|
100
109
|
200: CommentView,
|
|
101
|
-
403
|
|
102
|
-
404: ErrorBody
|
|
110
|
+
...refusals(403, 404)
|
|
103
111
|
}
|
|
104
112
|
},
|
|
105
113
|
handler: async (req) => {
|
|
106
114
|
const orgUser = await container.organizations.getOrgUser(req.orgId, req.userId);
|
|
107
115
|
if (!orgUser) throw new NotFoundError("OrgUser", req.userId);
|
|
108
116
|
const parent = await discussion.getComment(req.orgId, req.params.commentId);
|
|
109
|
-
if (!parent) throw new NotFoundError("Comment", req.params.commentId);
|
|
117
|
+
if (!parent || parent.activityId === null) throw new NotFoundError("Comment", req.params.commentId);
|
|
110
118
|
return discussion.postComment(req.orgId, {
|
|
111
119
|
actor: orgUser,
|
|
112
120
|
activityId: parent.activityId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discussion.js","names":[],"sources":["../../../src/http/routes/discussion.ts"],"sourcesContent":["// Moderator-facing discussion routes. The learner surface (everything under\n// `/api/
|
|
1
|
+
{"version":3,"file":"discussion.js","names":[],"sources":["../../../src/http/routes/discussion.ts"],"sourcesContent":["// Moderator-facing discussion routes. The learner surface (everything under\n// `/api/member`) lives in routes/member/comments.ts.\nimport type { FastifyInstance, FastifyRequest } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport { z } from 'zod';\nimport {\n Comment,\n CommentIdParam,\n CommentsPage,\n CommentsQuery,\n CommentView,\n PatchComment,\n ReplyToComment,\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 discussionRoutes(app: FastifyInstance, container: Container): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n const discussion = container.discussion;\n const staff = async (req: FastifyRequest) => {\n await resolveScope(container, req);\n };\n\n r.route({\n method: 'GET',\n url: '/api/comments',\n preHandler: staff,\n schema: {\n operationId: 'listComments',\n tags: ['Discussion'],\n summary: 'List course comments for moderation (staff)',\n description:\n \"Staff only (owner, admin, instructor). Comments on course activities, filtered by course, activity, author, status or open reports; each row carries the author's email and the open reports.\",\n querystring: CommentsQuery,\n response: { 200: CommentsPage, ...refusals(403) },\n },\n handler: async (req) => {\n return discussion.listComments(req.orgId, req.query);\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/comments/:commentId',\n preHandler: staff,\n schema: {\n operationId: 'moderateRemoveComment',\n tags: ['Discussion'],\n summary: 'Remove a course comment (staff)',\n description:\n 'Staff only (owner, admin, instructor). Hides the comment and resolves its open reports as `removed`. Removing a removed comment returns it unchanged.',\n params: CommentIdParam,\n response: { 200: CommentView, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const orgUser = await container.organizations.getOrgUser(req.orgId, req.userId);\n return discussion.remove(req.orgId, req.params.commentId, orgUser!, null);\n },\n });\n\n r.route({\n method: 'PATCH',\n url: '/api/comments/:commentId',\n preHandler: staff,\n schema: {\n operationId: 'publishComment',\n tags: ['Discussion'],\n summary: 'Publish a course comment (staff)',\n description:\n 'Staff only (owner, admin, instructor). Approves a pending comment or restores a removed one; a published comment is returned unchanged.',\n params: CommentIdParam,\n body: PatchComment,\n response: { 200: Comment, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const orgUser = await container.organizations.getOrgUser(req.orgId, req.userId);\n if (!orgUser) {\n throw new NotFoundError('OrgUser', req.userId);\n }\n return discussion.publish(req.orgId, req.params.commentId, orgUser, null);\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/comments/:commentId/reports',\n preHandler: staff,\n schema: {\n operationId: 'dismissCommentReports',\n tags: ['Discussion'],\n summary: 'Dismiss every open report on a course comment (staff)',\n description: 'Staff only (owner, admin, instructor). The comment stays up.',\n params: CommentIdParam,\n response: { 204: z.void(), ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const orgUser = await container.organizations.getOrgUser(req.orgId, req.userId);\n if (!orgUser) {\n throw new NotFoundError('OrgUser', req.userId);\n }\n await discussion.resolveReports(req.orgId, req.params.commentId, orgUser, null);\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/comments/:commentId/replies',\n preHandler: staff,\n schema: {\n operationId: 'replyToComment',\n tags: ['Discussion'],\n summary: 'Reply to a course comment from the moderation queue (staff)',\n description:\n 'Staff only (owner, admin, instructor). Replies nest one level: answering a reply attaches to its root comment.',\n params: CommentIdParam,\n body: ReplyToComment,\n response: { 200: CommentView, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const orgUser = await container.organizations.getOrgUser(req.orgId, req.userId);\n if (!orgUser) {\n throw new NotFoundError('OrgUser', req.userId);\n }\n const parent = await discussion.getComment(req.orgId, req.params.commentId);\n if (!parent || parent.activityId === null) {\n throw new NotFoundError('Comment', req.params.commentId);\n }\n // Replies nest one level: answering a reply attaches to its root.\n return discussion.postComment(req.orgId, {\n actor: orgUser,\n activityId: parent.activityId,\n parentId: parent.parentId ?? parent.id,\n body: req.body.body,\n });\n },\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { refusals } from "../schemas/shared.js";
|
|
1
2
|
import { resolveScope } from "../scope.js";
|
|
2
|
-
import {
|
|
3
|
-
import { AddDownloadAsset, CreateDownload, Download, DownloadAsset, DownloadAssetParams, DownloadIdParam, DownloadsPage, DownloadsQuery, RenameDownloadAsset, ReorderDownloadAssets, UpdateDownload } from "../schemas/downloads.js";
|
|
3
|
+
import { AddDownloadAsset, CreateDownload, Download, DownloadAssetParams, DownloadFile, DownloadIdParam, DownloadsPage, DownloadsQuery, RenameDownloadAsset, ReorderDownloadAssets, UpdateDownload } from "../schemas/downloads.js";
|
|
4
4
|
import "../schemas/index.js";
|
|
5
|
-
import { NotFoundError } from "@headless-lms/core/shared/errors";
|
|
6
5
|
import { z } from "zod";
|
|
6
|
+
import { NotFoundError } from "@headless-lms/core/shared/errors";
|
|
7
7
|
//#region src/http/routes/downloads.ts
|
|
8
8
|
async function downloadsRoutes(app, container) {
|
|
9
9
|
const r = app.withTypeProvider();
|
|
@@ -14,10 +14,14 @@ async function downloadsRoutes(app, container) {
|
|
|
14
14
|
preHandler: app.requireOrgSession,
|
|
15
15
|
schema: {
|
|
16
16
|
operationId: "listDownloads",
|
|
17
|
-
tags: ["
|
|
18
|
-
summary: "List downloads",
|
|
17
|
+
tags: ["Content"],
|
|
18
|
+
summary: "List downloads (staff)",
|
|
19
|
+
description: "Staff only (owner, admin, instructor). Every download, drafts included, filtered by status and category and searched by title.",
|
|
19
20
|
querystring: DownloadsQuery,
|
|
20
|
-
response: {
|
|
21
|
+
response: {
|
|
22
|
+
200: DownloadsPage,
|
|
23
|
+
...refusals(403)
|
|
24
|
+
}
|
|
21
25
|
},
|
|
22
26
|
handler: async (req) => {
|
|
23
27
|
const scope = await resolveScope(container, req);
|
|
@@ -30,12 +34,13 @@ async function downloadsRoutes(app, container) {
|
|
|
30
34
|
preHandler: app.requireOrgSession,
|
|
31
35
|
schema: {
|
|
32
36
|
operationId: "getDownload",
|
|
33
|
-
tags: ["
|
|
34
|
-
summary: "Get a download
|
|
37
|
+
tags: ["Content"],
|
|
38
|
+
summary: "Get a download (staff)",
|
|
39
|
+
description: "Staff only (owner, admin, instructor).",
|
|
35
40
|
params: DownloadIdParam,
|
|
36
41
|
response: {
|
|
37
42
|
200: Download,
|
|
38
|
-
404
|
|
43
|
+
...refusals(403, 404)
|
|
39
44
|
}
|
|
40
45
|
},
|
|
41
46
|
handler: async (req) => {
|
|
@@ -51,10 +56,14 @@ async function downloadsRoutes(app, container) {
|
|
|
51
56
|
preHandler: app.requireOrgSession,
|
|
52
57
|
schema: {
|
|
53
58
|
operationId: "createDownload",
|
|
54
|
-
tags: ["
|
|
55
|
-
summary: "Create a download",
|
|
59
|
+
tags: ["Content"],
|
|
60
|
+
summary: "Create a download (staff)",
|
|
61
|
+
description: "Staff only (owner, admin, instructor). The download starts as a draft. 409 when its slug is taken.",
|
|
56
62
|
body: CreateDownload,
|
|
57
|
-
response: {
|
|
63
|
+
response: {
|
|
64
|
+
201: Download,
|
|
65
|
+
...refusals(403, 409)
|
|
66
|
+
}
|
|
58
67
|
},
|
|
59
68
|
handler: async (req, reply) => {
|
|
60
69
|
const scope = await resolveScope(container, req);
|
|
@@ -68,13 +77,14 @@ async function downloadsRoutes(app, container) {
|
|
|
68
77
|
preHandler: app.requireOrgSession,
|
|
69
78
|
schema: {
|
|
70
79
|
operationId: "updateDownload",
|
|
71
|
-
tags: ["
|
|
72
|
-
summary: "Update a download",
|
|
80
|
+
tags: ["Content"],
|
|
81
|
+
summary: "Update a download (staff)",
|
|
82
|
+
description: "Staff only (owner, admin, instructor). Changes only the fields sent. `thumbnailAssetId` must be a ready library image (409 otherwise); null clears it.",
|
|
73
83
|
params: DownloadIdParam,
|
|
74
84
|
body: UpdateDownload,
|
|
75
85
|
response: {
|
|
76
86
|
200: Download,
|
|
77
|
-
404
|
|
87
|
+
...refusals(403, 404, 409)
|
|
78
88
|
}
|
|
79
89
|
},
|
|
80
90
|
handler: async (req) => {
|
|
@@ -88,17 +98,21 @@ async function downloadsRoutes(app, container) {
|
|
|
88
98
|
preHandler: app.requireOrgSession,
|
|
89
99
|
schema: {
|
|
90
100
|
operationId: "deleteDownload",
|
|
91
|
-
tags: ["
|
|
92
|
-
summary: "Delete a download",
|
|
101
|
+
tags: ["Content"],
|
|
102
|
+
summary: "Delete a download (staff)",
|
|
103
|
+
description: "Staff only (owner, admin, instructor). Its library files survive.",
|
|
93
104
|
params: DownloadIdParam,
|
|
94
105
|
response: {
|
|
95
106
|
204: z.void(),
|
|
96
|
-
404
|
|
107
|
+
...refusals(403, 404)
|
|
97
108
|
}
|
|
98
109
|
},
|
|
99
110
|
handler: async (req, reply) => {
|
|
100
111
|
const scope = await resolveScope(container, req);
|
|
101
|
-
await content.removeDownload(scope.orgId, req.params.downloadId
|
|
112
|
+
await content.removeDownload(scope.orgId, req.params.downloadId, {
|
|
113
|
+
id: scope.orgUserId,
|
|
114
|
+
role: scope.role
|
|
115
|
+
});
|
|
102
116
|
return reply.code(204).send();
|
|
103
117
|
}
|
|
104
118
|
});
|
|
@@ -108,12 +122,13 @@ async function downloadsRoutes(app, container) {
|
|
|
108
122
|
preHandler: app.requireOrgSession,
|
|
109
123
|
schema: {
|
|
110
124
|
operationId: "listDownloadAssets",
|
|
111
|
-
tags: ["
|
|
112
|
-
summary: "List a download's
|
|
125
|
+
tags: ["Content"],
|
|
126
|
+
summary: "List a download's files in order (staff)",
|
|
127
|
+
description: "Staff only (owner, admin, instructor).",
|
|
113
128
|
params: DownloadIdParam,
|
|
114
129
|
response: {
|
|
115
|
-
200: z.array(
|
|
116
|
-
|
|
130
|
+
200: z.array(DownloadFile),
|
|
131
|
+
...refusals(403)
|
|
117
132
|
}
|
|
118
133
|
},
|
|
119
134
|
handler: async (req) => {
|
|
@@ -127,13 +142,14 @@ async function downloadsRoutes(app, container) {
|
|
|
127
142
|
preHandler: app.requireOrgSession,
|
|
128
143
|
schema: {
|
|
129
144
|
operationId: "addDownloadAsset",
|
|
130
|
-
tags: ["
|
|
131
|
-
summary: "
|
|
145
|
+
tags: ["Content"],
|
|
146
|
+
summary: "Add a library file to a download (staff)",
|
|
147
|
+
description: "Staff only (owner, admin, instructor). Added last. 409 when the file is not a ready library file or is already in the download. Returns the download's files.",
|
|
132
148
|
params: DownloadIdParam,
|
|
133
149
|
body: AddDownloadAsset,
|
|
134
150
|
response: {
|
|
135
|
-
200: z.array(
|
|
136
|
-
404
|
|
151
|
+
200: z.array(DownloadFile),
|
|
152
|
+
...refusals(403, 404, 409)
|
|
137
153
|
}
|
|
138
154
|
},
|
|
139
155
|
handler: async (req) => {
|
|
@@ -147,14 +163,14 @@ async function downloadsRoutes(app, container) {
|
|
|
147
163
|
preHandler: app.requireOrgSession,
|
|
148
164
|
schema: {
|
|
149
165
|
operationId: "reorderDownloadAssets",
|
|
150
|
-
tags: ["
|
|
151
|
-
summary: "Reorder a download's
|
|
166
|
+
tags: ["Content"],
|
|
167
|
+
summary: "Reorder a download's files (staff)",
|
|
168
|
+
description: "Staff only (owner, admin, instructor). Send every file id of the download exactly once (409 otherwise). Returns the download's files.",
|
|
152
169
|
params: DownloadIdParam,
|
|
153
170
|
body: ReorderDownloadAssets,
|
|
154
171
|
response: {
|
|
155
|
-
200: z.array(
|
|
156
|
-
404
|
|
157
|
-
409: ErrorBody
|
|
172
|
+
200: z.array(DownloadFile),
|
|
173
|
+
...refusals(403, 404, 409)
|
|
158
174
|
}
|
|
159
175
|
},
|
|
160
176
|
handler: async (req) => {
|
|
@@ -168,13 +184,14 @@ async function downloadsRoutes(app, container) {
|
|
|
168
184
|
preHandler: app.requireOrgSession,
|
|
169
185
|
schema: {
|
|
170
186
|
operationId: "renameDownloadAsset",
|
|
171
|
-
tags: ["
|
|
172
|
-
summary: "Set
|
|
187
|
+
tags: ["Content"],
|
|
188
|
+
summary: "Set a file's display name within a download (staff)",
|
|
189
|
+
description: "Staff only (owner, admin, instructor). Null falls back to the filename. Returns the download's files.",
|
|
173
190
|
params: DownloadAssetParams,
|
|
174
191
|
body: RenameDownloadAsset,
|
|
175
192
|
response: {
|
|
176
|
-
200: z.array(
|
|
177
|
-
404
|
|
193
|
+
200: z.array(DownloadFile),
|
|
194
|
+
...refusals(403, 404)
|
|
178
195
|
}
|
|
179
196
|
},
|
|
180
197
|
handler: async (req) => {
|
|
@@ -188,12 +205,13 @@ async function downloadsRoutes(app, container) {
|
|
|
188
205
|
preHandler: app.requireOrgSession,
|
|
189
206
|
schema: {
|
|
190
207
|
operationId: "removeDownloadAsset",
|
|
191
|
-
tags: ["
|
|
192
|
-
summary: "
|
|
208
|
+
tags: ["Content"],
|
|
209
|
+
summary: "Remove a file from a download (staff)",
|
|
210
|
+
description: "Staff only (owner, admin, instructor). The library file itself survives. Returns the download's files.",
|
|
193
211
|
params: DownloadAssetParams,
|
|
194
212
|
response: {
|
|
195
|
-
200: z.array(
|
|
196
|
-
404
|
|
213
|
+
200: z.array(DownloadFile),
|
|
214
|
+
...refusals(403, 404)
|
|
197
215
|
}
|
|
198
216
|
},
|
|
199
217
|
handler: async (req) => {
|