@goscribe/server 1.5.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/context.d.ts +14 -1
- package/dist/context.js +23 -2
- package/dist/generated/prisma/client.d.ts +224 -0
- package/dist/generated/prisma/client.js +34 -0
- package/dist/generated/prisma/commonInputTypes.d.ts +941 -0
- package/dist/generated/prisma/commonInputTypes.js +10 -0
- package/dist/generated/prisma/enums.d.ts +67 -0
- package/dist/generated/prisma/enums.js +66 -0
- package/dist/generated/prisma/internal/class.d.ts +539 -0
- package/dist/generated/prisma/internal/class.js +49 -0
- package/dist/generated/prisma/internal/prismaNamespace.d.ts +3924 -0
- package/dist/generated/prisma/internal/prismaNamespace.js +557 -0
- package/dist/generated/prisma/models/ActivityLog.d.ts +1847 -0
- package/dist/generated/prisma/models/ActivityLog.js +1 -0
- package/dist/generated/prisma/models/Artifact.d.ts +2345 -0
- package/dist/generated/prisma/models/Artifact.js +1 -0
- package/dist/generated/prisma/models/ArtifactVersion.d.ts +1550 -0
- package/dist/generated/prisma/models/ArtifactVersion.js +1 -0
- package/dist/generated/prisma/models/Channel.d.ts +1257 -0
- package/dist/generated/prisma/models/Channel.js +1 -0
- package/dist/generated/prisma/models/Chat.d.ts +1339 -0
- package/dist/generated/prisma/models/Chat.js +1 -0
- package/dist/generated/prisma/models/CopilotConversation.d.ts +1450 -0
- package/dist/generated/prisma/models/CopilotConversation.js +1 -0
- package/dist/generated/prisma/models/CopilotMessage.d.ts +1179 -0
- package/dist/generated/prisma/models/CopilotMessage.js +1 -0
- package/dist/generated/prisma/models/FileAsset.d.ts +1832 -0
- package/dist/generated/prisma/models/FileAsset.js +1 -0
- package/dist/generated/prisma/models/Flashcard.d.ts +1460 -0
- package/dist/generated/prisma/models/Flashcard.js +1 -0
- package/dist/generated/prisma/models/FlashcardProgress.d.ts +1782 -0
- package/dist/generated/prisma/models/FlashcardProgress.js +1 -0
- package/dist/generated/prisma/models/Folder.d.ts +1685 -0
- package/dist/generated/prisma/models/Folder.js +1 -0
- package/dist/generated/prisma/models/IdempotencyRecord.d.ts +1319 -0
- package/dist/generated/prisma/models/IdempotencyRecord.js +1 -0
- package/dist/generated/prisma/models/Invoice.d.ts +1586 -0
- package/dist/generated/prisma/models/Invoice.js +1 -0
- package/dist/generated/prisma/models/KnowledgeBase.d.ts +1721 -0
- package/dist/generated/prisma/models/KnowledgeBase.js +1 -0
- package/dist/generated/prisma/models/KnowledgeBaseChunk.d.ts +1333 -0
- package/dist/generated/prisma/models/KnowledgeBaseChunk.js +1 -0
- package/dist/generated/prisma/models/KnowledgeBaseDocument.d.ts +1695 -0
- package/dist/generated/prisma/models/KnowledgeBaseDocument.js +1 -0
- package/dist/generated/prisma/models/Notification.d.ts +1992 -0
- package/dist/generated/prisma/models/Notification.js +1 -0
- package/dist/generated/prisma/models/PasswordResetToken.d.ts +1210 -0
- package/dist/generated/prisma/models/PasswordResetToken.js +1 -0
- package/dist/generated/prisma/models/Plan.d.ts +1431 -0
- package/dist/generated/prisma/models/Plan.js +1 -0
- package/dist/generated/prisma/models/PlanLimit.d.ts +1328 -0
- package/dist/generated/prisma/models/PlanLimit.js +1 -0
- package/dist/generated/prisma/models/PodcastSegment.d.ts +1564 -0
- package/dist/generated/prisma/models/PodcastSegment.js +1 -0
- package/dist/generated/prisma/models/ResourcePrice.d.ts +1008 -0
- package/dist/generated/prisma/models/ResourcePrice.js +1 -0
- package/dist/generated/prisma/models/Role.d.ts +1065 -0
- package/dist/generated/prisma/models/Role.js +1 -0
- package/dist/generated/prisma/models/Session.d.ts +1105 -0
- package/dist/generated/prisma/models/Session.js +1 -0
- package/dist/generated/prisma/models/StripeEvent.d.ts +1081 -0
- package/dist/generated/prisma/models/StripeEvent.js +1 -0
- package/dist/generated/prisma/models/StudyGuideComment.d.ts +1321 -0
- package/dist/generated/prisma/models/StudyGuideComment.js +1 -0
- package/dist/generated/prisma/models/StudyGuideHighlight.d.ts +1629 -0
- package/dist/generated/prisma/models/StudyGuideHighlight.js +1 -0
- package/dist/generated/prisma/models/Subscription.d.ts +1677 -0
- package/dist/generated/prisma/models/Subscription.js +1 -0
- package/dist/generated/prisma/models/User.d.ts +7559 -0
- package/dist/generated/prisma/models/User.js +1 -0
- package/dist/generated/prisma/models/UserCredit.d.ts +1249 -0
- package/dist/generated/prisma/models/UserCredit.js +1 -0
- package/dist/generated/prisma/models/VerificationToken.d.ts +946 -0
- package/dist/generated/prisma/models/VerificationToken.js +1 -0
- package/dist/generated/prisma/models/WorksheetPreset.d.ts +1433 -0
- package/dist/generated/prisma/models/WorksheetPreset.js +1 -0
- package/dist/generated/prisma/models/WorksheetQuestion.d.ts +1491 -0
- package/dist/generated/prisma/models/WorksheetQuestion.js +1 -0
- package/dist/generated/prisma/models/WorksheetQuestionProgress.d.ts +1620 -0
- package/dist/generated/prisma/models/WorksheetQuestionProgress.js +1 -0
- package/dist/generated/prisma/models/Workspace.d.ts +3620 -0
- package/dist/generated/prisma/models/Workspace.js +1 -0
- package/dist/generated/prisma/models/WorkspaceInvitation.d.ts +1490 -0
- package/dist/generated/prisma/models/WorkspaceInvitation.js +1 -0
- package/dist/generated/prisma/models/WorkspaceKnowledgeBase.d.ts +1410 -0
- package/dist/generated/prisma/models/WorkspaceKnowledgeBase.js +1 -0
- package/dist/generated/prisma/models/WorkspaceMember.d.ts +1326 -0
- package/dist/generated/prisma/models/WorkspaceMember.js +1 -0
- package/dist/generated/prisma/models.d.ts +39 -0
- package/dist/generated/prisma/models.js +1 -0
- package/dist/lib/ai/index.d.ts +3 -2
- package/dist/lib/ai/index.js +3 -2
- package/dist/lib/ai/llm-client.d.ts +1 -0
- package/dist/lib/ai/llm-client.js +17 -0
- package/dist/routers/_app.d.ts +40 -80
- package/dist/routers/auth.js +1 -1
- package/dist/routers/flashcards.d.ts +12 -1
- package/dist/routers/payment.d.ts +1 -12
- package/dist/routers/workspace.d.ts +27 -67
- package/dist/routers/workspace.js +1 -0
- package/dist/services/billing/payment.service.d.ts +1 -12
- package/dist/services/billing/payment.service.js +3 -6
- package/dist/services/billing/usage.service.d.ts +30 -10
- package/dist/services/billing/usage.service.js +87 -15
- package/dist/services/content/copilot.service.js +15 -29
- package/dist/services/content/flashcard-progress.service.js +9 -9
- package/dist/services/content/flashcard.service.d.ts +45 -1
- package/dist/services/content/flashcard.service.js +81 -68
- package/dist/services/content/media-analysis.service.js +27 -27
- package/dist/services/content/worksheet-generation.service.test.js +2 -2
- package/dist/services/workspace/workspace.service.d.ts +23 -67
- package/dist/services/workspace/workspace.service.js +69 -62
- package/dist/src/context.d.ts +27 -0
- package/dist/src/context.js +33 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +1 -0
- package/dist/src/lib/ai/config.d.ts +20 -0
- package/dist/src/lib/ai/config.js +31 -0
- package/dist/src/lib/ai/embedding-client.d.ts +8 -0
- package/dist/src/lib/ai/embedding-client.js +30 -0
- package/dist/src/lib/ai/index.d.ts +48 -0
- package/dist/src/lib/ai/index.js +29 -0
- package/dist/src/lib/ai/inference-backend/client.d.ts +28 -0
- package/dist/src/lib/ai/inference-backend/client.js +301 -0
- package/dist/src/lib/ai/inference-backend/mocks.d.ts +12 -0
- package/dist/src/lib/ai/inference-backend/mocks.js +133 -0
- package/dist/src/lib/ai/inference-backend/types.d.ts +44 -0
- package/dist/src/lib/ai/inference-backend/types.js +1 -0
- package/dist/src/lib/ai/json-parse.d.ts +2 -0
- package/dist/src/lib/ai/json-parse.js +34 -0
- package/dist/src/lib/ai/llm-client.d.ts +7 -0
- package/dist/src/lib/ai/llm-client.js +36 -0
- package/dist/src/lib/ai/mock.d.ts +2 -0
- package/dist/src/lib/ai/mock.js +10 -0
- package/dist/src/lib/ai/types.d.ts +9 -0
- package/dist/src/lib/ai/types.js +1 -0
- package/dist/src/lib/auth.d.ts +36 -0
- package/dist/src/lib/auth.js +117 -0
- package/dist/src/lib/chunking.d.ts +19 -0
- package/dist/src/lib/chunking.js +47 -0
- package/dist/src/lib/constants.d.ts +13 -0
- package/dist/src/lib/constants.js +12 -0
- package/dist/src/lib/curated-kb-seed.d.ts +12 -0
- package/dist/src/lib/curated-kb-seed.js +155 -0
- package/dist/src/lib/email.d.ts +11 -0
- package/dist/src/lib/email.js +152 -0
- package/dist/src/lib/embeddings.d.ts +2 -0
- package/dist/src/lib/embeddings.js +1 -0
- package/dist/src/lib/ensure-curated-kb-catalog.d.ts +6 -0
- package/dist/src/lib/ensure-curated-kb-catalog.js +53 -0
- package/dist/src/lib/env.d.ts +41 -0
- package/dist/src/lib/env.js +57 -0
- package/dist/src/lib/errors.d.ts +33 -0
- package/dist/src/lib/errors.js +78 -0
- package/dist/src/lib/file.d.ts +0 -0
- package/dist/src/lib/file.js +1 -0
- package/dist/src/lib/inference.d.ts +1 -0
- package/dist/src/lib/inference.js +1 -0
- package/dist/src/lib/kb-meta.d.ts +8 -0
- package/dist/src/lib/kb-meta.js +77 -0
- package/dist/src/lib/logger.d.ts +62 -0
- package/dist/src/lib/logger.js +364 -0
- package/dist/src/lib/pdf.d.ts +11 -0
- package/dist/src/lib/pdf.js +11 -0
- package/dist/src/lib/prisma.d.ts +3 -0
- package/dist/src/lib/prisma.js +15 -0
- package/dist/src/lib/pusher.d.ts +38 -0
- package/dist/src/lib/pusher.js +170 -0
- package/dist/src/lib/retry.d.ts +15 -0
- package/dist/src/lib/retry.js +37 -0
- package/dist/src/lib/storage.d.ts +11 -0
- package/dist/src/lib/storage.js +71 -0
- package/dist/src/lib/stripe.d.ts +10 -0
- package/dist/src/lib/stripe.js +36 -0
- package/dist/src/lib/validation.d.ts +51 -0
- package/dist/src/lib/validation.js +64 -0
- package/dist/src/lib/workspace-kb.d.ts +5 -0
- package/dist/src/lib/workspace-kb.js +7 -0
- package/dist/src/repositories/artifact.repository.d.ts +64 -0
- package/dist/src/repositories/artifact.repository.js +40 -0
- package/dist/src/repositories/base.repository.d.ts +14 -0
- package/dist/src/repositories/base.repository.js +14 -0
- package/dist/src/repositories/invitation.repository.d.ts +104 -0
- package/dist/src/repositories/invitation.repository.js +44 -0
- package/dist/src/repositories/notification.repository.d.ts +76 -0
- package/dist/src/repositories/notification.repository.js +44 -0
- package/dist/src/repositories/user.repository.d.ts +84 -0
- package/dist/src/repositories/user.repository.js +37 -0
- package/dist/src/repositories/workspace-member.repository.d.ts +35 -0
- package/dist/src/repositories/workspace-member.repository.js +31 -0
- package/dist/src/repositories/workspace.repository.d.ts +101 -0
- package/dist/src/repositories/workspace.repository.js +79 -0
- package/dist/src/routers/_app.d.ts +3464 -0
- package/dist/src/routers/_app.js +36 -0
- package/dist/src/routers/admin.d.ts +358 -0
- package/dist/src/routers/admin.js +105 -0
- package/dist/src/routers/annotations.d.ts +219 -0
- package/dist/src/routers/annotations.js +29 -0
- package/dist/src/routers/artifactVersions.d.ts +65 -0
- package/dist/src/routers/artifactVersions.js +14 -0
- package/dist/src/routers/auth.d.ts +161 -0
- package/dist/src/routers/auth.js +97 -0
- package/dist/src/routers/chat.d.ts +170 -0
- package/dist/src/routers/chat.js +32 -0
- package/dist/src/routers/copilot.d.ts +200 -0
- package/dist/src/routers/copilot.js +52 -0
- package/dist/src/routers/flashcards.d.ts +336 -0
- package/dist/src/routers/flashcards.js +93 -0
- package/dist/src/routers/knowledgeBase.d.ts +421 -0
- package/dist/src/routers/knowledgeBase.js +118 -0
- package/dist/src/routers/members.d.ts +169 -0
- package/dist/src/routers/members.js +47 -0
- package/dist/src/routers/notifications.d.ts +99 -0
- package/dist/src/routers/notifications.js +25 -0
- package/dist/src/routers/payment.d.ts +80 -0
- package/dist/src/routers/payment.js +21 -0
- package/dist/src/routers/podcast.d.ts +287 -0
- package/dist/src/routers/podcast.js +34 -0
- package/dist/src/routers/studyguide.d.ts +36 -0
- package/dist/src/routers/studyguide.js +8 -0
- package/dist/src/routers/worksheets.d.ts +429 -0
- package/dist/src/routers/worksheets.js +139 -0
- package/dist/src/routers/workspace.d.ts +563 -0
- package/dist/src/routers/workspace.js +104 -0
- package/dist/src/scripts/purge-deleted-users.d.ts +1 -0
- package/dist/src/scripts/purge-deleted-users.js +148 -0
- package/dist/src/server.d.ts +1 -0
- package/dist/src/server.js +190 -0
- package/dist/src/services/activity/activity-human-description.service.d.ts +13 -0
- package/dist/src/services/activity/activity-human-description.service.js +221 -0
- package/dist/src/services/activity/activity-human-description.service.test.d.ts +1 -0
- package/dist/src/services/activity/activity-human-description.service.test.js +16 -0
- package/dist/src/services/activity/activity-log.service.d.ts +87 -0
- package/dist/src/services/activity/activity-log.service.js +276 -0
- package/dist/src/services/activity/activity-log.service.test.d.ts +1 -0
- package/dist/src/services/activity/activity-log.service.test.js +27 -0
- package/dist/src/services/admin/admin.service.d.ts +270 -0
- package/dist/src/services/admin/admin.service.js +476 -0
- package/dist/src/services/ai/ai-session.service.d.ts +5 -0
- package/dist/src/services/ai/ai-session.service.js +4 -0
- package/dist/src/services/artifacts/annotation.service.d.ts +177 -0
- package/dist/src/services/artifacts/annotation.service.js +154 -0
- package/dist/src/services/artifacts/artifact-version.service.d.ts +38 -0
- package/dist/src/services/artifacts/artifact-version.service.js +129 -0
- package/dist/src/services/artifacts/chat.service.d.ts +127 -0
- package/dist/src/services/artifacts/chat.service.js +182 -0
- package/dist/src/services/artifacts/study-guide.service.d.ts +18 -0
- package/dist/src/services/artifacts/study-guide.service.js +65 -0
- package/dist/src/services/auth/auth.service.d.ts +94 -0
- package/dist/src/services/auth/auth.service.js +368 -0
- package/dist/src/services/base.service.d.ts +14 -0
- package/dist/src/services/base.service.js +14 -0
- package/dist/src/services/billing/payment.service.d.ts +44 -0
- package/dist/src/services/billing/payment.service.js +365 -0
- package/dist/src/services/billing/subscription.service.d.ts +37 -0
- package/dist/src/services/billing/subscription.service.js +654 -0
- package/dist/src/services/billing/usage.service.d.ts +47 -0
- package/dist/src/services/billing/usage.service.js +149 -0
- package/dist/src/services/content/copilot.service.d.ts +113 -0
- package/dist/src/services/content/copilot.service.js +439 -0
- package/dist/src/services/content/flashcard-progress.service.d.ts +159 -0
- package/dist/src/services/content/flashcard-progress.service.js +432 -0
- package/dist/src/services/content/flashcard.service.d.ts +184 -0
- package/dist/src/services/content/flashcard.service.js +339 -0
- package/dist/src/services/content/media-analysis.service.d.ts +23 -0
- package/dist/src/services/content/media-analysis.service.js +404 -0
- package/dist/src/services/content/podcast.service.d.ts +267 -0
- package/dist/src/services/content/podcast.service.js +653 -0
- package/dist/src/services/content/worksheet-content.service.d.ts +37 -0
- package/dist/src/services/content/worksheet-content.service.js +84 -0
- package/dist/src/services/content/worksheet-content.service.test.d.ts +1 -0
- package/dist/src/services/content/worksheet-content.service.test.js +69 -0
- package/dist/src/services/content/worksheet-generation.service.d.ts +91 -0
- package/dist/src/services/content/worksheet-generation.service.js +95 -0
- package/dist/src/services/content/worksheet-generation.service.test.d.ts +1 -0
- package/dist/src/services/content/worksheet-generation.service.test.js +20 -0
- package/dist/src/services/content/worksheet.service.d.ts +347 -0
- package/dist/src/services/content/worksheet.service.js +599 -0
- package/dist/src/services/knowledge/knowledge-base.service.d.ts +316 -0
- package/dist/src/services/knowledge/knowledge-base.service.js +544 -0
- package/dist/src/services/members/invitation.service.d.ts +66 -0
- package/dist/src/services/members/invitation.service.js +348 -0
- package/dist/src/services/members/member.service.d.ts +36 -0
- package/dist/src/services/members/member.service.js +193 -0
- package/dist/src/services/notifications/notification.service.d.ts +214 -0
- package/dist/src/services/notifications/notification.service.js +550 -0
- package/dist/src/services/notifications/notification.service.test.d.ts +1 -0
- package/dist/src/services/notifications/notification.service.test.js +87 -0
- package/dist/src/services/workspace/workspace-analytics.service.d.ts +24 -0
- package/dist/src/services/workspace/workspace-analytics.service.js +95 -0
- package/dist/src/services/workspace/workspace-kb.service.d.ts +40 -0
- package/dist/src/services/workspace/workspace-kb.service.js +184 -0
- package/dist/src/services/workspace/workspace.service.d.ts +263 -0
- package/dist/src/services/workspace/workspace.service.js +401 -0
- package/dist/src/trpc.d.ts +60 -0
- package/dist/src/trpc.js +217 -0
- package/dist/src/types/index.d.ts +126 -0
- package/dist/src/types/index.js +1 -0
- package/dist/trpc.d.ts +12 -4
- package/dist/trpc.js +5 -11
- package/package.json +8 -9
- package/prisma/schema.prisma +3 -4
- package/prisma/seed.mjs +5 -2
- package/prisma.config.ts +16 -0
- package/src/context.ts +33 -3
- package/src/lib/ai/index.ts +3 -0
- package/src/lib/ai/llm-client.ts +23 -0
- package/src/lib/prisma.ts +18 -9
- package/src/routers/auth.ts +1 -1
- package/src/routers/workspace.ts +4 -0
- package/src/scripts/purge-deleted-users.ts +1 -3
- package/src/services/billing/payment.service.ts +3 -6
- package/src/services/billing/usage.service.ts +190 -77
- package/src/services/content/copilot.service.ts +23 -32
- package/src/services/content/flashcard-progress.service.ts +12 -9
- package/src/services/content/flashcard.service.ts +89 -66
- package/src/services/content/media-analysis.service.ts +34 -29
- package/src/services/content/worksheet-generation.service.test.ts +2 -2
- package/src/services/workspace/workspace.service.ts +73 -66
- package/src/trpc.ts +5 -13
- package/tsconfig.json +3 -0
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import { createWriteStream, existsSync, mkdirSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
export var LogLevel;
|
|
4
|
+
(function (LogLevel) {
|
|
5
|
+
LogLevel[LogLevel["ERROR"] = 0] = "ERROR";
|
|
6
|
+
LogLevel[LogLevel["WARN"] = 1] = "WARN";
|
|
7
|
+
LogLevel[LogLevel["INFO"] = 2] = "INFO";
|
|
8
|
+
LogLevel[LogLevel["DEBUG"] = 3] = "DEBUG";
|
|
9
|
+
LogLevel[LogLevel["TRACE"] = 4] = "TRACE";
|
|
10
|
+
})(LogLevel || (LogLevel = {}));
|
|
11
|
+
// Icons and colors for different log levels
|
|
12
|
+
const LOG_STYLES = {
|
|
13
|
+
[LogLevel.ERROR]: {
|
|
14
|
+
icon: '❌',
|
|
15
|
+
color: '\x1b[31m', // Red
|
|
16
|
+
bgColor: '\x1b[41m', // Red background
|
|
17
|
+
bold: '\x1b[1m',
|
|
18
|
+
},
|
|
19
|
+
[LogLevel.WARN]: {
|
|
20
|
+
icon: '⚠️ ',
|
|
21
|
+
color: '\x1b[33m', // Yellow
|
|
22
|
+
bgColor: '\x1b[43m', // Yellow background
|
|
23
|
+
bold: '\x1b[1m',
|
|
24
|
+
},
|
|
25
|
+
[LogLevel.INFO]: {
|
|
26
|
+
icon: 'ℹ️ ',
|
|
27
|
+
color: '\x1b[36m', // Cyan
|
|
28
|
+
bgColor: '\x1b[46m', // Cyan background
|
|
29
|
+
bold: '\x1b[1m',
|
|
30
|
+
},
|
|
31
|
+
[LogLevel.DEBUG]: {
|
|
32
|
+
icon: '🐛',
|
|
33
|
+
color: '\x1b[35m', // Magenta
|
|
34
|
+
bgColor: '\x1b[45m', // Magenta background
|
|
35
|
+
bold: '\x1b[1m',
|
|
36
|
+
},
|
|
37
|
+
[LogLevel.TRACE]: {
|
|
38
|
+
icon: '🔍',
|
|
39
|
+
color: '\x1b[37m', // White
|
|
40
|
+
bgColor: '\x1b[47m', // White background
|
|
41
|
+
bold: '\x1b[1m',
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
// Context icons for common services
|
|
45
|
+
const CONTEXT_ICONS = {
|
|
46
|
+
'SERVER': '🖥️ ',
|
|
47
|
+
'HTTP': '🌐',
|
|
48
|
+
'API': '🔌',
|
|
49
|
+
'AUTH': '🔐',
|
|
50
|
+
'DATABASE': '🗄️ ',
|
|
51
|
+
'DB': '🗄️ ',
|
|
52
|
+
'TRPC': '⚡',
|
|
53
|
+
'WORKSPACE': '📁',
|
|
54
|
+
'WORKSHEET': '📝',
|
|
55
|
+
'FLASHCARD': '🃏',
|
|
56
|
+
'STUDYGUIDE': '📚',
|
|
57
|
+
'PODCAST': '🎙️ ',
|
|
58
|
+
'MEETING': '🤝',
|
|
59
|
+
'CHAT': '💬',
|
|
60
|
+
'FILE': '📄',
|
|
61
|
+
'STORAGE': '💾',
|
|
62
|
+
'CACHE': '⚡',
|
|
63
|
+
'MIDDLEWARE': '🔧',
|
|
64
|
+
'PERFORMANCE': '⚡',
|
|
65
|
+
'SECURITY': '🛡️ ',
|
|
66
|
+
'VALIDATION': '✅',
|
|
67
|
+
'ERROR': '❌',
|
|
68
|
+
'SUCCESS': '✅',
|
|
69
|
+
'LOGGER': '📋',
|
|
70
|
+
};
|
|
71
|
+
class Logger {
|
|
72
|
+
constructor(config = {}) {
|
|
73
|
+
this.config = {
|
|
74
|
+
level: LogLevel.INFO,
|
|
75
|
+
enableConsole: true,
|
|
76
|
+
enableFile: false,
|
|
77
|
+
logDir: './logs',
|
|
78
|
+
maxFileSize: 10 * 1024 * 1024, // 10MB
|
|
79
|
+
maxFiles: 5,
|
|
80
|
+
format: 'pretty',
|
|
81
|
+
...config,
|
|
82
|
+
};
|
|
83
|
+
if (this.config.enableFile) {
|
|
84
|
+
this.setupFileLogging();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
setupFileLogging() {
|
|
88
|
+
if (!this.config.logDir)
|
|
89
|
+
return;
|
|
90
|
+
// Ensure log directory exists
|
|
91
|
+
if (!existsSync(this.config.logDir)) {
|
|
92
|
+
mkdirSync(this.config.logDir, { recursive: true });
|
|
93
|
+
}
|
|
94
|
+
const logFile = join(this.config.logDir, `app-${new Date().toISOString().split('T')[0]}.log`);
|
|
95
|
+
this.logStream = createWriteStream(logFile, { flags: 'a' });
|
|
96
|
+
}
|
|
97
|
+
shouldLog(level) {
|
|
98
|
+
return level <= this.config.level;
|
|
99
|
+
}
|
|
100
|
+
formatLogEntry(entry) {
|
|
101
|
+
if (this.config.format === 'json') {
|
|
102
|
+
return JSON.stringify(entry) + '\n';
|
|
103
|
+
}
|
|
104
|
+
// Pretty format with enhanced styling
|
|
105
|
+
const timestamp = this.formatTimestamp(entry.timestamp);
|
|
106
|
+
const level = this.formatLevel(entry.level);
|
|
107
|
+
const context = entry.context ? this.formatContext(entry.context) : '';
|
|
108
|
+
const metadata = entry.metadata ? this.formatMetadata(entry.metadata) : '';
|
|
109
|
+
const error = entry.error ? this.formatError(entry.error) : '';
|
|
110
|
+
return `${timestamp} ${level} ${context}${entry.message}${metadata}${error}`;
|
|
111
|
+
}
|
|
112
|
+
formatLevel(level) {
|
|
113
|
+
const levelNum = LogLevel[level];
|
|
114
|
+
const style = LOG_STYLES[levelNum];
|
|
115
|
+
return `${style.color}${style.bold}${level.padEnd(5)}\x1b[0m`;
|
|
116
|
+
}
|
|
117
|
+
formatTimestamp(timestamp) {
|
|
118
|
+
const date = new Date(timestamp);
|
|
119
|
+
const time = date.toLocaleTimeString('en-US', {
|
|
120
|
+
hour12: false,
|
|
121
|
+
hour: '2-digit',
|
|
122
|
+
minute: '2-digit',
|
|
123
|
+
second: '2-digit',
|
|
124
|
+
});
|
|
125
|
+
return `\x1b[90m${time}\x1b[0m`; // Gray color
|
|
126
|
+
}
|
|
127
|
+
formatContext(context) {
|
|
128
|
+
if (typeof context !== 'string')
|
|
129
|
+
return '';
|
|
130
|
+
const icon = CONTEXT_ICONS[context.toUpperCase()] || '📦';
|
|
131
|
+
return `\x1b[94m${icon}${context}\x1b[0m `; // Blue color
|
|
132
|
+
}
|
|
133
|
+
formatMetadata(metadata) {
|
|
134
|
+
const entries = Object.entries(metadata)
|
|
135
|
+
.map(([key, value]) => {
|
|
136
|
+
const formattedValue = this.formatValue(value);
|
|
137
|
+
return `\x1b[93m${key}\x1b[0m=\x1b[96m${formattedValue}\x1b[0m`;
|
|
138
|
+
})
|
|
139
|
+
.join(' \x1b[90m|\x1b[0m ');
|
|
140
|
+
return entries ? `\n \x1b[90m└─\x1b[0m \x1b[90m{\x1b[0m ${entries} \x1b[90m}\x1b[0m` : '';
|
|
141
|
+
}
|
|
142
|
+
formatValue(value) {
|
|
143
|
+
if (value === null)
|
|
144
|
+
return '\x1b[90mnull\x1b[0m';
|
|
145
|
+
if (value === undefined)
|
|
146
|
+
return '\x1b[90mundefined\x1b[0m';
|
|
147
|
+
if (typeof value === 'boolean')
|
|
148
|
+
return value ? '\x1b[92mtrue\x1b[0m' : '\x1b[91mfalse\x1b[0m';
|
|
149
|
+
if (typeof value === 'number')
|
|
150
|
+
return `\x1b[95m${value}\x1b[0m`;
|
|
151
|
+
if (typeof value === 'string')
|
|
152
|
+
return `\x1b[96m"${value}"\x1b[0m`;
|
|
153
|
+
if (typeof value === 'object') {
|
|
154
|
+
if (Array.isArray(value)) {
|
|
155
|
+
const items = value.map(item => this.formatValue(item)).join('\x1b[90m, \x1b[0m');
|
|
156
|
+
return `\x1b[90m[\x1b[0m${items}\x1b[90m]\x1b[0m`;
|
|
157
|
+
}
|
|
158
|
+
const objEntries = Object.entries(value)
|
|
159
|
+
.map(([k, v]) => `\x1b[93m${k}\x1b[0m:\x1b[96m${this.formatValue(v)}\x1b[0m`)
|
|
160
|
+
.join('\x1b[90m, \x1b[0m');
|
|
161
|
+
return `\x1b[90m{\x1b[0m${objEntries}\x1b[90m}\x1b[0m`;
|
|
162
|
+
}
|
|
163
|
+
return `\x1b[96m${String(value)}\x1b[0m`;
|
|
164
|
+
}
|
|
165
|
+
formatError(error) {
|
|
166
|
+
let errorStr = `\n \x1b[90m└─\x1b[0m \x1b[31m❌ \x1b[93m${error.name}\x1b[0m: \x1b[91m${error.message}\x1b[0m`;
|
|
167
|
+
if (error.stack) {
|
|
168
|
+
const stackLines = error.stack.split('\n').slice(1, 4); // Show first 3 stack lines
|
|
169
|
+
errorStr += `\n \x1b[90m└─ Stack:\x1b[0m`;
|
|
170
|
+
stackLines.forEach((line, index) => {
|
|
171
|
+
const isLast = index === stackLines.length - 1;
|
|
172
|
+
const connector = isLast ? '└─' : '├─';
|
|
173
|
+
errorStr += `\n \x1b[90m${connector} \x1b[0m\x1b[90m${line.trim()}\x1b[0m`;
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
return errorStr;
|
|
177
|
+
}
|
|
178
|
+
log(level, message, context, metadata, error) {
|
|
179
|
+
if (!this.shouldLog(level))
|
|
180
|
+
return;
|
|
181
|
+
const entry = {
|
|
182
|
+
timestamp: new Date().toISOString(),
|
|
183
|
+
level: LogLevel[level],
|
|
184
|
+
message,
|
|
185
|
+
context,
|
|
186
|
+
metadata,
|
|
187
|
+
error: error ? {
|
|
188
|
+
name: error.name,
|
|
189
|
+
message: error.message,
|
|
190
|
+
stack: error.stack,
|
|
191
|
+
} : undefined,
|
|
192
|
+
};
|
|
193
|
+
const formattedLog = this.formatLogEntry(entry);
|
|
194
|
+
if (this.config.enableConsole) {
|
|
195
|
+
// Enhanced console output with icons and colors
|
|
196
|
+
const style = LOG_STYLES[level];
|
|
197
|
+
const reset = '\x1b[0m';
|
|
198
|
+
// Create a beautiful log line with proper spacing and colors
|
|
199
|
+
const logLine = `${style.color}${style.icon} ${formattedLog}${reset}`;
|
|
200
|
+
console.log(logLine);
|
|
201
|
+
}
|
|
202
|
+
if (this.config.enableFile && this.logStream) {
|
|
203
|
+
this.logStream.write(formattedLog + '\n');
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
error(message, contextOrError, metadata, error) {
|
|
207
|
+
if (contextOrError instanceof Error) {
|
|
208
|
+
this.log(LogLevel.ERROR, message, undefined, metadata, contextOrError);
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
this.log(LogLevel.ERROR, message, contextOrError, metadata, error);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
warn(message, contextOrMeta, metadata) {
|
|
215
|
+
if (typeof contextOrMeta === 'object' && contextOrMeta !== null) {
|
|
216
|
+
this.log(LogLevel.WARN, message, undefined, contextOrMeta);
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
this.log(LogLevel.WARN, message, contextOrMeta, metadata);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
info(message, contextOrMeta, metadata) {
|
|
223
|
+
if (typeof contextOrMeta === 'object' && contextOrMeta !== null) {
|
|
224
|
+
this.log(LogLevel.INFO, message, undefined, contextOrMeta);
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
this.log(LogLevel.INFO, message, contextOrMeta, metadata);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
debug(message, contextOrMeta, metadata) {
|
|
231
|
+
if (typeof contextOrMeta === 'object' && contextOrMeta !== null) {
|
|
232
|
+
this.log(LogLevel.DEBUG, message, undefined, contextOrMeta);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
this.log(LogLevel.DEBUG, message, contextOrMeta, metadata);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
trace(message, context, metadata) {
|
|
239
|
+
this.log(LogLevel.TRACE, message, context, metadata);
|
|
240
|
+
}
|
|
241
|
+
// Convenience methods for common use cases
|
|
242
|
+
http(method, url, statusCode, responseTime, context) {
|
|
243
|
+
const statusIcon = this.getHttpStatusIcon(statusCode);
|
|
244
|
+
const responseTimeStr = responseTime ? `${responseTime}ms` : undefined;
|
|
245
|
+
const metadata = {
|
|
246
|
+
method,
|
|
247
|
+
url,
|
|
248
|
+
statusCode,
|
|
249
|
+
responseTime: responseTimeStr,
|
|
250
|
+
};
|
|
251
|
+
this.info(`${statusIcon} ${method} ${url} - ${statusCode}`, context || 'HTTP', metadata);
|
|
252
|
+
}
|
|
253
|
+
getHttpStatusIcon(statusCode) {
|
|
254
|
+
if (statusCode >= 200 && statusCode < 300)
|
|
255
|
+
return '✅';
|
|
256
|
+
if (statusCode >= 300 && statusCode < 400)
|
|
257
|
+
return '↩️ ';
|
|
258
|
+
if (statusCode >= 400 && statusCode < 500)
|
|
259
|
+
return '⚠️ ';
|
|
260
|
+
if (statusCode >= 500)
|
|
261
|
+
return '❌';
|
|
262
|
+
return '❓';
|
|
263
|
+
}
|
|
264
|
+
database(operation, table, duration, context) {
|
|
265
|
+
const operationIcon = this.getDatabaseOperationIcon(operation);
|
|
266
|
+
const durationStr = duration ? `${duration}ms` : undefined;
|
|
267
|
+
const metadata = {
|
|
268
|
+
operation,
|
|
269
|
+
table,
|
|
270
|
+
duration: durationStr,
|
|
271
|
+
};
|
|
272
|
+
this.debug(`${operationIcon} ${operation} on ${table}`, context || 'DATABASE', metadata);
|
|
273
|
+
}
|
|
274
|
+
getDatabaseOperationIcon(operation) {
|
|
275
|
+
const op = operation.toUpperCase();
|
|
276
|
+
if (op.includes('SELECT'))
|
|
277
|
+
return '🔍';
|
|
278
|
+
if (op.includes('INSERT'))
|
|
279
|
+
return '➕';
|
|
280
|
+
if (op.includes('UPDATE'))
|
|
281
|
+
return '✏️ ';
|
|
282
|
+
if (op.includes('DELETE'))
|
|
283
|
+
return '🗑️ ';
|
|
284
|
+
if (op.includes('CREATE'))
|
|
285
|
+
return '🏗️ ';
|
|
286
|
+
if (op.includes('DROP'))
|
|
287
|
+
return '💥';
|
|
288
|
+
return '🗄️ ';
|
|
289
|
+
}
|
|
290
|
+
auth(action, userId, context) {
|
|
291
|
+
const metadata = {
|
|
292
|
+
action,
|
|
293
|
+
userId,
|
|
294
|
+
};
|
|
295
|
+
this.info(`Auth ${action}`, context, metadata);
|
|
296
|
+
}
|
|
297
|
+
trpc(procedure, input, output, duration, context) {
|
|
298
|
+
const metadata = {
|
|
299
|
+
procedure,
|
|
300
|
+
input: input ? JSON.stringify(input) : undefined,
|
|
301
|
+
output: output ? JSON.stringify(output) : undefined,
|
|
302
|
+
duration: duration ? `${duration}ms` : undefined,
|
|
303
|
+
};
|
|
304
|
+
this.debug(`tRPC ${procedure}`, context, metadata);
|
|
305
|
+
}
|
|
306
|
+
// Method to update configuration at runtime
|
|
307
|
+
updateConfig(newConfig) {
|
|
308
|
+
this.config = { ...this.config, ...newConfig };
|
|
309
|
+
if (newConfig.enableFile && !this.logStream) {
|
|
310
|
+
this.setupFileLogging();
|
|
311
|
+
}
|
|
312
|
+
else if (!newConfig.enableFile && this.logStream) {
|
|
313
|
+
this.logStream.end();
|
|
314
|
+
this.logStream = undefined;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
// Progress indicator for long-running operations
|
|
318
|
+
progress(message, current, total, context) {
|
|
319
|
+
const percentage = Math.round((current / total) * 100);
|
|
320
|
+
const progressBar = this.createProgressBar(percentage);
|
|
321
|
+
this.info(`${progressBar} ${message} (${current}/${total} - ${percentage}%)`, context || 'PROGRESS');
|
|
322
|
+
}
|
|
323
|
+
createProgressBar(percentage, width = 20) {
|
|
324
|
+
const filled = Math.round((percentage / 100) * width);
|
|
325
|
+
const empty = width - filled;
|
|
326
|
+
const bar = '█'.repeat(filled) + '░'.repeat(empty);
|
|
327
|
+
return `[${bar}]`;
|
|
328
|
+
}
|
|
329
|
+
// Success and failure helpers
|
|
330
|
+
success(message, context, metadata) {
|
|
331
|
+
this.info(`✅ ${message}`, context, metadata);
|
|
332
|
+
}
|
|
333
|
+
failure(message, context, metadata, error) {
|
|
334
|
+
this.error(`❌ ${message}`, context, metadata, error);
|
|
335
|
+
}
|
|
336
|
+
// Method to close file streams (useful for graceful shutdown)
|
|
337
|
+
close() {
|
|
338
|
+
if (this.logStream) {
|
|
339
|
+
this.logStream.end();
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
// Create default logger instance
|
|
344
|
+
const defaultConfig = {
|
|
345
|
+
level: process.env.NODE_ENV === 'production' ? LogLevel.INFO : LogLevel.DEBUG,
|
|
346
|
+
enableConsole: true,
|
|
347
|
+
enableFile: process.env.NODE_ENV === 'production',
|
|
348
|
+
logDir: './logs',
|
|
349
|
+
format: process.env.NODE_ENV === 'production' ? 'json' : 'pretty',
|
|
350
|
+
};
|
|
351
|
+
export const logger = new Logger(defaultConfig);
|
|
352
|
+
// Export the Logger class for custom instances
|
|
353
|
+
export { Logger };
|
|
354
|
+
// Graceful shutdown handling
|
|
355
|
+
process.on('SIGINT', () => {
|
|
356
|
+
logger.info('Received SIGINT, closing logger...');
|
|
357
|
+
logger.close();
|
|
358
|
+
process.exit(0);
|
|
359
|
+
});
|
|
360
|
+
process.on('SIGTERM', () => {
|
|
361
|
+
logger.info('Received SIGTERM, closing logger...');
|
|
362
|
+
logger.close();
|
|
363
|
+
process.exit(0);
|
|
364
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin wrapper around `pdf-parse` that returns plain text + page count.
|
|
3
|
+
*
|
|
4
|
+
* pdf-parse is loaded lazily and via a deep import to avoid the package's
|
|
5
|
+
* top-level "test" code that runs when the module index is loaded directly.
|
|
6
|
+
*/
|
|
7
|
+
export interface ExtractedPdf {
|
|
8
|
+
text: string;
|
|
9
|
+
numPages: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function extractPdfText(buffer: Buffer): Promise<ExtractedPdf>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export async function extractPdfText(buffer) {
|
|
2
|
+
// Deep import skips pdf-parse's top-level demo block (`if (!module.parent)`).
|
|
3
|
+
// @ts-ignore - no types ship for the deep file
|
|
4
|
+
const mod = await import('pdf-parse/lib/pdf-parse.js');
|
|
5
|
+
const pdfParse = mod.default ?? mod;
|
|
6
|
+
const data = await pdfParse(buffer);
|
|
7
|
+
return {
|
|
8
|
+
text: data.text ?? '',
|
|
9
|
+
numPages: data.numpages ?? 0,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { PrismaPg } from "@prisma/adapter-pg";
|
|
2
|
+
import { PrismaClient } from "../../generated/prisma/client.js";
|
|
3
|
+
export { ArtifactType, ActivityLogCategory, ActivityLogStatus, InvoiceType, } from "../../generated/prisma/client.js";
|
|
4
|
+
const globalForPrisma = globalThis;
|
|
5
|
+
function createPrismaClient() {
|
|
6
|
+
const connectionString = process.env.DATABASE_URL;
|
|
7
|
+
if (!connectionString) {
|
|
8
|
+
throw new Error("DATABASE_URL is not set");
|
|
9
|
+
}
|
|
10
|
+
const adapter = new PrismaPg({ connectionString });
|
|
11
|
+
return new PrismaClient({ adapter });
|
|
12
|
+
}
|
|
13
|
+
export const prisma = globalForPrisma.prisma ?? createPrismaClient();
|
|
14
|
+
if (process.env.NODE_ENV !== "production")
|
|
15
|
+
globalForPrisma.prisma = prisma;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import Pusher from 'pusher';
|
|
2
|
+
export declare const pusher: Pusher;
|
|
3
|
+
export declare class PusherService {
|
|
4
|
+
static emitUserEvent(userId: string, eventName: string, data: any): Promise<void>;
|
|
5
|
+
static emitTaskComplete(workspaceId: string, event: string, data: any): Promise<void>;
|
|
6
|
+
static emitAnalysisComplete(workspaceId: string, analysisType: string, result: any): Promise<void>;
|
|
7
|
+
static emitStudyGuideComplete(workspaceId: string, artifact: any): Promise<void>;
|
|
8
|
+
static emitFlashcardComplete(workspaceId: string, artifact: any): Promise<void>;
|
|
9
|
+
static emitWorksheetComplete(workspaceId: string, artifact: any): Promise<void>;
|
|
10
|
+
static emitWorksheetGenerationStart(workspaceId: string): Promise<void>;
|
|
11
|
+
static emitWorksheetNew(workspaceId: string, worksheet: any): Promise<void>;
|
|
12
|
+
static emitWorksheetGenerationComplete(workspaceId: string, worksheet: any): Promise<void>;
|
|
13
|
+
static emitPodcastComplete(workspaceId: string, artifact: any): Promise<void>;
|
|
14
|
+
static emitOverallComplete(workspaceId: string, filename: string, artifacts: any): Promise<void>;
|
|
15
|
+
static emitError(workspaceId: string, error: string, analysisType?: string): Promise<void>;
|
|
16
|
+
static emitAnalysisProgress(workspaceId: string, progress: any): Promise<void>;
|
|
17
|
+
static emitChannelEvent(channelId: string, event: string, data: any): Promise<void>;
|
|
18
|
+
static emitMemberJoined(workspaceId: string, member: any): Promise<void>;
|
|
19
|
+
static emitProfileUpdate(userId: string): Promise<void>;
|
|
20
|
+
static emitLibraryUpdate(userId: string): Promise<void>;
|
|
21
|
+
static emitNotificationNew(userId: string, data: {
|
|
22
|
+
notificationId: string;
|
|
23
|
+
type: string;
|
|
24
|
+
title: string;
|
|
25
|
+
unreadCount: number;
|
|
26
|
+
createdAt: string;
|
|
27
|
+
}): Promise<void>;
|
|
28
|
+
static emitNotificationReadState(userId: string, data: {
|
|
29
|
+
unreadCount: number;
|
|
30
|
+
timestamp?: string;
|
|
31
|
+
}): Promise<void>;
|
|
32
|
+
static emitPaymentSuccess(userId: string, data: {
|
|
33
|
+
type: 'topup' | 'subscription';
|
|
34
|
+
resourceType?: string;
|
|
35
|
+
quantity?: string;
|
|
36
|
+
}): Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
export default PusherService;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import Pusher from 'pusher';
|
|
2
|
+
import { logger } from './logger.js';
|
|
3
|
+
// Server-side Pusher instance
|
|
4
|
+
export const pusher = new Pusher({
|
|
5
|
+
appId: process.env.PUSHER_APP_ID || '',
|
|
6
|
+
key: process.env.PUSHER_KEY || '',
|
|
7
|
+
secret: process.env.PUSHER_SECRET || '',
|
|
8
|
+
cluster: process.env.PUSHER_CLUSTER || 'us2',
|
|
9
|
+
useTLS: true,
|
|
10
|
+
});
|
|
11
|
+
// Pusher service for managing notifications
|
|
12
|
+
export class PusherService {
|
|
13
|
+
static async emitUserEvent(userId, eventName, data) {
|
|
14
|
+
try {
|
|
15
|
+
const channel = `user_${userId}`;
|
|
16
|
+
await pusher.trigger(channel, eventName, data);
|
|
17
|
+
logger.info(`📡 Pusher user event sent: ${eventName} to ${channel}`);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
logger.error('Pusher user event error:', 'PUSHER', { error, userId, eventName });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
// Emit task completion notification
|
|
24
|
+
static async emitTaskComplete(workspaceId, event, data) {
|
|
25
|
+
try {
|
|
26
|
+
const channel = `workspace_${workspaceId}`;
|
|
27
|
+
const eventName = event;
|
|
28
|
+
await pusher.trigger(channel, eventName, data);
|
|
29
|
+
logger.info(`📡 Pusher notification sent: ${eventName} to ${channel}`);
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
logger.error('Pusher notification error:', 'PUSHER', { error });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Emit AI analysis completion
|
|
36
|
+
static async emitAnalysisComplete(workspaceId, analysisType, result) {
|
|
37
|
+
await this.emitTaskComplete(workspaceId, `${analysisType}_ended`, {
|
|
38
|
+
type: analysisType,
|
|
39
|
+
result,
|
|
40
|
+
timestamp: new Date().toISOString(),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
// Emit study guide completion
|
|
44
|
+
static async emitStudyGuideComplete(workspaceId, artifact) {
|
|
45
|
+
await this.emitTaskComplete(workspaceId, 'study_guide_generation_complete', {
|
|
46
|
+
artifactId: artifact.id,
|
|
47
|
+
title: artifact.title,
|
|
48
|
+
status: 'completed'
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
// Emit flashcard completion
|
|
52
|
+
static async emitFlashcardComplete(workspaceId, artifact) {
|
|
53
|
+
await this.emitAnalysisComplete(workspaceId, 'flashcard', {
|
|
54
|
+
artifactId: artifact.id,
|
|
55
|
+
title: artifact.title,
|
|
56
|
+
status: 'completed'
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
// Emit worksheet completion
|
|
60
|
+
static async emitWorksheetComplete(workspaceId, artifact) {
|
|
61
|
+
await this.emitAnalysisComplete(workspaceId, 'worksheet', {
|
|
62
|
+
artifactId: artifact.id,
|
|
63
|
+
title: artifact.title,
|
|
64
|
+
status: 'completed'
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
// Emit worksheet generation start notification
|
|
68
|
+
static async emitWorksheetGenerationStart(workspaceId) {
|
|
69
|
+
await this.emitTaskComplete(workspaceId, 'worksheet_generation_start', {});
|
|
70
|
+
}
|
|
71
|
+
// Emit new worksheet notification
|
|
72
|
+
static async emitWorksheetNew(workspaceId, worksheet) {
|
|
73
|
+
await this.emitTaskComplete(workspaceId, 'worksheet_new', { worksheet });
|
|
74
|
+
}
|
|
75
|
+
// Emit worksheet generation completion notification
|
|
76
|
+
static async emitWorksheetGenerationComplete(workspaceId, worksheet) {
|
|
77
|
+
await this.emitTaskComplete(workspaceId, 'worksheet_generation_complete', { worksheet });
|
|
78
|
+
}
|
|
79
|
+
// Emit podcast completion
|
|
80
|
+
static async emitPodcastComplete(workspaceId, artifact) {
|
|
81
|
+
await this.emitAnalysisComplete(workspaceId, 'podcast', {
|
|
82
|
+
artifactId: artifact.id,
|
|
83
|
+
title: artifact.title,
|
|
84
|
+
status: 'completed'
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
// Emit overall analysis completion
|
|
88
|
+
static async emitOverallComplete(workspaceId, filename, artifacts) {
|
|
89
|
+
await this.emitTaskComplete(workspaceId, 'analysis_ended', {
|
|
90
|
+
filename,
|
|
91
|
+
artifacts,
|
|
92
|
+
timestamp: new Date().toISOString(),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
// Emit error notification
|
|
96
|
+
static async emitError(workspaceId, error, analysisType) {
|
|
97
|
+
const event = analysisType ? `${analysisType}_error` : 'analysis_error';
|
|
98
|
+
await this.emitTaskComplete(workspaceId, event, {
|
|
99
|
+
error,
|
|
100
|
+
analysisType,
|
|
101
|
+
timestamp: new Date().toISOString(),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
// Emit analysis progress update (single event for all progress updates)
|
|
105
|
+
static async emitAnalysisProgress(workspaceId, progress) {
|
|
106
|
+
try {
|
|
107
|
+
const channel = `workspace_${workspaceId}`;
|
|
108
|
+
await pusher.trigger(channel, 'analysis_progress', progress);
|
|
109
|
+
logger.info(`📡 Analysis progress sent to ${channel}: ${progress.status}`);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
logger.error('Pusher progress notification error:', 'PUSHER', { error });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Emit channel-specific events (for chat messages)
|
|
116
|
+
static async emitChannelEvent(channelId, event, data) {
|
|
117
|
+
try {
|
|
118
|
+
const channel = channelId; // Use channelId directly as channel name
|
|
119
|
+
const eventName = event;
|
|
120
|
+
await pusher.trigger(channel, eventName, data);
|
|
121
|
+
logger.info(`Pusher notification sent: ${eventName} to ${channel}`);
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
logger.error('Pusher channel notification error:', 'PUSHER', { error });
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Emit member joined notification
|
|
128
|
+
static async emitMemberJoined(workspaceId, member) {
|
|
129
|
+
await this.emitTaskComplete(workspaceId, 'member_joined', { member });
|
|
130
|
+
}
|
|
131
|
+
// Emit profile update notification
|
|
132
|
+
static async emitProfileUpdate(userId) {
|
|
133
|
+
await this.emitUserEvent(userId, 'profile_updated', {
|
|
134
|
+
userId,
|
|
135
|
+
timestamp: new Date().toISOString(),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
// Emit library (folders/workspaces) update notification
|
|
139
|
+
static async emitLibraryUpdate(userId) {
|
|
140
|
+
await this.emitUserEvent(userId, 'library_updated', {
|
|
141
|
+
userId,
|
|
142
|
+
timestamp: new Date().toISOString(),
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
static async emitNotificationNew(userId, data) {
|
|
146
|
+
await this.emitUserEvent(userId, 'notification_new', data);
|
|
147
|
+
}
|
|
148
|
+
static async emitNotificationReadState(userId, data) {
|
|
149
|
+
await this.emitUserEvent(userId, 'notification_read_state_changed', {
|
|
150
|
+
...data,
|
|
151
|
+
timestamp: data.timestamp ?? new Date().toISOString(),
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
// Emit payment success (top-up or subscription)
|
|
155
|
+
static async emitPaymentSuccess(userId, data) {
|
|
156
|
+
try {
|
|
157
|
+
const channel = `user_${userId}`;
|
|
158
|
+
const eventName = 'payment_success';
|
|
159
|
+
await pusher.trigger(channel, eventName, {
|
|
160
|
+
...data,
|
|
161
|
+
timestamp: new Date().toISOString(),
|
|
162
|
+
});
|
|
163
|
+
logger.info(`📡 Pusher payment success sent: ${eventName} to ${channel}`);
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
logger.error('Pusher payment success error:', 'PUSHER', { error });
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
export default PusherService;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface RetryOptions {
|
|
2
|
+
/** Maximum number of attempts (default: 3) */
|
|
3
|
+
maxRetries?: number;
|
|
4
|
+
/** Base delay in ms for exponential backoff (default: 2000) */
|
|
5
|
+
baseDelayMs?: number;
|
|
6
|
+
/** Timeout per attempt in ms (default: 300000 = 5 minutes) */
|
|
7
|
+
timeoutMs?: number;
|
|
8
|
+
/** Label for logging (optional) */
|
|
9
|
+
label?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Wraps an async function with retry logic and exponential backoff.
|
|
13
|
+
* Throws the last error if all attempts fail.
|
|
14
|
+
*/
|
|
15
|
+
export declare function withRetry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { logger } from './logger.js';
|
|
2
|
+
/**
|
|
3
|
+
* Wraps an async function with retry logic and exponential backoff.
|
|
4
|
+
* Throws the last error if all attempts fail.
|
|
5
|
+
*/
|
|
6
|
+
export async function withRetry(fn, options = {}) {
|
|
7
|
+
const { maxRetries = 3, baseDelayMs = 2000, timeoutMs = 300000, label = 'operation', } = options;
|
|
8
|
+
let lastError = null;
|
|
9
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
10
|
+
try {
|
|
11
|
+
logger.info(`[retry] ${label} attempt ${attempt}/${maxRetries}`);
|
|
12
|
+
// Create an AbortController for per-attempt timeout
|
|
13
|
+
const controller = new AbortController();
|
|
14
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
15
|
+
try {
|
|
16
|
+
const result = await fn();
|
|
17
|
+
clearTimeout(timeoutId);
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
clearTimeout(timeoutId);
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
27
|
+
logger.error(`[retry] ${label} attempt ${attempt} failed: ${lastError.message}`);
|
|
28
|
+
if (attempt < maxRetries) {
|
|
29
|
+
const delay = Math.pow(2, attempt) * baseDelayMs;
|
|
30
|
+
logger.info(`[retry] ${label} retrying in ${delay}ms...`);
|
|
31
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
logger.error(`[retry] ${label} all ${maxRetries} attempts failed`);
|
|
36
|
+
throw lastError;
|
|
37
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface UploadResult {
|
|
2
|
+
url: string;
|
|
3
|
+
signedUrl?: string;
|
|
4
|
+
objectKey: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function uploadToSupabase(fileBuffer: Buffer, fileName: string, contentType: string, makePublic?: boolean): Promise<UploadResult>;
|
|
7
|
+
export declare function generateSignedUrl(objectKey: string, expiresInHours?: number): Promise<string>;
|
|
8
|
+
export declare function deleteFromSupabase(objectKey: string): Promise<void>;
|
|
9
|
+
export declare function makeFilePublic(objectKey: string): Promise<void>;
|
|
10
|
+
export declare function makeFilePrivate(objectKey: string): Promise<void>;
|
|
11
|
+
export declare const supabaseClient: import("@supabase/supabase-js").SupabaseClient<any, "public", "public", any, any>;
|