@goscribe/server 1.2.0 → 1.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/check-difficulty.cjs +14 -0
- package/check-questions.cjs +14 -0
- package/db-summary.cjs +22 -0
- package/mcq-test.cjs +36 -0
- package/package.json +9 -2
- package/prisma/migrations/20260413143206_init/migration.sql +873 -0
- package/prisma/schema.prisma +471 -324
- package/src/context.ts +4 -1
- package/src/lib/activity_human_description.test.ts +28 -0
- package/src/lib/activity_human_description.ts +239 -0
- package/src/lib/activity_log_service.test.ts +37 -0
- package/src/lib/activity_log_service.ts +353 -0
- package/src/lib/ai-session.ts +79 -51
- package/src/lib/email.ts +213 -29
- package/src/lib/env.ts +23 -6
- package/src/lib/inference.ts +2 -2
- package/src/lib/notification-service.test.ts +106 -0
- package/src/lib/notification-service.ts +677 -0
- package/src/lib/prisma.ts +6 -1
- package/src/lib/pusher.ts +86 -2
- package/src/lib/stripe.ts +39 -0
- package/src/lib/subscription_service.ts +722 -0
- package/src/lib/usage_service.ts +74 -0
- package/src/lib/worksheet-generation.test.ts +31 -0
- package/src/lib/worksheet-generation.ts +139 -0
- package/src/routers/_app.ts +9 -0
- package/src/routers/admin.ts +710 -0
- package/src/routers/annotations.ts +41 -0
- package/src/routers/auth.ts +338 -28
- package/src/routers/copilot.ts +719 -0
- package/src/routers/flashcards.ts +201 -68
- package/src/routers/members.ts +280 -80
- package/src/routers/notifications.ts +142 -0
- package/src/routers/payment.ts +448 -0
- package/src/routers/podcast.ts +112 -83
- package/src/routers/studyguide.ts +12 -0
- package/src/routers/worksheets.ts +289 -66
- package/src/routers/workspace.ts +329 -122
- package/src/scripts/purge-deleted-users.ts +167 -0
- package/src/server.ts +137 -11
- package/src/services/flashcard-progress.service.ts +49 -37
- package/src/trpc.ts +184 -5
- package/test-generate.js +30 -0
- package/test-ratio.cjs +9 -0
- package/zod-test.cjs +22 -0
- package/prisma/migrations/20250826124819_add_worksheet_difficulty_and_estimated_time/migration.sql +0 -213
- package/prisma/migrations/20250826133236_add_worksheet_question_progress/migration.sql +0 -31
- package/prisma/seed.mjs +0 -135
package/src/lib/pusher.ts
CHANGED
|
@@ -12,6 +12,16 @@ export const pusher = new Pusher({
|
|
|
12
12
|
|
|
13
13
|
// Pusher service for managing notifications
|
|
14
14
|
export class PusherService {
|
|
15
|
+
static async emitUserEvent(userId: string, eventName: string, data: any) {
|
|
16
|
+
try {
|
|
17
|
+
const channel = `user_${userId}`;
|
|
18
|
+
await pusher.trigger(channel, eventName, data);
|
|
19
|
+
logger.info(`📡 Pusher user event sent: ${eventName} to ${channel}`);
|
|
20
|
+
} catch (error) {
|
|
21
|
+
logger.error('Pusher user event error:', 'PUSHER', { error, userId, eventName });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
15
25
|
// Emit task completion notification
|
|
16
26
|
static async emitTaskComplete(workspaceId: string, event: string, data: any) {
|
|
17
27
|
try {
|
|
@@ -35,7 +45,7 @@ export class PusherService {
|
|
|
35
45
|
|
|
36
46
|
// Emit study guide completion
|
|
37
47
|
static async emitStudyGuideComplete(workspaceId: string, artifact: any) {
|
|
38
|
-
await this.
|
|
48
|
+
await this.emitTaskComplete(workspaceId, 'study_guide_generation_complete', {
|
|
39
49
|
artifactId: artifact.id,
|
|
40
50
|
title: artifact.title,
|
|
41
51
|
status: 'completed'
|
|
@@ -60,6 +70,21 @@ export class PusherService {
|
|
|
60
70
|
});
|
|
61
71
|
}
|
|
62
72
|
|
|
73
|
+
// Emit worksheet generation start notification
|
|
74
|
+
static async emitWorksheetGenerationStart(workspaceId: string) {
|
|
75
|
+
await this.emitTaskComplete(workspaceId, 'worksheet_generation_start', {});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Emit new worksheet notification
|
|
79
|
+
static async emitWorksheetNew(workspaceId: string, worksheet: any) {
|
|
80
|
+
await this.emitTaskComplete(workspaceId, 'worksheet_new', { worksheet });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Emit worksheet generation completion notification
|
|
84
|
+
static async emitWorksheetGenerationComplete(workspaceId: string, worksheet: any) {
|
|
85
|
+
await this.emitTaskComplete(workspaceId, 'worksheet_generation_complete', { worksheet });
|
|
86
|
+
}
|
|
87
|
+
|
|
63
88
|
// Emit podcast completion
|
|
64
89
|
static async emitPodcastComplete(workspaceId: string, artifact: any) {
|
|
65
90
|
await this.emitAnalysisComplete(workspaceId, 'podcast', {
|
|
@@ -81,7 +106,7 @@ export class PusherService {
|
|
|
81
106
|
// Emit error notification
|
|
82
107
|
static async emitError(workspaceId: string, error: string, analysisType?: string) {
|
|
83
108
|
const event = analysisType ? `${analysisType}_error` : 'analysis_error';
|
|
84
|
-
|
|
109
|
+
|
|
85
110
|
await this.emitTaskComplete(workspaceId, event, {
|
|
86
111
|
error,
|
|
87
112
|
analysisType,
|
|
@@ -111,6 +136,65 @@ export class PusherService {
|
|
|
111
136
|
logger.error('Pusher channel notification error:', 'PUSHER', { error });
|
|
112
137
|
}
|
|
113
138
|
}
|
|
139
|
+
|
|
140
|
+
// Emit member joined notification
|
|
141
|
+
static async emitMemberJoined(workspaceId: string, member: any) {
|
|
142
|
+
await this.emitTaskComplete(workspaceId, 'member_joined', { member });
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Emit profile update notification
|
|
146
|
+
static async emitProfileUpdate(userId: string) {
|
|
147
|
+
await this.emitUserEvent(userId, 'profile_updated', {
|
|
148
|
+
userId,
|
|
149
|
+
timestamp: new Date().toISOString(),
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Emit library (folders/workspaces) update notification
|
|
154
|
+
static async emitLibraryUpdate(userId: string) {
|
|
155
|
+
await this.emitUserEvent(userId, 'library_updated', {
|
|
156
|
+
userId,
|
|
157
|
+
timestamp: new Date().toISOString(),
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
static async emitNotificationNew(
|
|
162
|
+
userId: string,
|
|
163
|
+
data: {
|
|
164
|
+
notificationId: string;
|
|
165
|
+
type: string;
|
|
166
|
+
title: string;
|
|
167
|
+
unreadCount: number;
|
|
168
|
+
createdAt: string;
|
|
169
|
+
},
|
|
170
|
+
) {
|
|
171
|
+
await this.emitUserEvent(userId, 'notification_new', data);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
static async emitNotificationReadState(
|
|
175
|
+
userId: string,
|
|
176
|
+
data: { unreadCount: number; timestamp?: string },
|
|
177
|
+
) {
|
|
178
|
+
await this.emitUserEvent(userId, 'notification_read_state_changed', {
|
|
179
|
+
...data,
|
|
180
|
+
timestamp: data.timestamp ?? new Date().toISOString(),
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Emit payment success (top-up or subscription)
|
|
185
|
+
static async emitPaymentSuccess(userId: string, data: { type: 'topup' | 'subscription', resourceType?: string, quantity?: string }) {
|
|
186
|
+
try {
|
|
187
|
+
const channel = `user_${userId}`;
|
|
188
|
+
const eventName = 'payment_success';
|
|
189
|
+
await pusher.trigger(channel, eventName, {
|
|
190
|
+
...data,
|
|
191
|
+
timestamp: new Date().toISOString(),
|
|
192
|
+
});
|
|
193
|
+
logger.info(`📡 Pusher payment success sent: ${eventName} to ${channel}`);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
logger.error('Pusher payment success error:', 'PUSHER', { error });
|
|
196
|
+
}
|
|
197
|
+
}
|
|
114
198
|
}
|
|
115
199
|
|
|
116
200
|
export default PusherService;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import Stripe from 'stripe';
|
|
2
|
+
import { env } from './env.js';
|
|
3
|
+
import { logger } from './logger.js';
|
|
4
|
+
|
|
5
|
+
if (!env.STRIPE_SECRET_KEY) {
|
|
6
|
+
logger.warn('STRIPE_SECRET_KEY is not set. Stripe functionality will be disabled.', 'STRIPE');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const stripe = env.STRIPE_SECRET_KEY
|
|
10
|
+
? new Stripe(env.STRIPE_SECRET_KEY, {
|
|
11
|
+
apiVersion: '2026-02-25.clover' as any,
|
|
12
|
+
})
|
|
13
|
+
: null;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Creates a Stripe customer for a user.
|
|
17
|
+
*
|
|
18
|
+
* @param email - User's email
|
|
19
|
+
* @param name - User's name
|
|
20
|
+
* @returns The Stripe customer ID
|
|
21
|
+
*/
|
|
22
|
+
export async function createStripeCustomer(email: string, name?: string): Promise<string | null> {
|
|
23
|
+
if (!stripe) {
|
|
24
|
+
logger.error('Stripe is not initialized. Cannot create customer.', 'STRIPE');
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const customer = await stripe.customers.create({
|
|
30
|
+
email,
|
|
31
|
+
name,
|
|
32
|
+
});
|
|
33
|
+
logger.info(`Stripe customer created for ${email}: ${customer.id}`, 'STRIPE');
|
|
34
|
+
return customer.id;
|
|
35
|
+
} catch (error: any) {
|
|
36
|
+
logger.error(`Failed to create Stripe customer for ${email}: ${error.message}`, 'STRIPE');
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|