@studious-lms/server 1.13.0 → 1.15.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/.dockerignore +28 -0
- package/.env.example +5 -0
- package/.github/workflows/deploy.yml +123 -0
- package/Dockerfile +54 -0
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/instrument.js +3 -3
- package/dist/instrument.js.map +1 -1
- package/dist/lib/config/cors.d.ts.map +1 -1
- package/dist/lib/config/cors.js +31 -11
- package/dist/lib/config/cors.js.map +1 -1
- package/dist/lib/config/env.d.ts +17 -0
- package/dist/lib/config/env.d.ts.map +1 -1
- package/dist/lib/config/env.js +8 -2
- package/dist/lib/config/env.js.map +1 -1
- package/dist/lib/googleCloudStorage.d.ts +10 -0
- package/dist/lib/googleCloudStorage.d.ts.map +1 -1
- package/dist/lib/googleCloudStorage.js +22 -2
- package/dist/lib/googleCloudStorage.js.map +1 -1
- package/dist/lib/inferDocumentFormat.d.ts +10 -0
- package/dist/lib/inferDocumentFormat.d.ts.map +1 -0
- package/dist/lib/inferDocumentFormat.js +48 -0
- package/dist/lib/inferDocumentFormat.js.map +1 -0
- package/dist/lib/legal.d.ts +3 -0
- package/dist/lib/legal.d.ts.map +1 -0
- package/dist/lib/legal.js +6 -0
- package/dist/lib/legal.js.map +1 -0
- package/dist/lib/prisma.d.ts +104 -5
- package/dist/lib/prisma.d.ts.map +1 -1
- package/dist/lib/prisma.js +33 -2
- package/dist/lib/prisma.js.map +1 -1
- package/dist/models/agenda.d.ts +20 -20
- package/dist/models/announcement.d.ts +211 -101
- package/dist/models/announcement.d.ts.map +1 -1
- package/dist/models/assignment.d.ts +560 -362
- package/dist/models/assignment.d.ts.map +1 -1
- package/dist/models/attendance.d.ts +197 -71
- package/dist/models/attendance.d.ts.map +1 -1
- package/dist/models/auth.d.ts +356 -114
- package/dist/models/auth.d.ts.map +1 -1
- package/dist/models/auth.js +4 -2
- package/dist/models/auth.js.map +1 -1
- package/dist/models/class.d.ts +327 -201
- package/dist/models/class.d.ts.map +1 -1
- package/dist/models/class.js +2 -2
- package/dist/models/class.js.map +1 -1
- package/dist/models/cloudStorage.d.ts +146 -56
- package/dist/models/cloudStorage.d.ts.map +1 -1
- package/dist/models/comment.d.ts +262 -110
- package/dist/models/comment.d.ts.map +1 -1
- package/dist/models/conversation.d.ts +206 -80
- package/dist/models/conversation.d.ts.map +1 -1
- package/dist/models/department.d.ts +196 -70
- package/dist/models/department.d.ts.map +1 -1
- package/dist/models/event.d.ts +305 -141
- package/dist/models/event.d.ts.map +1 -1
- package/dist/models/file.d.ts +422 -272
- package/dist/models/file.d.ts.map +1 -1
- package/dist/models/folder.d.ts +433 -181
- package/dist/models/folder.d.ts.map +1 -1
- package/dist/models/labChat.d.ts +205 -79
- package/dist/models/labChat.d.ts.map +1 -1
- package/dist/models/marketing.d.ts +79 -38
- package/dist/models/marketing.d.ts.map +1 -1
- package/dist/models/marketing.js +12 -4
- package/dist/models/marketing.js.map +1 -1
- package/dist/models/message.d.ts +97 -43
- package/dist/models/message.d.ts.map +1 -1
- package/dist/models/newtonChat.d.ts +84 -30
- package/dist/models/newtonChat.d.ts.map +1 -1
- package/dist/models/notification.d.ts +57 -21
- package/dist/models/notification.d.ts.map +1 -1
- package/dist/models/school.d.ts +349 -133
- package/dist/models/school.d.ts.map +1 -1
- package/dist/models/section.d.ts +216 -72
- package/dist/models/section.d.ts.map +1 -1
- package/dist/models/tag.d.ts +156 -48
- package/dist/models/tag.d.ts.map +1 -1
- package/dist/models/user.d.ts +82 -28
- package/dist/models/user.d.ts.map +1 -1
- package/dist/models/worksheet.d.ts +1032 -423
- package/dist/models/worksheet.d.ts.map +1 -1
- package/dist/models/worksheet.js +8 -2
- package/dist/models/worksheet.js.map +1 -1
- package/dist/pipelines/aiLabChat.d.ts +7 -9
- package/dist/pipelines/aiLabChat.d.ts.map +1 -1
- package/dist/pipelines/aiLabChat.js +194 -125
- package/dist/pipelines/aiLabChat.js.map +1 -1
- package/dist/pipelines/aiLabChatContract.d.ts +233 -389
- package/dist/pipelines/aiLabChatContract.d.ts.map +1 -1
- package/dist/pipelines/aiLabChatContract.js +54 -70
- package/dist/pipelines/aiLabChatContract.js.map +1 -1
- package/dist/pipelines/aiNewtonChat.d.ts.map +1 -1
- package/dist/pipelines/aiNewtonChat.js +41 -41
- package/dist/pipelines/aiNewtonChat.js.map +1 -1
- package/dist/pipelines/gradeWorksheet.d.ts +8 -8
- package/dist/pipelines/labChatPrompt.d.ts +18 -11
- package/dist/pipelines/labChatPrompt.d.ts.map +1 -1
- package/dist/pipelines/labChatPrompt.js +93 -75
- package/dist/pipelines/labChatPrompt.js.map +1 -1
- package/dist/pipelines/pdfToWorksheet.d.ts +1 -1
- package/dist/routers/_app.d.ts +2601 -2151
- package/dist/routers/_app.d.ts.map +1 -1
- package/dist/routers/_app.js +4 -2
- package/dist/routers/_app.js.map +1 -1
- package/dist/routers/admin.d.ts +13 -13
- package/dist/routers/agenda.d.ts +18 -18
- package/dist/routers/announcement.d.ts +60 -60
- package/dist/routers/assignment.d.ts +393 -383
- package/dist/routers/assignment.d.ts.map +1 -1
- package/dist/routers/attendance.d.ts +10 -10
- package/dist/routers/auth.d.ts +4 -2
- package/dist/routers/auth.d.ts.map +1 -1
- package/dist/routers/auth.js +15 -2
- package/dist/routers/auth.js.map +1 -1
- package/dist/routers/class.d.ts +157 -153
- package/dist/routers/class.d.ts.map +1 -1
- package/dist/routers/comment.d.ts +18 -18
- package/dist/routers/conversation.d.ts +11 -11
- package/dist/routers/department.d.ts +34 -34
- package/dist/routers/discussion.d.ts +68 -56
- package/dist/routers/discussion.d.ts.map +1 -1
- package/dist/routers/discussion.js +6 -2
- package/dist/routers/discussion.js.map +1 -1
- package/dist/routers/embedding.d.ts +73 -0
- package/dist/routers/embedding.d.ts.map +1 -0
- package/dist/routers/embedding.js +151 -0
- package/dist/routers/embedding.js.map +1 -0
- package/dist/routers/event.d.ts +57 -55
- package/dist/routers/event.d.ts.map +1 -1
- package/dist/routers/file.d.ts +14 -14
- package/dist/routers/folder.d.ts +38 -38
- package/dist/routers/labChat.d.ts +16 -16
- package/dist/routers/marketing.d.ts +1 -14
- package/dist/routers/marketing.d.ts.map +1 -1
- package/dist/routers/message.d.ts +13 -13
- package/dist/routers/newtonChat.d.ts +4 -4
- package/dist/routers/notifications.d.ts +5 -5
- package/dist/routers/permissions.d.ts +14 -14
- package/dist/routers/school.d.ts +59 -55
- package/dist/routers/school.d.ts.map +1 -1
- package/dist/routers/search.d.ts +22 -1
- package/dist/routers/search.d.ts.map +1 -1
- package/dist/routers/search.js +9 -3
- package/dist/routers/search.js.map +1 -1
- package/dist/routers/section.d.ts +4 -4
- package/dist/routers/studentProgress.d.ts +1 -1
- package/dist/routers/tag.d.ts +7 -7
- package/dist/routers/user.d.ts +99 -10
- package/dist/routers/user.d.ts.map +1 -1
- package/dist/routers/user.js +19 -2
- package/dist/routers/user.js.map +1 -1
- package/dist/routers/worksheet.d.ts +93 -55
- package/dist/routers/worksheet.d.ts.map +1 -1
- package/dist/routers/worksheet.js +26 -2
- package/dist/routers/worksheet.js.map +1 -1
- package/dist/routes/aiStream.d.ts +2 -0
- package/dist/routes/aiStream.d.ts.map +1 -0
- package/dist/routes/aiStream.js +726 -0
- package/dist/routes/aiStream.js.map +1 -0
- package/dist/seedDatabase.d.ts +3 -1
- package/dist/seedDatabase.d.ts.map +1 -1
- package/dist/seedDatabase.js +6 -6
- package/dist/seedDatabase.js.map +1 -1
- package/dist/services/adminInstitution.d.ts +8 -8
- package/dist/services/adminRunJob.d.ts +4 -4
- package/dist/services/agenda.d.ts +18 -18
- package/dist/services/aiChatStream.d.ts +88 -0
- package/dist/services/aiChatStream.d.ts.map +1 -0
- package/dist/services/aiChatStream.js +254 -0
- package/dist/services/aiChatStream.js.map +1 -0
- package/dist/services/aiModifierTools.d.ts +16 -0
- package/dist/services/aiModifierTools.d.ts.map +1 -0
- package/dist/services/aiModifierTools.js +274 -0
- package/dist/services/aiModifierTools.js.map +1 -0
- package/dist/services/aiProposalTools.d.ts +32 -0
- package/dist/services/aiProposalTools.d.ts.map +1 -0
- package/dist/services/aiProposalTools.js +207 -0
- package/dist/services/aiProposalTools.js.map +1 -0
- package/dist/services/aiStream.d.ts +22 -0
- package/dist/services/aiStream.d.ts.map +1 -0
- package/dist/services/aiStream.js +142 -0
- package/dist/services/aiStream.js.map +1 -0
- package/dist/services/aiTools.d.ts +16 -0
- package/dist/services/aiTools.d.ts.map +1 -0
- package/dist/services/aiTools.js +271 -0
- package/dist/services/aiTools.js.map +1 -0
- package/dist/services/announcement.d.ts +42 -42
- package/dist/services/announcement.d.ts.map +1 -1
- package/dist/services/announcement.js +7 -2
- package/dist/services/announcement.js.map +1 -1
- package/dist/services/assignment.d.ts +355 -345
- package/dist/services/assignment.d.ts.map +1 -1
- package/dist/services/assignment.js +30 -9
- package/dist/services/assignment.js.map +1 -1
- package/dist/services/attendance.d.ts +10 -10
- package/dist/services/auth.d.ts +4 -2
- package/dist/services/auth.d.ts.map +1 -1
- package/dist/services/auth.js +13 -4
- package/dist/services/auth.js.map +1 -1
- package/dist/services/class.d.ts +146 -142
- package/dist/services/class.d.ts.map +1 -1
- package/dist/services/class.js +24 -4
- package/dist/services/class.js.map +1 -1
- package/dist/services/comment.d.ts +18 -18
- package/dist/services/conversation.d.ts +11 -11
- package/dist/services/department.d.ts +33 -33
- package/dist/services/discussion.d.ts +58 -58
- package/dist/services/discussion.d.ts.map +1 -1
- package/dist/services/discussion.js +15 -8
- package/dist/services/discussion.js.map +1 -1
- package/dist/services/discussionSummary.d.ts +21 -0
- package/dist/services/discussionSummary.d.ts.map +1 -0
- package/dist/services/discussionSummary.js +179 -0
- package/dist/services/discussionSummary.js.map +1 -0
- package/dist/services/embedding.d.ts +85 -0
- package/dist/services/embedding.d.ts.map +1 -0
- package/dist/services/embedding.js +372 -0
- package/dist/services/embedding.js.map +1 -0
- package/dist/services/event.d.ts +55 -53
- package/dist/services/event.d.ts.map +1 -1
- package/dist/services/file.d.ts +28 -28
- package/dist/services/folder.d.ts +36 -36
- package/dist/services/folder.d.ts.map +1 -1
- package/dist/services/folder.js +32 -2
- package/dist/services/folder.js.map +1 -1
- package/dist/services/labChat.d.ts +16 -16
- package/dist/services/marketing.d.ts +2 -15
- package/dist/services/marketing.d.ts.map +1 -1
- package/dist/services/marketing.js +5 -5
- package/dist/services/marketing.js.map +1 -1
- package/dist/services/message.d.ts +11 -11
- package/dist/services/message.d.ts.map +1 -1
- package/dist/services/message.js +2 -2
- package/dist/services/message.js.map +1 -1
- package/dist/services/newtonChat.d.ts +4 -4
- package/dist/services/notification.d.ts +5 -5
- package/dist/services/notification.d.ts.map +1 -1
- package/dist/services/openaiDocumentGen.d.ts +37 -0
- package/dist/services/openaiDocumentGen.d.ts.map +1 -0
- package/dist/services/openaiDocumentGen.js +262 -0
- package/dist/services/openaiDocumentGen.js.map +1 -0
- package/dist/services/permissions.d.ts +14 -14
- package/dist/services/school.d.ts +54 -50
- package/dist/services/school.d.ts.map +1 -1
- package/dist/services/search.d.ts +13 -1
- package/dist/services/search.d.ts.map +1 -1
- package/dist/services/search.js +145 -2
- package/dist/services/search.js.map +1 -1
- package/dist/services/section.d.ts +3 -3
- package/dist/services/tag.d.ts +4 -4
- package/dist/services/user.d.ts +4 -4
- package/dist/services/user.d.ts.map +1 -1
- package/dist/services/user.js +10 -15
- package/dist/services/user.js.map +1 -1
- package/dist/services/userPrivacy.d.ts +86 -0
- package/dist/services/userPrivacy.d.ts.map +1 -0
- package/dist/services/userPrivacy.js +184 -0
- package/dist/services/userPrivacy.js.map +1 -0
- package/dist/services/worksheet.d.ts +86 -57
- package/dist/services/worksheet.d.ts.map +1 -1
- package/dist/services/worksheet.js +57 -5
- package/dist/services/worksheet.js.map +1 -1
- package/dist/utils/email.d.ts.map +1 -1
- package/dist/utils/email.js +7 -3
- package/dist/utils/email.js.map +1 -1
- package/dist/utils/streamBroadcast.d.ts +11 -0
- package/dist/utils/streamBroadcast.d.ts.map +1 -0
- package/dist/utils/streamBroadcast.js +32 -0
- package/dist/utils/streamBroadcast.js.map +1 -0
- package/dist/workers/connection.d.ts +15 -0
- package/dist/workers/connection.d.ts.map +1 -1
- package/dist/workers/connection.js +20 -2
- package/dist/workers/connection.js.map +1 -1
- package/dist/workers/index.js +4 -2
- package/dist/workers/index.js.map +1 -1
- package/dist/workers/processors/createRunJobWorker.d.ts.map +1 -1
- package/dist/workers/processors/createRunJobWorker.js +31 -8
- package/dist/workers/processors/createRunJobWorker.js.map +1 -1
- package/dist/workers/processors/embedContent.d.ts +8 -0
- package/dist/workers/processors/embedContent.d.ts.map +1 -0
- package/dist/workers/processors/embedContent.js +67 -0
- package/dist/workers/processors/embedContent.js.map +1 -0
- package/dist/workers/queues.d.ts +6 -0
- package/dist/workers/queues.d.ts.map +1 -1
- package/dist/workers/queues.js +5 -3
- package/dist/workers/queues.js.map +1 -1
- package/package.json +5 -1
- package/prisma/migrations/20260609215135_init/migration.sql +1412 -0
- package/prisma/migrations/20260610130000_add_worksheet_tags/migration.sql +13 -0
- package/prisma/migrations/20260610140000_expand_embedding_source_types/migration.sql +4 -0
- package/prisma/migrations/20260611120000_add_user_terms_acceptance/migration.sql +3 -0
- package/prisma/schema.prisma +44 -7
- package/src/index.ts +4 -0
- package/src/instrument.ts +1 -1
- package/src/lib/config/cors.ts +32 -9
- package/src/lib/config/env.ts +6 -0
- package/src/lib/googleCloudStorage.ts +21 -0
- package/src/lib/inferDocumentFormat.ts +58 -0
- package/src/lib/legal.ts +2 -0
- package/src/lib/prisma.ts +40 -1
- package/src/models/auth.ts +4 -0
- package/src/models/class.ts +3 -2
- package/src/models/marketing.ts +10 -2
- package/src/models/worksheet.ts +5 -2
- package/src/pipelines/aiLabChat.ts +245 -146
- package/src/pipelines/aiLabChatContract.ts +59 -69
- package/src/pipelines/aiNewtonChat.ts +46 -43
- package/src/pipelines/labChatPrompt.ts +115 -90
- package/src/routers/_app.ts +2 -0
- package/src/routers/auth.ts +13 -0
- package/src/routers/discussion.ts +7 -0
- package/src/routers/embedding.ts +164 -0
- package/src/routers/search.ts +10 -1
- package/src/routers/user.ts +26 -0
- package/src/routers/worksheet.ts +27 -0
- package/src/routes/aiStream.ts +827 -0
- package/src/seedDatabase.ts +4 -4
- package/src/services/aiChatStream.ts +341 -0
- package/src/services/aiModifierTools.ts +341 -0
- package/src/services/aiProposalTools.ts +274 -0
- package/src/services/aiStream.ts +175 -0
- package/src/services/aiTools.ts +290 -0
- package/src/services/announcement.ts +7 -0
- package/src/services/assignment.ts +31 -7
- package/src/services/auth.ts +14 -2
- package/src/services/class.ts +27 -2
- package/src/services/discussion.ts +22 -8
- package/src/services/discussionSummary.ts +226 -0
- package/src/services/embedding.ts +446 -0
- package/src/services/folder.ts +31 -0
- package/src/services/marketing.ts +3 -3
- package/src/services/message.ts +2 -2
- package/src/services/openaiDocumentGen.ts +319 -0
- package/src/services/search.ts +163 -1
- package/src/services/user.ts +9 -17
- package/src/services/userPrivacy.ts +196 -0
- package/src/services/worksheet.ts +77 -3
- package/src/utils/email.ts +5 -1
- package/src/utils/streamBroadcast.ts +48 -0
- package/src/workers/connection.ts +19 -0
- package/src/workers/index.ts +2 -0
- package/src/workers/processors/createRunJobWorker.ts +32 -6
- package/src/workers/processors/embedContent.ts +86 -0
- package/src/workers/queues.ts +5 -1
- package/tests/helpers/registerInput.ts +20 -0
- package/tests/integration/globalSetup.ts +10 -18
- package/tests/integration/routers/auth.test.ts +13 -18
- package/tests/unit/lib/inferDocumentFormat.test.ts +33 -0
- package/tests/unit/pipelines/aiLabChatContract.test.ts +38 -21
- package/tests/unit/pipelines/labChatPrompt.test.ts +23 -36
- package/tests/unit/services/aiChatStream.test.ts +92 -0
- package/tests/unit/services/openaiDocumentGen.test.ts +65 -0
- package/prisma/migrations/20250807062924_init/migration.sql +0 -436
- package/prisma/migrations/20250919063704_init2/migration.sql +0 -24
- package/prisma/migrations/20250920143543_add_profile_fields/migration.sql +0 -15
- package/prisma/migrations/20250922165147_add_chat_models/migration.sql +0 -68
- package/prisma/migrations/20250922165314_add_chat_roles/migration.sql +0 -5
- package/prisma/migrations/20250922171242_refactor_notification_system/migration.sql +0 -20
- package/prisma/migrations/20250922172208_add_mentions_system/migration.sql +0 -21
- package/prisma/migrations/20250925072732_add_lab_chat_system/migration.sql +0 -25
- package/prisma/migrations/20251020151505_add_upload_tracking_fields/migration.sql +0 -57
- package/prisma/migrations/20251109122857_annuoncements_comments/migration.sql +0 -30
- package/prisma/migrations/20251109135555_reactions_announcements_comments/migration.sql +0 -35
- package/prisma/migrations/20260410124000_add_submission_recommendation_state/migration.sql +0 -14
- package/prisma/migrations/20260415103500_add_session_type/migration.sql +0 -33
- package/prisma/migrations/20260415133000_add_ai_usage_logs/migration.sql +0 -19
- package/prisma/migrations/20260417083000_add_conversation_member_hidden_at/migration.sql +0 -2
- package/prisma/migrations/20260502230500_assignment_submission_comments/migration.sql +0 -60
- package/prisma/migrations/20260504071500_school_memberships/migration.sql +0 -81
- package/prisma/migrations/20260506162500_consolidate_run_job_and_unify_job_status/migration.sql +0 -166
- package/prisma/migrations/20260509220000_institution_overhaul/migration.sql +0 -184
- package/prisma/migrations/20260510170000_add_folder_permissions/migration.sql +0 -93
- package/prisma/migrations/20260510183000_add_discussions/migration.sql +0 -151
- /package/.github/workflows/{npm.yml → npm-publish.yml} +0 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Background worker for embedding content into pgvector.
|
|
3
|
+
* Handles indexing of files, assignments, worksheets, announcements,
|
|
4
|
+
* discussions, submissions, and syllabi.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="fbd2bf1a-1ff1-5ee4-867c-95f9eebe5980")}catch(e){}}();
|
|
8
|
+
import { createRunJobWorker } from './createRunJobWorker.js';
|
|
9
|
+
import { indexAssignment, indexWorksheet, indexAnnouncement, indexDiscussion, indexSubmission, indexSyllabus, indexFile, indexContent, } from '../../services/embedding.js';
|
|
10
|
+
import { prisma } from '../../lib/prisma.js';
|
|
11
|
+
import { logger } from '../../utils/logger.js';
|
|
12
|
+
export const embedContentWorker = createRunJobWorker({
|
|
13
|
+
type: 'EMBED_CONTENT',
|
|
14
|
+
workerOptions: {
|
|
15
|
+
concurrency: 3,
|
|
16
|
+
limiter: { max: 10, duration: 60000 },
|
|
17
|
+
},
|
|
18
|
+
run: async ({ classId, sourceType, sourceId }) => {
|
|
19
|
+
const typedSourceType = sourceType;
|
|
20
|
+
switch (typedSourceType) {
|
|
21
|
+
case 'ASSIGNMENT':
|
|
22
|
+
await indexAssignment(classId, sourceId);
|
|
23
|
+
break;
|
|
24
|
+
case 'WORKSHEET':
|
|
25
|
+
await indexWorksheet(classId, sourceId);
|
|
26
|
+
break;
|
|
27
|
+
case 'ANNOUNCEMENT':
|
|
28
|
+
await indexAnnouncement(classId, sourceId);
|
|
29
|
+
break;
|
|
30
|
+
case 'FILE':
|
|
31
|
+
await indexFile(classId, sourceId);
|
|
32
|
+
break;
|
|
33
|
+
case 'DISCUSSION':
|
|
34
|
+
await indexDiscussion(classId, sourceId);
|
|
35
|
+
break;
|
|
36
|
+
case 'SUBMISSION':
|
|
37
|
+
await indexSubmission(classId, sourceId);
|
|
38
|
+
break;
|
|
39
|
+
case 'SYLLABUS':
|
|
40
|
+
await indexSyllabus(sourceId);
|
|
41
|
+
break;
|
|
42
|
+
case 'SECTION': {
|
|
43
|
+
const section = await prisma.section.findUnique({
|
|
44
|
+
where: { id: sourceId },
|
|
45
|
+
select: { name: true },
|
|
46
|
+
});
|
|
47
|
+
if (!section) {
|
|
48
|
+
return { skipped: true, reason: 'section_not_found' };
|
|
49
|
+
}
|
|
50
|
+
await indexContent({
|
|
51
|
+
classId,
|
|
52
|
+
sourceType: 'SECTION',
|
|
53
|
+
sourceId,
|
|
54
|
+
text: `Section: ${section.name}`,
|
|
55
|
+
metadata: { name: section.name },
|
|
56
|
+
});
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
default:
|
|
60
|
+
logger.warn('Unknown embedding source type', { sourceType, sourceId });
|
|
61
|
+
return { skipped: true, reason: 'unknown_source_type' };
|
|
62
|
+
}
|
|
63
|
+
return { indexed: true, sourceType, sourceId };
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
//# sourceMappingURL=embedContent.js.map
|
|
67
|
+
//# debugId=fbd2bf1a-1ff1-5ee4-867c-95f9eebe5980
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedContent.js","sources":["workers/processors/embedContent.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Background worker for embedding content into pgvector.\n * Handles indexing of files, assignments, worksheets, announcements,\n * discussions, submissions, and syllabi.\n */\nimport { createRunJobWorker } from './createRunJobWorker.js';\nimport {\n indexAssignment,\n indexWorksheet,\n indexAnnouncement,\n indexDiscussion,\n indexSubmission,\n indexSyllabus,\n indexFile,\n indexContent,\n} from '../../services/embedding.js';\nimport { prisma } from '../../lib/prisma.js';\nimport { logger } from '../../utils/logger.js';\nimport type { EmbeddingSourceType } from '@prisma/client';\n\nexport const embedContentWorker = createRunJobWorker({\n type: 'EMBED_CONTENT',\n workerOptions: {\n concurrency: 3,\n limiter: { max: 10, duration: 60_000 },\n },\n run: async ({ classId, sourceType, sourceId }) => {\n const typedSourceType = sourceType as EmbeddingSourceType;\n\n switch (typedSourceType) {\n case 'ASSIGNMENT':\n await indexAssignment(classId, sourceId);\n break;\n\n case 'WORKSHEET':\n await indexWorksheet(classId, sourceId);\n break;\n\n case 'ANNOUNCEMENT':\n await indexAnnouncement(classId, sourceId);\n break;\n\n case 'FILE':\n await indexFile(classId, sourceId);\n break;\n\n case 'DISCUSSION':\n await indexDiscussion(classId, sourceId);\n break;\n\n case 'SUBMISSION':\n await indexSubmission(classId, sourceId);\n break;\n\n case 'SYLLABUS':\n await indexSyllabus(sourceId);\n break;\n\n case 'SECTION': {\n const section = await prisma.section.findUnique({\n where: { id: sourceId },\n select: { name: true },\n });\n\n if (!section) {\n return { skipped: true, reason: 'section_not_found' };\n }\n\n await indexContent({\n classId,\n sourceType: 'SECTION',\n sourceId,\n text: `Section: ${section.name}`,\n metadata: { name: section.name },\n });\n break;\n }\n\n default:\n logger.warn('Unknown embedding source type', { sourceType, sourceId });\n return { skipped: true, reason: 'unknown_source_type' };\n }\n\n return { indexed: true, sourceType, sourceId };\n },\n});\n"],"names":[],"mappings":"AAAA;;;;GAIG;;;AACH,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EACL,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,aAAa,EACb,SAAS,EACT,YAAY,GACb,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAG/C,MAAM,CAAC,MAAM,kBAAkB,GAAG,kBAAkB,CAAC;IACnD,IAAI,EAAE,eAAe;IACrB,aAAa,EAAE;QACb,WAAW,EAAE,CAAC;QACd,OAAO,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAM,EAAE;KACvC;IACD,GAAG,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC/C,MAAM,eAAe,GAAG,UAAiC,CAAC;QAE1D,QAAQ,eAAe,EAAE,CAAC;YACxB,KAAK,YAAY;gBACf,MAAM,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;gBACzC,MAAM;YAER,KAAK,WAAW;gBACd,MAAM,cAAc,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;gBACxC,MAAM;YAER,KAAK,cAAc;gBACjB,MAAM,iBAAiB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;gBAC3C,MAAM;YAER,KAAK,MAAM;gBACT,MAAM,SAAS,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;gBACnC,MAAM;YAER,KAAK,YAAY;gBACf,MAAM,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;gBACzC,MAAM;YAER,KAAK,YAAY;gBACf,MAAM,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;gBACzC,MAAM;YAER,KAAK,UAAU;gBACb,MAAM,aAAa,CAAC,QAAQ,CAAC,CAAC;gBAC9B,MAAM;YAER,KAAK,SAAS,CAAC,CAAC,CAAC;gBACf,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC;oBAC9C,KAAK,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE;oBACvB,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;iBACvB,CAAC,CAAC;gBAEH,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;gBACxD,CAAC;gBAED,MAAM,YAAY,CAAC;oBACjB,OAAO;oBACP,UAAU,EAAE,SAAS;oBACrB,QAAQ;oBACR,IAAI,EAAE,YAAY,OAAO,CAAC,IAAI,EAAE;oBAChC,QAAQ,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE;iBACjC,CAAC,CAAC;gBACH,MAAM;YACR,CAAC;YAED;gBACE,MAAM,CAAC,IAAI,CAAC,+BAA+B,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC;gBACvE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC;QAC5D,CAAC;QAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;IACjD,CAAC;CACF,CAAC,CAAC","debug_id":"fbd2bf1a-1ff1-5ee4-867c-95f9eebe5980"}
|
package/dist/workers/queues.d.ts
CHANGED
|
@@ -52,6 +52,12 @@ export type JobInputs = {
|
|
|
52
52
|
studentId: string;
|
|
53
53
|
message: string;
|
|
54
54
|
};
|
|
55
|
+
/** Embed content into pgvector for RAG search. */
|
|
56
|
+
EMBED_CONTENT: {
|
|
57
|
+
classId: string;
|
|
58
|
+
sourceType: string;
|
|
59
|
+
sourceId: string;
|
|
60
|
+
};
|
|
55
61
|
};
|
|
56
62
|
export declare const QUEUE_NAMES: Record<RunJobType, string>;
|
|
57
63
|
export interface EnqueueOptions {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queues.d.ts","sourceRoot":"/","sources":["workers/queues.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAS,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,EAAU,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAYzD;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB;;;;;OAKG;IACH,gBAAgB,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3E,eAAe,EAAE;QAAE,mBAAmB,EAAE,MAAM,CAAA;KAAE,CAAC;IACjD;;;;;OAKG;IACH,WAAW,EAAE;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D;;OAEG;IACH,cAAc,EAAE;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAChE,qBAAqB,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"queues.d.ts","sourceRoot":"/","sources":["workers/queues.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAS,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,EAAU,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAYzD;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB;;;;;OAKG;IACH,gBAAgB,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3E,eAAe,EAAE;QAAE,mBAAmB,EAAE,MAAM,CAAA;KAAE,CAAC;IACjD;;;;;OAKG;IACH,WAAW,EAAE;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D;;OAEG;IACH,cAAc,EAAE;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAChE,qBAAqB,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/E,kDAAkD;IAClD,aAAa,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1E,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAOlD,CAAC;AAqBF,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,qEAAqE;IACrE,UAAU,CAAC,EAAE,WAAW,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,CAAC,SAAS,UAAU,EACtD,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,EACnB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,aAAa,CAAC,CA2DxB;AAED;;;GAGG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAGpD"}
|
package/dist/workers/queues.js
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
* which is the entrypoint of the separate long-running worker process.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
10
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="8b504f67-acd8-5793-a500-d561724f9c85")}catch(e){}}();
|
|
11
11
|
import { Queue } from 'bullmq';
|
|
12
|
-
import { bullConnection } from './connection.js';
|
|
12
|
+
import { bullConnection, getBullPrefix } from './connection.js';
|
|
13
13
|
import { prisma } from '../lib/prisma.js';
|
|
14
14
|
import { logger } from '../utils/logger.js';
|
|
15
15
|
const DEFAULT_JOB_OPTIONS = {
|
|
@@ -24,6 +24,7 @@ export const QUEUE_NAMES = {
|
|
|
24
24
|
AI_LAB_CHAT: 'aiLabChat',
|
|
25
25
|
AI_NEWTON_CHAT: 'aiNewtonChat',
|
|
26
26
|
STUDENT_PROGRESS_CHAT: 'studentProgressChat',
|
|
27
|
+
EMBED_CONTENT: 'embedContent',
|
|
27
28
|
};
|
|
28
29
|
/**
|
|
29
30
|
* One Queue instance per type. Created lazily so that importing this module
|
|
@@ -35,6 +36,7 @@ function getQueue(type) {
|
|
|
35
36
|
if (!queue) {
|
|
36
37
|
queue = new Queue(QUEUE_NAMES[type], {
|
|
37
38
|
connection: bullConnection,
|
|
39
|
+
prefix: getBullPrefix(),
|
|
38
40
|
defaultJobOptions: DEFAULT_JOB_OPTIONS,
|
|
39
41
|
});
|
|
40
42
|
queueCache.set(type, queue);
|
|
@@ -116,4 +118,4 @@ export async function closeAllQueues() {
|
|
|
116
118
|
queueCache.clear();
|
|
117
119
|
}
|
|
118
120
|
//# sourceMappingURL=queues.js.map
|
|
119
|
-
//# debugId=
|
|
121
|
+
//# debugId=8b504f67-acd8-5793-a500-d561724f9c85
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queues.js","sources":["workers/queues.ts"],"sourceRoot":"/","sourcesContent":["/**\n * BullMQ queue producers and the `enqueueRunJob` helper.\n *\n * Producer side only — safe to import from HTTP routes / services running on\n * Vercel. Importing this file does NOT start any workers; workers live in\n * `src/workers/processors/*` and are wired up by `src/workers/index.ts`,\n * which is the entrypoint of the separate long-running worker process.\n */\nimport { Queue, type JobsOptions } from 'bullmq';\nimport { Prisma, type RunJobType } from '@prisma/client';\nimport { bullConnection } from './connection.js';\nimport { prisma } from '../lib/prisma.js';\nimport { logger } from '../utils/logger.js';\n\nconst DEFAULT_JOB_OPTIONS: JobsOptions = {\n attempts: 3,\n backoff: { type: 'exponential', delay: 5_000 },\n removeOnComplete: { age: 60 * 60 }, // keep completed jobs in Redis for 1h, then drop\n removeOnFail: { age: 24 * 60 * 60 }, // keep failed jobs for 24h for inspection\n};\n\n/**\n * Map RunJobType → (queue name, input payload shape).\n *\n * Add a new entry here whenever you introduce a new background job type.\n * The queue name string must match what the corresponding processor passes\n * to `new Worker(<name>, ...)`.\n */\nexport type JobInputs = {\n /**\n * `worksheetId` is the placeholder Worksheet row created synchronously by\n * the producer (so the client has an id to navigate to). The pipeline fills\n * that row in asynchronously and broadcasts progress on the per-worksheet\n * job channel.\n */\n PDF_TO_WORKSHEET: { gcsUrl: string; classId: string; worksheetId: string };\n GRADE_WORKSHEET: { worksheetResponseId: string };\n /**\n * `aiMessageId` is the placeholder AI Message row created synchronously by\n * the producer before enqueue (so the client renders a PENDING bubble in\n * the timeline). The pipeline fills in the content and flips the row to\n * COMPLETED / FAILED. Used for both intros and replies — single shape.\n */\n AI_LAB_CHAT: { conversationId: string; aiMessageId: string };\n /**\n * `aiMessageId` placeholder pattern, same as AI_LAB_CHAT — see above.\n */\n AI_NEWTON_CHAT: { conversationId: string; aiMessageId: string };\n STUDENT_PROGRESS_CHAT: { classId: string; studentId: string; message: string };\n};\n\nexport const QUEUE_NAMES: Record<RunJobType, string> = {\n PDF_TO_WORKSHEET: 'pdfToWorksheet',\n GRADE_WORKSHEET: 'gradeWorksheet',\n AI_LAB_CHAT: 'aiLabChat',\n AI_NEWTON_CHAT: 'aiNewtonChat',\n STUDENT_PROGRESS_CHAT: 'studentProgressChat',\n};\n\n/**\n * One Queue instance per type. Created lazily so that importing this module\n * does not eagerly open queues you may never use in a given runtime.\n */\nconst queueCache = new Map<RunJobType, Queue>();\n\nfunction getQueue(type: RunJobType): Queue {\n let queue = queueCache.get(type);\n if (!queue) {\n queue = new Queue(QUEUE_NAMES[type], {\n connection: bullConnection,\n defaultJobOptions: DEFAULT_JOB_OPTIONS,\n });\n queueCache.set(type, queue);\n }\n return queue;\n}\n\nexport interface EnqueueOptions {\n classId?: string | null;\n userId?: string | null;\n /** Override BullMQ job options (attempts, delay, priority, etc.). */\n jobOptions?: JobsOptions;\n}\n\nexport interface EnqueueResult {\n runJobId: string;\n bullJobId: string | null;\n}\n\n/**\n * Create a `RunJob` audit row, enqueue the BullMQ job, and link the two.\n *\n * Returns immediately — the actual work happens on the worker process. The\n * caller can return `runJobId` to the client and have them poll `getRunJob`\n * (or subscribe over Pusher) to track progress.\n *\n * IMPORTANT: do not call this inside a Prisma `$transaction`. If the outer\n * transaction rolls back after the BullMQ job is added, the worker will pick\n * up an orphaned job pointing at a non-existent RunJob row. Enqueue *after*\n * the transaction commits.\n */\nexport async function enqueueRunJob<T extends RunJobType>(\n type: T,\n input: JobInputs[T],\n options: EnqueueOptions = {},\n): Promise<EnqueueResult> {\n const runJob = await prisma.runJob.create({\n data: {\n type,\n status: 'PENDING',\n classId: options.classId ?? null,\n userId: options.userId ?? null,\n input: input as unknown as Prisma.InputJsonValue,\n },\n });\n\n try {\n const queue = getQueue(type);\n const job = await queue.add(\n QUEUE_NAMES[type],\n { runJobId: runJob.id, ...input },\n options.jobOptions,\n );\n\n try {\n await prisma.runJob.update({\n where: { id: runJob.id },\n data: { bullJobId: job.id ?? null },\n });\n } catch (linkError) {\n logger.error('RunJob enqueued but bullJobId linkage failed', {\n runJobId: runJob.id,\n bullJobId: job.id ?? null,\n type,\n error: linkError instanceof Error ? linkError.message : String(linkError),\n });\n }\n\n return { runJobId: runJob.id, bullJobId: job.id ?? null };\n } catch (error) {\n logger.error('Failed to enqueue RunJob; marking FAILED', {\n runJobId: runJob.id,\n type,\n error: error instanceof Error ? error.message : String(error),\n });\n\n try {\n await prisma.runJob.update({\n where: { id: runJob.id },\n data: {\n status: 'FAILED',\n error: error instanceof Error ? error.message : String(error),\n finishedAt: new Date(),\n },\n });\n } catch (updateError) {\n logger.error('Failed to mark RunJob as FAILED after enqueue error', {\n runJobId: runJob.id,\n error: updateError instanceof Error ? updateError.message : String(updateError),\n });\n }\n\n throw error;\n }\n}\n\n/**\n * Close every cached queue. Call from the HTTP server's shutdown handler so\n * the producer side disconnects from Redis cleanly.\n */\nexport async function closeAllQueues(): Promise<void> {\n await Promise.all(Array.from(queueCache.values()).map((q) => q.close()));\n queueCache.clear();\n}\n"],"names":[],"mappings":"AAAA;;;;;;;GAOG;;;AACH,OAAO,EAAE,KAAK,EAAoB,MAAM,QAAQ,CAAC;AAEjD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"queues.js","sources":["workers/queues.ts"],"sourceRoot":"/","sourcesContent":["/**\n * BullMQ queue producers and the `enqueueRunJob` helper.\n *\n * Producer side only — safe to import from HTTP routes / services running on\n * Vercel. Importing this file does NOT start any workers; workers live in\n * `src/workers/processors/*` and are wired up by `src/workers/index.ts`,\n * which is the entrypoint of the separate long-running worker process.\n */\nimport { Queue, type JobsOptions } from 'bullmq';\nimport { Prisma, type RunJobType } from '@prisma/client';\nimport { bullConnection, getBullPrefix } from './connection.js';\nimport { prisma } from '../lib/prisma.js';\nimport { logger } from '../utils/logger.js';\n\nconst DEFAULT_JOB_OPTIONS: JobsOptions = {\n attempts: 3,\n backoff: { type: 'exponential', delay: 5_000 },\n removeOnComplete: { age: 60 * 60 }, // keep completed jobs in Redis for 1h, then drop\n removeOnFail: { age: 24 * 60 * 60 }, // keep failed jobs for 24h for inspection\n};\n\n/**\n * Map RunJobType → (queue name, input payload shape).\n *\n * Add a new entry here whenever you introduce a new background job type.\n * The queue name string must match what the corresponding processor passes\n * to `new Worker(<name>, ...)`.\n */\nexport type JobInputs = {\n /**\n * `worksheetId` is the placeholder Worksheet row created synchronously by\n * the producer (so the client has an id to navigate to). The pipeline fills\n * that row in asynchronously and broadcasts progress on the per-worksheet\n * job channel.\n */\n PDF_TO_WORKSHEET: { gcsUrl: string; classId: string; worksheetId: string };\n GRADE_WORKSHEET: { worksheetResponseId: string };\n /**\n * `aiMessageId` is the placeholder AI Message row created synchronously by\n * the producer before enqueue (so the client renders a PENDING bubble in\n * the timeline). The pipeline fills in the content and flips the row to\n * COMPLETED / FAILED. Used for both intros and replies — single shape.\n */\n AI_LAB_CHAT: { conversationId: string; aiMessageId: string };\n /**\n * `aiMessageId` placeholder pattern, same as AI_LAB_CHAT — see above.\n */\n AI_NEWTON_CHAT: { conversationId: string; aiMessageId: string };\n STUDENT_PROGRESS_CHAT: { classId: string; studentId: string; message: string };\n /** Embed content into pgvector for RAG search. */\n EMBED_CONTENT: { classId: string; sourceType: string; sourceId: string };\n};\n\nexport const QUEUE_NAMES: Record<RunJobType, string> = {\n PDF_TO_WORKSHEET: 'pdfToWorksheet',\n GRADE_WORKSHEET: 'gradeWorksheet',\n AI_LAB_CHAT: 'aiLabChat',\n AI_NEWTON_CHAT: 'aiNewtonChat',\n STUDENT_PROGRESS_CHAT: 'studentProgressChat',\n EMBED_CONTENT: 'embedContent',\n};\n\n/**\n * One Queue instance per type. Created lazily so that importing this module\n * does not eagerly open queues you may never use in a given runtime.\n */\nconst queueCache = new Map<RunJobType, Queue>();\n\nfunction getQueue(type: RunJobType): Queue {\n let queue = queueCache.get(type);\n if (!queue) {\n queue = new Queue(QUEUE_NAMES[type], {\n connection: bullConnection,\n prefix: getBullPrefix(),\n defaultJobOptions: DEFAULT_JOB_OPTIONS,\n });\n queueCache.set(type, queue);\n }\n return queue;\n}\n\nexport interface EnqueueOptions {\n classId?: string | null;\n userId?: string | null;\n /** Override BullMQ job options (attempts, delay, priority, etc.). */\n jobOptions?: JobsOptions;\n}\n\nexport interface EnqueueResult {\n runJobId: string;\n bullJobId: string | null;\n}\n\n/**\n * Create a `RunJob` audit row, enqueue the BullMQ job, and link the two.\n *\n * Returns immediately — the actual work happens on the worker process. The\n * caller can return `runJobId` to the client and have them poll `getRunJob`\n * (or subscribe over Pusher) to track progress.\n *\n * IMPORTANT: do not call this inside a Prisma `$transaction`. If the outer\n * transaction rolls back after the BullMQ job is added, the worker will pick\n * up an orphaned job pointing at a non-existent RunJob row. Enqueue *after*\n * the transaction commits.\n */\nexport async function enqueueRunJob<T extends RunJobType>(\n type: T,\n input: JobInputs[T],\n options: EnqueueOptions = {},\n): Promise<EnqueueResult> {\n const runJob = await prisma.runJob.create({\n data: {\n type,\n status: 'PENDING',\n classId: options.classId ?? null,\n userId: options.userId ?? null,\n input: input as unknown as Prisma.InputJsonValue,\n },\n });\n\n try {\n const queue = getQueue(type);\n const job = await queue.add(\n QUEUE_NAMES[type],\n { runJobId: runJob.id, ...input },\n options.jobOptions,\n );\n\n try {\n await prisma.runJob.update({\n where: { id: runJob.id },\n data: { bullJobId: job.id ?? null },\n });\n } catch (linkError) {\n logger.error('RunJob enqueued but bullJobId linkage failed', {\n runJobId: runJob.id,\n bullJobId: job.id ?? null,\n type,\n error: linkError instanceof Error ? linkError.message : String(linkError),\n });\n }\n\n return { runJobId: runJob.id, bullJobId: job.id ?? null };\n } catch (error) {\n logger.error('Failed to enqueue RunJob; marking FAILED', {\n runJobId: runJob.id,\n type,\n error: error instanceof Error ? error.message : String(error),\n });\n\n try {\n await prisma.runJob.update({\n where: { id: runJob.id },\n data: {\n status: 'FAILED',\n error: error instanceof Error ? error.message : String(error),\n finishedAt: new Date(),\n },\n });\n } catch (updateError) {\n logger.error('Failed to mark RunJob as FAILED after enqueue error', {\n runJobId: runJob.id,\n error: updateError instanceof Error ? updateError.message : String(updateError),\n });\n }\n\n throw error;\n }\n}\n\n/**\n * Close every cached queue. Call from the HTTP server's shutdown handler so\n * the producer side disconnects from Redis cleanly.\n */\nexport async function closeAllQueues(): Promise<void> {\n await Promise.all(Array.from(queueCache.values()).map((q) => q.close()));\n queueCache.clear();\n}\n"],"names":[],"mappings":"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","debug_id":"8b504f67-acd8-5793-a500-d561724f9c85"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@studious-lms/server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.0",
|
|
4
4
|
"description": "Backend server for Studious application",
|
|
5
5
|
"main": "dist/exportType.js",
|
|
6
6
|
"types": "dist/exportType.d.ts",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"sentry:sourcemaps": "sentry-cli sourcemaps inject ./dist && sentry-cli sourcemaps upload --org \"${SENTRY_ORG:-studious-lms}\" --project \"${SENTRY_PROJECT:-server}\" ./dist"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
+
"@ai-sdk/openai": "^3.0.68",
|
|
32
33
|
"@google-cloud/storage": "^5.18.3",
|
|
33
34
|
"@pdf-lib/fontkit": "^1.1.1",
|
|
34
35
|
"@prisma/client": "^6.7.0",
|
|
@@ -36,6 +37,7 @@
|
|
|
36
37
|
"@sentry/node": "^10.26.0",
|
|
37
38
|
"@trpc/server": "^11.4.3",
|
|
38
39
|
"@unkey/ratelimit": "^2.1.3",
|
|
40
|
+
"ai": "^6.0.197",
|
|
39
41
|
"bcryptjs": "^3.0.2",
|
|
40
42
|
"bullmq": "^5.76.6",
|
|
41
43
|
"compression": "^1.8.1",
|
|
@@ -49,6 +51,7 @@
|
|
|
49
51
|
"nodemailer": "^8.0.7",
|
|
50
52
|
"openai": "^5.23.0",
|
|
51
53
|
"pdf-lib": "^1.17.1",
|
|
54
|
+
"pdf-parse": "^2.4.5",
|
|
52
55
|
"prisma": "^6.7.0",
|
|
53
56
|
"pusher": "^5.2.0",
|
|
54
57
|
"sharp": "^0.34.2",
|
|
@@ -63,6 +66,7 @@
|
|
|
63
66
|
"@types/express": "^4.17.21",
|
|
64
67
|
"@types/node": "^20.11.24",
|
|
65
68
|
"@types/nodemailer": "^6.4.17",
|
|
69
|
+
"@types/pdf-parse": "^1.1.5",
|
|
66
70
|
"@types/supertest": "^6.0.3",
|
|
67
71
|
"@types/uuid": "^10.0.0",
|
|
68
72
|
"@vitest/coverage-v8": "^3.2.4",
|