@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,59 +1,109 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ErrorBody, ValidationErrorBody } from "../schemas/shared.js";
|
|
2
|
+
import { version } from "../../packages/server/package.js";
|
|
3
|
+
import { jsonSchemaTransform, jsonSchemaTransformObject } from "fastify-type-provider-zod";
|
|
2
4
|
import swagger from "@fastify/swagger";
|
|
3
5
|
import swaggerUi from "@fastify/swagger-ui";
|
|
4
6
|
//#region src/http/plugins/openapi.ts
|
|
7
|
+
const PUBLIC_ROUTES = /* @__PURE__ */ new Set(["GET /api/organizations/invites/:token"]);
|
|
8
|
+
function withDefaultResponses(schema, method, url) {
|
|
9
|
+
if (!schema || !url.startsWith("/api/") || url.startsWith("/api/auth/")) return schema;
|
|
10
|
+
const response = { ...schema.response ?? {} };
|
|
11
|
+
if ((schema.body || schema.querystring || schema.params) && !response["400"]) response["400"] = ValidationErrorBody;
|
|
12
|
+
if (!PUBLIC_ROUTES.has(`${method} ${url}`) && !response["401"]) response["401"] = ErrorBody;
|
|
13
|
+
if (!response["500"]) response["500"] = ErrorBody;
|
|
14
|
+
return {
|
|
15
|
+
...schema,
|
|
16
|
+
response
|
|
17
|
+
};
|
|
18
|
+
}
|
|
5
19
|
function registerOpenApi(app, config) {
|
|
6
20
|
app.register(swagger, {
|
|
7
21
|
openapi: {
|
|
8
22
|
info: {
|
|
9
23
|
title: "Headless LMS API",
|
|
10
|
-
version
|
|
24
|
+
version,
|
|
25
|
+
description: "API documentation for the Headless LMS platform",
|
|
26
|
+
license: {
|
|
27
|
+
name: "MIT",
|
|
28
|
+
url: "https://opensource.org/licenses/MIT"
|
|
29
|
+
}
|
|
11
30
|
},
|
|
12
31
|
servers: [{ url: config.publicUrl }],
|
|
13
32
|
tags: [
|
|
14
33
|
{
|
|
15
34
|
name: "Organizations",
|
|
16
|
-
description: "
|
|
35
|
+
description: "The tenant: its members, roles, invites and students"
|
|
17
36
|
},
|
|
18
37
|
{
|
|
19
|
-
name: "
|
|
20
|
-
description: "
|
|
38
|
+
name: "Content",
|
|
39
|
+
description: "Authored content: courses and downloads, their structure and delivery"
|
|
21
40
|
},
|
|
22
41
|
{
|
|
23
|
-
name: "
|
|
24
|
-
description: "
|
|
42
|
+
name: "Entitlements",
|
|
43
|
+
description: "Access grants to content"
|
|
25
44
|
},
|
|
26
45
|
{
|
|
27
|
-
name: "
|
|
28
|
-
description: "
|
|
46
|
+
name: "Progress",
|
|
47
|
+
description: "Per-student progress and completion through course content"
|
|
29
48
|
},
|
|
30
49
|
{
|
|
31
|
-
name: "
|
|
32
|
-
description: "
|
|
50
|
+
name: "Discussion",
|
|
51
|
+
description: "Learner comments, replies, reactions and moderation"
|
|
33
52
|
},
|
|
34
53
|
{
|
|
35
|
-
name: "
|
|
36
|
-
description: "
|
|
54
|
+
name: "Communities",
|
|
55
|
+
description: "Communities, their spaces, topics, and direct-message settings"
|
|
37
56
|
},
|
|
38
57
|
{
|
|
39
|
-
name: "
|
|
40
|
-
description: "
|
|
58
|
+
name: "Posts",
|
|
59
|
+
description: "Posts in a space, reactions, and the moderation queue"
|
|
41
60
|
},
|
|
42
61
|
{
|
|
43
|
-
name: "
|
|
44
|
-
description: "
|
|
62
|
+
name: "Chats",
|
|
63
|
+
description: "Direct and group chats inside one community"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: "Profile",
|
|
67
|
+
description: "The signed-in member profile"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: "Notifications",
|
|
71
|
+
description: "What happened to the signed-in member, and how they want to be told"
|
|
45
72
|
},
|
|
46
73
|
{
|
|
47
74
|
name: "Assets",
|
|
48
|
-
description: "
|
|
75
|
+
description: "The org media library: uploads, serving and lifecycle"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: "Files",
|
|
79
|
+
description: "Stable file URLs that check access and redirect to a signed storage URL"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: "Automations",
|
|
83
|
+
description: "Workflows and webhooks that react to system events"
|
|
49
84
|
},
|
|
50
85
|
{
|
|
51
86
|
name: "Integrations",
|
|
52
|
-
description: "
|
|
87
|
+
description: "Connections to external services"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: "Reporting",
|
|
91
|
+
description: "Reporting and analytics"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: "Access",
|
|
95
|
+
description: "Access scopes, connected apps and API keys"
|
|
53
96
|
}
|
|
54
97
|
]
|
|
55
98
|
},
|
|
56
|
-
transform:
|
|
99
|
+
transform: (input) => {
|
|
100
|
+
const method = String(Array.isArray(input.route.method) ? input.route.method[0] : input.route.method);
|
|
101
|
+
return jsonSchemaTransform({
|
|
102
|
+
...input,
|
|
103
|
+
schema: withDefaultResponses(input.schema, method, input.url)
|
|
104
|
+
});
|
|
105
|
+
},
|
|
106
|
+
transformObject: jsonSchemaTransformObject
|
|
57
107
|
});
|
|
58
108
|
app.register(swaggerUi, { routePrefix: "/docs" });
|
|
59
109
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openapi.js","names":[],"sources":["../../../src/http/plugins/openapi.ts"],"sourcesContent":["// OpenAPI documentation. @fastify/swagger reads the Zod route schemas (via the\n// transform) to build the spec the frontend SDK is generated from; it must be\n// registered before the routes so its onRoute hook captures them. UI + JSON are\n// served under /docs.\nimport type { FastifyInstance } from 'fastify';\nimport swagger from '@fastify/swagger';\nimport swaggerUi from '@fastify/swagger-ui';\nimport { jsonSchemaTransform } from 'fastify-type-provider-zod';\nimport type { ServerConfig } from '../config.js';\n\nexport function registerOpenApi(app: FastifyInstance, config: ServerConfig): void {\n app.register(swagger, {\n openapi: {\n info: {
|
|
1
|
+
{"version":3,"file":"openapi.js","names":["pkg.version"],"sources":["../../../src/http/plugins/openapi.ts"],"sourcesContent":["// OpenAPI documentation. @fastify/swagger reads the Zod route schemas (via the\n// transform) to build the spec the frontend SDK is generated from; it must be\n// registered before the routes so its onRoute hook captures them. UI + JSON are\n// served under /docs.\nimport type { FastifyInstance } from 'fastify';\nimport swagger from '@fastify/swagger';\nimport swaggerUi from '@fastify/swagger-ui';\nimport { jsonSchemaTransform, jsonSchemaTransformObject } from 'fastify-type-provider-zod';\nimport type { ServerConfig } from '../config.js';\nimport { ErrorBody, ValidationErrorBody } from '../schemas/shared.js';\nimport pkg from '../../../package.json' with { type: 'json' };\n\nconst PUBLIC_ROUTES = new Set(['GET /api/organizations/invites/:token']);\n\ntype RouteSchema = {\n body?: unknown;\n querystring?: unknown;\n params?: unknown;\n response?: Record<string, unknown>;\n};\n\nfunction withDefaultResponses(\n schema: RouteSchema | undefined,\n method: string,\n url: string,\n): RouteSchema | undefined {\n if (!schema || !url.startsWith('/api/') || url.startsWith('/api/auth/')) {\n return schema;\n }\n const response: Record<string, unknown> = { ...(schema.response ?? {}) };\n if ((schema.body || schema.querystring || schema.params) && !response['400']) {\n response['400'] = ValidationErrorBody;\n }\n if (!PUBLIC_ROUTES.has(`${method} ${url}`) && !response['401']) {\n response['401'] = ErrorBody;\n }\n if (!response['500']) {\n response['500'] = ErrorBody;\n }\n return { ...schema, response };\n}\n\nexport function registerOpenApi(app: FastifyInstance, config: ServerConfig): void {\n app.register(swagger, {\n openapi: {\n info: {\n title: 'Headless LMS API',\n version: pkg.version,\n description: 'API documentation for the Headless LMS platform',\n license: {\n name: 'MIT',\n url: 'https://opensource.org/licenses/MIT',\n },\n },\n servers: [{ url: config.publicUrl }],\n tags: [\n {\n name: 'Organizations',\n description: 'The tenant: its members, roles, invites and students',\n },\n {\n name: 'Content',\n description: 'Authored content: courses and downloads, their structure and delivery',\n },\n { name: 'Entitlements', description: 'Access grants to content' },\n {\n name: 'Progress',\n description: 'Per-student progress and completion through course content',\n },\n { name: 'Discussion', description: 'Learner comments, replies, reactions and moderation' },\n {\n name: 'Communities',\n description: 'Communities, their spaces, topics, and direct-message settings',\n },\n { name: 'Posts', description: 'Posts in a space, reactions, and the moderation queue' },\n { name: 'Chats', description: 'Direct and group chats inside one community' },\n { name: 'Profile', description: 'The signed-in member profile' },\n {\n name: 'Notifications',\n description: 'What happened to the signed-in member, and how they want to be told',\n },\n { name: 'Assets', description: 'The org media library: uploads, serving and lifecycle' },\n {\n name: 'Files',\n description: 'Stable file URLs that check access and redirect to a signed storage URL',\n },\n { name: 'Automations', description: 'Workflows and webhooks that react to system events' },\n { name: 'Integrations', description: 'Connections to external services' },\n { name: 'Reporting', description: 'Reporting and analytics' },\n { name: 'Access', description: 'Access scopes, connected apps and API keys' },\n ],\n },\n transform: (input) => {\n const method = String(\n Array.isArray(input.route.method) ? input.route.method[0] : input.route.method,\n );\n return jsonSchemaTransform({\n ...input,\n schema: withDefaultResponses(input.schema as RouteSchema | undefined, method, input.url),\n } as typeof input);\n },\n transformObject: jsonSchemaTransformObject,\n });\n app.register(swaggerUi, { routePrefix: '/docs' });\n}\n"],"mappings":";;;;;;AAYA,MAAM,gCAAgB,IAAI,IAAI,CAAC,uCAAuC,CAAC;AASvE,SAAS,qBACP,QACA,QACA,KACyB;CACzB,IAAI,CAAC,UAAU,CAAC,IAAI,WAAW,OAAO,KAAK,IAAI,WAAW,YAAY,GACpE,OAAO;CAET,MAAM,WAAoC,EAAE,GAAI,OAAO,YAAY,CAAC,EAAG;CACvE,KAAK,OAAO,QAAQ,OAAO,eAAe,OAAO,WAAW,CAAC,SAAS,QACpE,SAAS,SAAS;CAEpB,IAAI,CAAC,cAAc,IAAI,GAAG,OAAO,GAAG,KAAK,KAAK,CAAC,SAAS,QACtD,SAAS,SAAS;CAEpB,IAAI,CAAC,SAAS,QACZ,SAAS,SAAS;CAEpB,OAAO;EAAE,GAAG;EAAQ;CAAS;AAC/B;AAEA,SAAgB,gBAAgB,KAAsB,QAA4B;CAChF,IAAI,SAAS,SAAS;EACpB,SAAS;GACP,MAAM;IACJ,OAAO;IACEA;IACT,aAAa;IACb,SAAS;KACP,MAAM;KACN,KAAK;IACP;GACF;GACA,SAAS,CAAC,EAAE,KAAK,OAAO,UAAU,CAAC;GACnC,MAAM;IACJ;KACE,MAAM;KACN,aAAa;IACf;IACA;KACE,MAAM;KACN,aAAa;IACf;IACA;KAAE,MAAM;KAAgB,aAAa;IAA2B;IAChE;KACE,MAAM;KACN,aAAa;IACf;IACA;KAAE,MAAM;KAAc,aAAa;IAAsD;IACzF;KACE,MAAM;KACN,aAAa;IACf;IACA;KAAE,MAAM;KAAS,aAAa;IAAwD;IACtF;KAAE,MAAM;KAAS,aAAa;IAA8C;IAC5E;KAAE,MAAM;KAAW,aAAa;IAA+B;IAC/D;KACE,MAAM;KACN,aAAa;IACf;IACA;KAAE,MAAM;KAAU,aAAa;IAAwD;IACvF;KACE,MAAM;KACN,aAAa;IACf;IACA;KAAE,MAAM;KAAe,aAAa;IAAqD;IACzF;KAAE,MAAM;KAAgB,aAAa;IAAmC;IACxE;KAAE,MAAM;KAAa,aAAa;IAA0B;IAC5D;KAAE,MAAM;KAAU,aAAa;IAA6C;GAC9E;EACF;EACA,YAAY,UAAU;GACpB,MAAM,SAAS,OACb,MAAM,QAAQ,MAAM,MAAM,MAAM,IAAI,MAAM,MAAM,OAAO,KAAK,MAAM,MAAM,MAC1E;GACA,OAAO,oBAAoB;IACzB,GAAG;IACH,QAAQ,qBAAqB,MAAM,QAAmC,QAAQ,MAAM,GAAG;GACzF,CAAiB;EACnB;EACA,iBAAiB;CACnB,CAAC;CACD,IAAI,SAAS,WAAW,EAAE,aAAa,QAAQ,CAAC;AAClD"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Container } from "../../app/container.js";
|
|
2
|
+
import { FastifyInstance } from "fastify";
|
|
3
|
+
//#region src/http/routes/access.d.ts
|
|
4
|
+
declare function accessRoutes(app: FastifyInstance, container: Container): Promise<void>;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { accessRoutes };
|
|
7
|
+
//# sourceMappingURL=access.d.ts.map
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { refusals } from "../schemas/shared.js";
|
|
2
|
+
import { resolveScope } from "../scope.js";
|
|
3
|
+
import { ApiKeyIdParam, ApiKeyList, ClientIdParam, ConnectedAppList, CreateApiKey, CreatedApiKey, ScopeOptionList } from "../schemas/access.js";
|
|
4
|
+
import "../schemas/index.js";
|
|
5
|
+
import { assertRoleHoldsScopes, scopeOptions } from "@headless-lms/core/organizations";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
//#region src/http/routes/access.ts
|
|
8
|
+
async function accessRoutes(app, container) {
|
|
9
|
+
const r = app.withTypeProvider();
|
|
10
|
+
const tags = ["Access"];
|
|
11
|
+
r.route({
|
|
12
|
+
method: "GET",
|
|
13
|
+
url: "/api/access/scopes",
|
|
14
|
+
preHandler: app.requireOrgSession,
|
|
15
|
+
schema: {
|
|
16
|
+
operationId: "listAccessScopes",
|
|
17
|
+
tags,
|
|
18
|
+
summary: "Every access scope and whether your role can grant it",
|
|
19
|
+
description: "Staff only (owner, admin, instructor). Each scope an app connection or API key can carry, marked with whether your role holds it. Only allowed scopes can be granted.",
|
|
20
|
+
response: {
|
|
21
|
+
200: ScopeOptionList,
|
|
22
|
+
...refusals(403)
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
handler: async (req) => {
|
|
26
|
+
return scopeOptions((await resolveScope(container, req)).role);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
r.route({
|
|
30
|
+
method: "GET",
|
|
31
|
+
url: "/api/access/apps",
|
|
32
|
+
preHandler: app.requireOrgSession,
|
|
33
|
+
schema: {
|
|
34
|
+
operationId: "listConnectedApps",
|
|
35
|
+
tags,
|
|
36
|
+
summary: "Apps connected to this organization as you",
|
|
37
|
+
description: "Staff only (owner, admin, instructor). The apps you connected to this organization, each with the scopes you granted and when.",
|
|
38
|
+
response: {
|
|
39
|
+
200: ConnectedAppList,
|
|
40
|
+
...refusals(403)
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
handler: async (req) => {
|
|
44
|
+
const scope = await resolveScope(container, req);
|
|
45
|
+
return container.auth.listConnectedApps(req.headers, scope.authOrgId);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
r.route({
|
|
49
|
+
method: "DELETE",
|
|
50
|
+
url: "/api/access/apps/:clientId",
|
|
51
|
+
preHandler: app.requireOrgSession,
|
|
52
|
+
schema: {
|
|
53
|
+
operationId: "revokeConnectedApp",
|
|
54
|
+
tags,
|
|
55
|
+
summary: "Disconnect an app",
|
|
56
|
+
description: "Staff only (owner, admin, instructor). Revokes your consent and refresh tokens for the app in this organization; its next call is refused.",
|
|
57
|
+
params: ClientIdParam,
|
|
58
|
+
response: {
|
|
59
|
+
204: z.void(),
|
|
60
|
+
...refusals(403)
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
handler: async (req, reply) => {
|
|
64
|
+
const scope = await resolveScope(container, req);
|
|
65
|
+
await container.auth.revokeConnectedApp(req.headers, scope.authOrgId, req.params.clientId);
|
|
66
|
+
return reply.code(204).send();
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
r.route({
|
|
70
|
+
method: "GET",
|
|
71
|
+
url: "/api/access/api-keys",
|
|
72
|
+
preHandler: app.requireOrgSession,
|
|
73
|
+
schema: {
|
|
74
|
+
operationId: "listApiKeys",
|
|
75
|
+
tags,
|
|
76
|
+
summary: "Your API keys for this organization",
|
|
77
|
+
description: "Staff only (owner, admin, instructor). Your keys for this organization with their scopes. The key itself is never returned again after it is created.",
|
|
78
|
+
response: {
|
|
79
|
+
200: ApiKeyList,
|
|
80
|
+
...refusals(403)
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
handler: async (req) => {
|
|
84
|
+
const scope = await resolveScope(container, req);
|
|
85
|
+
return container.auth.listApiKeys(req.headers, scope.authOrgId);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
r.route({
|
|
89
|
+
method: "POST",
|
|
90
|
+
url: "/api/access/api-keys",
|
|
91
|
+
preHandler: app.requireOrgSession,
|
|
92
|
+
schema: {
|
|
93
|
+
operationId: "createApiKey",
|
|
94
|
+
tags,
|
|
95
|
+
summary: "Create an API key",
|
|
96
|
+
description: "Staff only (owner, admin, instructor). The key acts as you in this organization with the scopes given. 403 when your role cannot hold one of them. The key is returned once.",
|
|
97
|
+
body: CreateApiKey,
|
|
98
|
+
response: {
|
|
99
|
+
201: CreatedApiKey,
|
|
100
|
+
...refusals(400, 403)
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
handler: async (req, reply) => {
|
|
104
|
+
const scope = await resolveScope(container, req);
|
|
105
|
+
assertRoleHoldsScopes(scope.role, req.body.scopes);
|
|
106
|
+
const created = await container.auth.createApiKey({
|
|
107
|
+
authUserId: req.authUser.id,
|
|
108
|
+
orgId: scope.authOrgId,
|
|
109
|
+
name: req.body.name,
|
|
110
|
+
scopes: req.body.scopes
|
|
111
|
+
});
|
|
112
|
+
return reply.code(201).send(created);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
r.route({
|
|
116
|
+
method: "DELETE",
|
|
117
|
+
url: "/api/access/api-keys/:id",
|
|
118
|
+
preHandler: app.requireOrgSession,
|
|
119
|
+
schema: {
|
|
120
|
+
operationId: "deleteApiKey",
|
|
121
|
+
tags,
|
|
122
|
+
summary: "Delete an API key",
|
|
123
|
+
description: "Staff only (owner, admin, instructor). 404 when the key is not one of yours in this organization.",
|
|
124
|
+
params: ApiKeyIdParam,
|
|
125
|
+
response: {
|
|
126
|
+
204: z.void(),
|
|
127
|
+
...refusals(403, 404)
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
handler: async (req, reply) => {
|
|
131
|
+
const scope = await resolveScope(container, req);
|
|
132
|
+
await container.auth.deleteApiKey(req.headers, scope.authOrgId, req.params.id);
|
|
133
|
+
return reply.code(204).send();
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
//#endregion
|
|
138
|
+
export { accessRoutes };
|
|
139
|
+
|
|
140
|
+
//# sourceMappingURL=access.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access.js","names":[],"sources":["../../../src/http/routes/access.ts"],"sourcesContent":["import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport { z } from 'zod';\nimport { assertRoleHoldsScopes, scopeOptions } from '@headless-lms/core/organizations';\nimport type { Container } from '../../app/container.js';\nimport {\n ApiKeyIdParam,\n ApiKeyList,\n ClientIdParam,\n ConnectedAppList,\n CreateApiKey,\n CreatedApiKey,\n refusals,\n ScopeOptionList,\n} from '../schemas/index.js';\nimport { resolveScope } from '../scope.js';\n\nexport async function accessRoutes(app: FastifyInstance, container: Container): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n const tags = ['Access'];\n\n r.route({\n method: 'GET',\n url: '/api/access/scopes',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listAccessScopes',\n tags,\n summary: 'Every access scope and whether your role can grant it',\n description:\n 'Staff only (owner, admin, instructor). Each scope an app connection or API key can carry, marked with whether your role holds it. Only allowed scopes can be granted.',\n response: { 200: ScopeOptionList, ...refusals(403) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return scopeOptions(scope.role);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/access/apps',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listConnectedApps',\n tags,\n summary: 'Apps connected to this organization as you',\n description:\n 'Staff only (owner, admin, instructor). The apps you connected to this organization, each with the scopes you granted and when.',\n response: { 200: ConnectedAppList, ...refusals(403) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return container.auth.listConnectedApps(req.headers, scope.authOrgId);\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/access/apps/:clientId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'revokeConnectedApp',\n tags,\n summary: 'Disconnect an app',\n description:\n 'Staff only (owner, admin, instructor). Revokes your consent and refresh tokens for the app in this organization; its next call is refused.',\n params: ClientIdParam,\n response: { 204: z.void(), ...refusals(403) },\n },\n handler: async (req, reply) => {\n const scope = await resolveScope(container, req);\n await container.auth.revokeConnectedApp(req.headers, scope.authOrgId, req.params.clientId);\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/access/api-keys',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listApiKeys',\n tags,\n summary: 'Your API keys for this organization',\n description:\n 'Staff only (owner, admin, instructor). Your keys for this organization with their scopes. The key itself is never returned again after it is created.',\n response: { 200: ApiKeyList, ...refusals(403) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return container.auth.listApiKeys(req.headers, scope.authOrgId);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/access/api-keys',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'createApiKey',\n tags,\n summary: 'Create an API key',\n description:\n 'Staff only (owner, admin, instructor). The key acts as you in this organization with the scopes given. 403 when your role cannot hold one of them. The key is returned once.',\n body: CreateApiKey,\n response: { 201: CreatedApiKey, ...refusals(400, 403) },\n },\n handler: async (req, reply) => {\n const scope = await resolveScope(container, req);\n assertRoleHoldsScopes(scope.role, req.body.scopes);\n const created = await container.auth.createApiKey({\n authUserId: req.authUser.id,\n orgId: scope.authOrgId,\n name: req.body.name,\n scopes: req.body.scopes,\n });\n return reply.code(201).send(created);\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/access/api-keys/:id',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'deleteApiKey',\n tags,\n summary: 'Delete an API key',\n description:\n 'Staff only (owner, admin, instructor). 404 when the key is not one of yours in this organization.',\n params: ApiKeyIdParam,\n response: { 204: z.void(), ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const scope = await resolveScope(container, req);\n await container.auth.deleteApiKey(req.headers, scope.authOrgId, req.params.id);\n return reply.code(204).send();\n },\n });\n}\n"],"mappings":";;;;;;;AAiBA,eAAsB,aAAa,KAAsB,WAAqC;CAC5F,MAAM,IAAI,IAAI,iBAAkC;CAChD,MAAM,OAAO,CAAC,QAAQ;CAEtB,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb;GACA,SAAS;GACT,aACE;GACF,UAAU;IAAE,KAAK;IAAiB,GAAG,SAAS,GAAG;GAAE;EACrD;EACA,SAAS,OAAO,QAAQ;GAEtB,OAAO,cAAa,MADA,aAAa,WAAW,GAAG,EAAA,CACrB,IAAI;EAChC;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb;GACA,SAAS;GACT,aACE;GACF,UAAU;IAAE,KAAK;IAAkB,GAAG,SAAS,GAAG;GAAE;EACtD;EACA,SAAS,OAAO,QAAQ;GACtB,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,OAAO,UAAU,KAAK,kBAAkB,IAAI,SAAS,MAAM,SAAS;EACtE;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb;GACA,SAAS;GACT,aACE;GACF,QAAQ;GACR,UAAU;IAAE,KAAK,EAAE,KAAK;IAAG,GAAG,SAAS,GAAG;GAAE;EAC9C;EACA,SAAS,OAAO,KAAK,UAAU;GAC7B,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,MAAM,UAAU,KAAK,mBAAmB,IAAI,SAAS,MAAM,WAAW,IAAI,OAAO,QAAQ;GACzF,OAAO,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK;EAC9B;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb;GACA,SAAS;GACT,aACE;GACF,UAAU;IAAE,KAAK;IAAY,GAAG,SAAS,GAAG;GAAE;EAChD;EACA,SAAS,OAAO,QAAQ;GACtB,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,OAAO,UAAU,KAAK,YAAY,IAAI,SAAS,MAAM,SAAS;EAChE;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb;GACA,SAAS;GACT,aACE;GACF,MAAM;GACN,UAAU;IAAE,KAAK;IAAe,GAAG,SAAS,KAAK,GAAG;GAAE;EACxD;EACA,SAAS,OAAO,KAAK,UAAU;GAC7B,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,sBAAsB,MAAM,MAAM,IAAI,KAAK,MAAM;GACjD,MAAM,UAAU,MAAM,UAAU,KAAK,aAAa;IAChD,YAAY,IAAI,SAAS;IACzB,OAAO,MAAM;IACb,MAAM,IAAI,KAAK;IACf,QAAQ,IAAI,KAAK;GACnB,CAAC;GACD,OAAO,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,OAAO;EACrC;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb;GACA,SAAS;GACT,aACE;GACF,QAAQ;GACR,UAAU;IAAE,KAAK,EAAE,KAAK;IAAG,GAAG,SAAS,KAAK,GAAG;GAAE;EACnD;EACA,SAAS,OAAO,KAAK,UAAU;GAC7B,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,MAAM,UAAU,KAAK,aAAa,IAAI,SAAS,MAAM,WAAW,IAAI,OAAO,EAAE;GAC7E,OAAO,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK;EAC9B;CACF,CAAC;AACH"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
+
import { refusals } from "../schemas/shared.js";
|
|
1
2
|
import { resolveScope } from "../scope.js";
|
|
2
|
-
import { ActivityPathParam, CourseIdPathParam, CreateModule, ModuleList, ModulePathParam, ReorderInput, SaveActivity, UpdateModule } from "../schemas/activities.js";
|
|
3
|
+
import { ActivityAssetList, ActivityList, ActivityPathParam, CourseIdPathParam, CreateModule, ModuleList, ModulePathParam, ReorderInput, SaveActivity, UpdateModule } from "../schemas/activities.js";
|
|
3
4
|
import "../schemas/index.js";
|
|
4
5
|
//#region src/http/routes/activities.ts
|
|
5
6
|
async function activitiesRoutes(app, container) {
|
|
6
7
|
const r = app.withTypeProvider();
|
|
7
8
|
const content = container.content;
|
|
8
|
-
const tags = ["
|
|
9
|
+
const tags = ["Content"];
|
|
9
10
|
r.route({
|
|
10
11
|
method: "GET",
|
|
11
12
|
url: "/api/courses/:courseId/modules",
|
|
@@ -13,15 +14,59 @@ async function activitiesRoutes(app, container) {
|
|
|
13
14
|
schema: {
|
|
14
15
|
operationId: "listModules",
|
|
15
16
|
tags,
|
|
16
|
-
summary: "List a course's modules",
|
|
17
|
+
summary: "List a course's modules (staff)",
|
|
18
|
+
description: "Staff only (owner, admin, instructor). Modules in order, each with its activities.",
|
|
17
19
|
params: CourseIdPathParam,
|
|
18
|
-
response: {
|
|
20
|
+
response: {
|
|
21
|
+
200: ModuleList,
|
|
22
|
+
...refusals(403)
|
|
23
|
+
}
|
|
19
24
|
},
|
|
20
25
|
handler: async (req) => {
|
|
21
26
|
const scope = await resolveScope(container, req);
|
|
22
27
|
return content.listCourseModules(scope.orgId, req.params.courseId);
|
|
23
28
|
}
|
|
24
29
|
});
|
|
30
|
+
r.route({
|
|
31
|
+
method: "GET",
|
|
32
|
+
url: "/api/courses/:courseId/activities",
|
|
33
|
+
preHandler: app.requireOrgSession,
|
|
34
|
+
schema: {
|
|
35
|
+
operationId: "listActivities",
|
|
36
|
+
tags,
|
|
37
|
+
summary: "List a course's activities (staff)",
|
|
38
|
+
description: "Staff only (owner, admin, instructor). Every activity, published or not.",
|
|
39
|
+
params: CourseIdPathParam,
|
|
40
|
+
response: {
|
|
41
|
+
200: ActivityList,
|
|
42
|
+
...refusals(403)
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
handler: async (req) => {
|
|
46
|
+
const scope = await resolveScope(container, req);
|
|
47
|
+
return content.listCourseActivityViews(scope.orgId, req.params.courseId);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
r.route({
|
|
51
|
+
method: "GET",
|
|
52
|
+
url: "/api/courses/:courseId/activity-assets",
|
|
53
|
+
preHandler: app.requireOrgSession,
|
|
54
|
+
schema: {
|
|
55
|
+
operationId: "listActivityAssets",
|
|
56
|
+
tags,
|
|
57
|
+
summary: "List the library files each activity of a course uses (staff)",
|
|
58
|
+
description: "Staff only (owner, admin, instructor). One row per activity and file, as recorded when the activity was saved.",
|
|
59
|
+
params: CourseIdPathParam,
|
|
60
|
+
response: {
|
|
61
|
+
200: ActivityAssetList,
|
|
62
|
+
...refusals(403)
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
handler: async (req) => {
|
|
66
|
+
const scope = await resolveScope(container, req);
|
|
67
|
+
return content.listCourseActivityAssets(scope.orgId, req.params.courseId);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
25
70
|
r.route({
|
|
26
71
|
method: "POST",
|
|
27
72
|
url: "/api/courses/:courseId/modules",
|
|
@@ -29,10 +74,14 @@ async function activitiesRoutes(app, container) {
|
|
|
29
74
|
schema: {
|
|
30
75
|
operationId: "createModule",
|
|
31
76
|
tags,
|
|
32
|
-
summary: "Add a module",
|
|
77
|
+
summary: "Add a module (staff)",
|
|
78
|
+
description: "Staff only (owner, admin, instructor). Added last. Returns the course's modules.",
|
|
33
79
|
params: CourseIdPathParam,
|
|
34
80
|
body: CreateModule,
|
|
35
|
-
response: {
|
|
81
|
+
response: {
|
|
82
|
+
200: ModuleList,
|
|
83
|
+
...refusals(403)
|
|
84
|
+
}
|
|
36
85
|
},
|
|
37
86
|
handler: async (req) => {
|
|
38
87
|
const scope = await resolveScope(container, req);
|
|
@@ -46,10 +95,14 @@ async function activitiesRoutes(app, container) {
|
|
|
46
95
|
schema: {
|
|
47
96
|
operationId: "reorderModules",
|
|
48
97
|
tags,
|
|
49
|
-
summary: "Reorder modules",
|
|
98
|
+
summary: "Reorder a course's modules (staff)",
|
|
99
|
+
description: "Staff only (owner, admin, instructor). Ids that are not modules of the course are ignored. Returns the course's modules.",
|
|
50
100
|
params: CourseIdPathParam,
|
|
51
101
|
body: ReorderInput,
|
|
52
|
-
response: {
|
|
102
|
+
response: {
|
|
103
|
+
200: ModuleList,
|
|
104
|
+
...refusals(403)
|
|
105
|
+
}
|
|
53
106
|
},
|
|
54
107
|
handler: async (req) => {
|
|
55
108
|
const scope = await resolveScope(container, req);
|
|
@@ -63,10 +116,14 @@ async function activitiesRoutes(app, container) {
|
|
|
63
116
|
schema: {
|
|
64
117
|
operationId: "updateModule",
|
|
65
118
|
tags,
|
|
66
|
-
summary: "Rename a module",
|
|
119
|
+
summary: "Rename a module (staff)",
|
|
120
|
+
description: "Staff only (owner, admin, instructor). Returns the course's modules.",
|
|
67
121
|
params: ModulePathParam,
|
|
68
122
|
body: UpdateModule,
|
|
69
|
-
response: {
|
|
123
|
+
response: {
|
|
124
|
+
200: ModuleList,
|
|
125
|
+
...refusals(403, 404)
|
|
126
|
+
}
|
|
70
127
|
},
|
|
71
128
|
handler: async (req) => {
|
|
72
129
|
const scope = await resolveScope(container, req);
|
|
@@ -80,9 +137,13 @@ async function activitiesRoutes(app, container) {
|
|
|
80
137
|
schema: {
|
|
81
138
|
operationId: "deleteModule",
|
|
82
139
|
tags,
|
|
83
|
-
summary: "Delete a module",
|
|
140
|
+
summary: "Delete a module (staff)",
|
|
141
|
+
description: "Staff only (owner, admin, instructor). Returns the course's modules.",
|
|
84
142
|
params: ModulePathParam,
|
|
85
|
-
response: {
|
|
143
|
+
response: {
|
|
144
|
+
200: ModuleList,
|
|
145
|
+
...refusals(403, 404)
|
|
146
|
+
}
|
|
86
147
|
},
|
|
87
148
|
handler: async (req) => {
|
|
88
149
|
const scope = await resolveScope(container, req);
|
|
@@ -96,10 +157,14 @@ async function activitiesRoutes(app, container) {
|
|
|
96
157
|
schema: {
|
|
97
158
|
operationId: "reorderActivities",
|
|
98
159
|
tags,
|
|
99
|
-
summary: "Reorder activities in a module",
|
|
160
|
+
summary: "Reorder the activities in a module (staff)",
|
|
161
|
+
description: "Staff only (owner, admin, instructor). Send every activity id of the module once (409 otherwise). Returns the course's modules.",
|
|
100
162
|
params: ModulePathParam,
|
|
101
163
|
body: ReorderInput,
|
|
102
|
-
response: {
|
|
164
|
+
response: {
|
|
165
|
+
200: ModuleList,
|
|
166
|
+
...refusals(403, 404, 409)
|
|
167
|
+
}
|
|
103
168
|
},
|
|
104
169
|
handler: async (req) => {
|
|
105
170
|
const scope = await resolveScope(container, req);
|
|
@@ -113,10 +178,14 @@ async function activitiesRoutes(app, container) {
|
|
|
113
178
|
schema: {
|
|
114
179
|
operationId: "createActivity",
|
|
115
180
|
tags,
|
|
116
|
-
summary: "Add an activity",
|
|
181
|
+
summary: "Add an activity (staff)",
|
|
182
|
+
description: "Staff only (owner, admin, instructor). Records the library files the activity uses; each must be a ready library file (409 otherwise). Returns the course's modules.",
|
|
117
183
|
params: ModulePathParam,
|
|
118
184
|
body: SaveActivity,
|
|
119
|
-
response: {
|
|
185
|
+
response: {
|
|
186
|
+
200: ModuleList,
|
|
187
|
+
...refusals(403, 404, 409)
|
|
188
|
+
}
|
|
120
189
|
},
|
|
121
190
|
handler: async (req) => {
|
|
122
191
|
const scope = await resolveScope(container, req);
|
|
@@ -130,10 +199,14 @@ async function activitiesRoutes(app, container) {
|
|
|
130
199
|
schema: {
|
|
131
200
|
operationId: "updateActivity",
|
|
132
201
|
tags,
|
|
133
|
-
summary: "Update an activity",
|
|
202
|
+
summary: "Update an activity (staff)",
|
|
203
|
+
description: "Staff only (owner, admin, instructor). Replaces its content and records the library files it uses; each must be a ready library file (409 otherwise). Returns the course's modules.",
|
|
134
204
|
params: ActivityPathParam,
|
|
135
205
|
body: SaveActivity,
|
|
136
|
-
response: {
|
|
206
|
+
response: {
|
|
207
|
+
200: ModuleList,
|
|
208
|
+
...refusals(403, 404, 409)
|
|
209
|
+
}
|
|
137
210
|
},
|
|
138
211
|
handler: async (req) => {
|
|
139
212
|
const scope = await resolveScope(container, req);
|
|
@@ -147,9 +220,13 @@ async function activitiesRoutes(app, container) {
|
|
|
147
220
|
schema: {
|
|
148
221
|
operationId: "deleteActivity",
|
|
149
222
|
tags,
|
|
150
|
-
summary: "Delete an activity",
|
|
223
|
+
summary: "Delete an activity (staff)",
|
|
224
|
+
description: "Staff only (owner, admin, instructor). Returns the course's modules.",
|
|
151
225
|
params: ActivityPathParam,
|
|
152
|
-
response: {
|
|
226
|
+
response: {
|
|
227
|
+
200: ModuleList,
|
|
228
|
+
...refusals(403, 404)
|
|
229
|
+
}
|
|
153
230
|
},
|
|
154
231
|
handler: async (req) => {
|
|
155
232
|
const scope = await resolveScope(container, req);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"activities.js","names":[],"sources":["../../../src/http/routes/activities.ts"],"sourcesContent":["// HTTP routes for course modules + activities. Write operations return the\n// course's full, reordered module list (how the editor re-renders). Nested under\n// courses. All require a session with an active organization; handlers resolve\n// the session's active org to the domain org id and scope every call by it.\nimport type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport {\n ActivityPathParam,\n CourseIdPathParam,\n CreateModule,\n ModuleList,\n ModulePathParam,\n ReorderInput,\n SaveActivity,\n UpdateModule,\n} from '../schemas/index.js';\nimport type { Container } from '../../app/container.js';\nimport { resolveScope } from '../scope.js';\n\nexport async function activitiesRoutes(app: FastifyInstance, container: Container): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n // Modules/activities are part of the content aggregate; grouped under the Courses tag.\n const content = container.content;\n const tags = ['Courses'];\n\n r.route({\n method: 'GET',\n url: '/api/courses/:courseId/modules',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listModules',\n tags,\n summary: \"List a course's modules\",\n params: CourseIdPathParam,\n response: { 200: ModuleList },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.listCourseModules(scope.orgId, req.params.courseId);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/courses/:courseId/modules',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'createModule',\n tags,\n summary: 'Add a module',\n params: CourseIdPathParam,\n body: CreateModule,\n response: { 200: ModuleList },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.createModule(scope.orgId, req.params.courseId, req.body.title);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/courses/:courseId/modules/reorder',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'reorderModules',\n tags,\n summary: 'Reorder modules',\n params: CourseIdPathParam,\n body: ReorderInput,\n response: { 200: ModuleList },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.reorderModules(scope.orgId, req.params.courseId, req.body.orderedIds);\n },\n });\n\n r.route({\n method: 'PATCH',\n url: '/api/courses/:courseId/modules/:moduleId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'updateModule',\n tags,\n summary: 'Rename a module',\n params: ModulePathParam,\n body: UpdateModule,\n response: { 200: ModuleList },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.updateModule(\n scope.orgId,\n req.params.courseId,\n req.params.moduleId,\n req.body.title,\n );\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/courses/:courseId/modules/:moduleId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'deleteModule',\n tags,\n summary: 'Delete a module',\n params: ModulePathParam,\n response: { 200: ModuleList },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.deleteModule(scope.orgId, req.params.courseId, req.params.moduleId);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/courses/:courseId/modules/:moduleId/activities/reorder',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'reorderActivities',\n tags,\n summary: 'Reorder activities in a module',\n params: ModulePathParam,\n body: ReorderInput,\n response: { 200: ModuleList },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.reorderActivities(\n scope.orgId,\n req.params.courseId,\n req.params.moduleId,\n req.body.orderedIds,\n );\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/courses/:courseId/modules/:moduleId/activities',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'createActivity',\n tags,\n summary: 'Add an activity',\n params: ModulePathParam,\n body: SaveActivity,\n response: { 200: ModuleList },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.saveActivity(scope.orgId, req.params.courseId, req.params.moduleId, req.body);\n },\n });\n\n r.route({\n method: 'PATCH',\n url: '/api/courses/:courseId/modules/:moduleId/activities/:activityId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'updateActivity',\n tags,\n summary: 'Update an activity',\n params: ActivityPathParam,\n body: SaveActivity,\n response: { 200: ModuleList },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.saveActivity(\n scope.orgId,\n req.params.courseId,\n req.params.moduleId,\n req.body,\n req.params.activityId,\n );\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/courses/:courseId/modules/:moduleId/activities/:activityId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'deleteActivity',\n tags,\n summary: 'Delete an activity',\n params: ActivityPathParam,\n response: { 200: ModuleList },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.deleteActivity(\n scope.orgId,\n req.params.courseId,\n req.params.moduleId,\n req.params.activityId,\n );\n },\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"activities.js","names":[],"sources":["../../../src/http/routes/activities.ts"],"sourcesContent":["// HTTP routes for course modules + activities. Write operations return the\n// course's full, reordered module list (how the editor re-renders). Nested under\n// courses. All require a session with an active organization; handlers resolve\n// the session's active org to the domain org id and scope every call by it.\nimport type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport {\n ActivityAssetList,\n ActivityList,\n ActivityPathParam,\n CourseIdPathParam,\n CreateModule,\n ModuleList,\n ModulePathParam,\n ReorderInput,\n SaveActivity,\n UpdateModule,\n refusals,\n} from '../schemas/index.js';\nimport type { Container } from '../../app/container.js';\nimport { resolveScope } from '../scope.js';\n\nexport async function activitiesRoutes(app: FastifyInstance, container: Container): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n // Modules/activities are part of the content aggregate; grouped under the Courses tag.\n const content = container.content;\n const tags = ['Content'];\n\n r.route({\n method: 'GET',\n url: '/api/courses/:courseId/modules',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listModules',\n tags,\n summary: \"List a course's modules (staff)\",\n description:\n 'Staff only (owner, admin, instructor). Modules in order, each with its activities.',\n params: CourseIdPathParam,\n response: { 200: ModuleList, ...refusals(403) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.listCourseModules(scope.orgId, req.params.courseId);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/courses/:courseId/activities',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listActivities',\n tags,\n summary: \"List a course's activities (staff)\",\n description: 'Staff only (owner, admin, instructor). Every activity, published or not.',\n params: CourseIdPathParam,\n response: { 200: ActivityList, ...refusals(403) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.listCourseActivityViews(scope.orgId, req.params.courseId);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/courses/:courseId/activity-assets',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listActivityAssets',\n tags,\n summary: 'List the library files each activity of a course uses (staff)',\n description:\n 'Staff only (owner, admin, instructor). One row per activity and file, as recorded when the activity was saved.',\n params: CourseIdPathParam,\n response: { 200: ActivityAssetList, ...refusals(403) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.listCourseActivityAssets(scope.orgId, req.params.courseId);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/courses/:courseId/modules',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'createModule',\n tags,\n summary: 'Add a module (staff)',\n description:\n \"Staff only (owner, admin, instructor). Added last. Returns the course's modules.\",\n params: CourseIdPathParam,\n body: CreateModule,\n response: { 200: ModuleList, ...refusals(403) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.createModule(scope.orgId, req.params.courseId, req.body.title);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/courses/:courseId/modules/reorder',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'reorderModules',\n tags,\n summary: \"Reorder a course's modules (staff)\",\n description:\n \"Staff only (owner, admin, instructor). Ids that are not modules of the course are ignored. Returns the course's modules.\",\n params: CourseIdPathParam,\n body: ReorderInput,\n response: { 200: ModuleList, ...refusals(403) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.reorderModules(scope.orgId, req.params.courseId, req.body.orderedIds);\n },\n });\n\n r.route({\n method: 'PATCH',\n url: '/api/courses/:courseId/modules/:moduleId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'updateModule',\n tags,\n summary: 'Rename a module (staff)',\n description: \"Staff only (owner, admin, instructor). Returns the course's modules.\",\n params: ModulePathParam,\n body: UpdateModule,\n response: { 200: ModuleList, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.updateModule(\n scope.orgId,\n req.params.courseId,\n req.params.moduleId,\n req.body.title,\n );\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/courses/:courseId/modules/:moduleId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'deleteModule',\n tags,\n summary: 'Delete a module (staff)',\n description: \"Staff only (owner, admin, instructor). Returns the course's modules.\",\n params: ModulePathParam,\n response: { 200: ModuleList, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.deleteModule(scope.orgId, req.params.courseId, req.params.moduleId);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/courses/:courseId/modules/:moduleId/activities/reorder',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'reorderActivities',\n tags,\n summary: 'Reorder the activities in a module (staff)',\n description:\n \"Staff only (owner, admin, instructor). Send every activity id of the module once (409 otherwise). Returns the course's modules.\",\n params: ModulePathParam,\n body: ReorderInput,\n response: { 200: ModuleList, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.reorderActivities(\n scope.orgId,\n req.params.courseId,\n req.params.moduleId,\n req.body.orderedIds,\n );\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/courses/:courseId/modules/:moduleId/activities',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'createActivity',\n tags,\n summary: 'Add an activity (staff)',\n description:\n \"Staff only (owner, admin, instructor). Records the library files the activity uses; each must be a ready library file (409 otherwise). Returns the course's modules.\",\n params: ModulePathParam,\n body: SaveActivity,\n response: { 200: ModuleList, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.saveActivity(scope.orgId, req.params.courseId, req.params.moduleId, req.body);\n },\n });\n\n r.route({\n method: 'PATCH',\n url: '/api/courses/:courseId/modules/:moduleId/activities/:activityId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'updateActivity',\n tags,\n summary: 'Update an activity (staff)',\n description:\n \"Staff only (owner, admin, instructor). Replaces its content and records the library files it uses; each must be a ready library file (409 otherwise). Returns the course's modules.\",\n params: ActivityPathParam,\n body: SaveActivity,\n response: { 200: ModuleList, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.saveActivity(\n scope.orgId,\n req.params.courseId,\n req.params.moduleId,\n req.body,\n req.params.activityId,\n );\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/courses/:courseId/modules/:moduleId/activities/:activityId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'deleteActivity',\n tags,\n summary: 'Delete an activity (staff)',\n description: \"Staff only (owner, admin, instructor). Returns the course's modules.\",\n params: ActivityPathParam,\n response: { 200: ModuleList, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const scope = await resolveScope(container, req);\n return content.deleteActivity(\n scope.orgId,\n req.params.courseId,\n req.params.moduleId,\n req.params.activityId,\n );\n },\n });\n}\n"],"mappings":"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"}
|