@goscribe/server 1.1.7 → 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.
Files changed (56) hide show
  1. package/.env.example +43 -0
  2. package/check-difficulty.cjs +14 -0
  3. package/check-questions.cjs +14 -0
  4. package/db-summary.cjs +22 -0
  5. package/dist/routers/auth.js +1 -1
  6. package/mcq-test.cjs +36 -0
  7. package/package.json +10 -2
  8. package/prisma/migrations/20260413143206_init/migration.sql +873 -0
  9. package/prisma/schema.prisma +485 -292
  10. package/src/context.ts +4 -1
  11. package/src/lib/activity_human_description.test.ts +28 -0
  12. package/src/lib/activity_human_description.ts +239 -0
  13. package/src/lib/activity_log_service.test.ts +37 -0
  14. package/src/lib/activity_log_service.ts +353 -0
  15. package/src/lib/ai-session.ts +194 -112
  16. package/src/lib/constants.ts +14 -0
  17. package/src/lib/email.ts +230 -0
  18. package/src/lib/env.ts +23 -6
  19. package/src/lib/inference.ts +3 -3
  20. package/src/lib/logger.ts +26 -9
  21. package/src/lib/notification-service.test.ts +106 -0
  22. package/src/lib/notification-service.ts +677 -0
  23. package/src/lib/prisma.ts +6 -1
  24. package/src/lib/pusher.ts +90 -6
  25. package/src/lib/retry.ts +61 -0
  26. package/src/lib/storage.ts +2 -2
  27. package/src/lib/stripe.ts +39 -0
  28. package/src/lib/subscription_service.ts +722 -0
  29. package/src/lib/usage_service.ts +74 -0
  30. package/src/lib/worksheet-generation.test.ts +31 -0
  31. package/src/lib/worksheet-generation.ts +139 -0
  32. package/src/lib/workspace-access.ts +13 -0
  33. package/src/routers/_app.ts +11 -0
  34. package/src/routers/admin.ts +710 -0
  35. package/src/routers/annotations.ts +227 -0
  36. package/src/routers/auth.ts +432 -33
  37. package/src/routers/copilot.ts +719 -0
  38. package/src/routers/flashcards.ts +207 -80
  39. package/src/routers/members.ts +280 -80
  40. package/src/routers/notifications.ts +142 -0
  41. package/src/routers/payment.ts +448 -0
  42. package/src/routers/podcast.ts +133 -108
  43. package/src/routers/studyguide.ts +80 -74
  44. package/src/routers/worksheets.ts +300 -80
  45. package/src/routers/workspace.ts +538 -328
  46. package/src/scripts/purge-deleted-users.ts +167 -0
  47. package/src/server.ts +140 -12
  48. package/src/services/flashcard-progress.service.ts +52 -43
  49. package/src/trpc.ts +184 -5
  50. package/test-generate.js +30 -0
  51. package/test-ratio.cjs +9 -0
  52. package/zod-test.cjs +22 -0
  53. package/prisma/migrations/20250826124819_add_worksheet_difficulty_and_estimated_time/migration.sql +0 -213
  54. package/prisma/migrations/20250826133236_add_worksheet_question_progress/migration.sql +0 -31
  55. package/prisma/seed.mjs +0 -135
  56. package/src/routers/meetingsummary.ts +0 -416
@@ -1,12 +1,9 @@
1
1
  import { z } from 'zod';
2
2
  import { TRPCError } from '@trpc/server';
3
3
  import { router, authedProcedure } from '../trpc.js';
4
- import { title } from 'node:process';
5
-
6
- // Mirror Prisma enum to avoid direct type import
7
- const ArtifactType = {
8
- STUDY_GUIDE: 'STUDY_GUIDE',
9
- } as const;
4
+ import { ArtifactType } from '../lib/constants.js';
5
+ import { getUserUsage, getUserPlanLimits } from '../lib/usage_service.js';
6
+ import { workspaceAccessFilter } from '../lib/workspace-access.js';
10
7
 
11
8
  const initializeEditorJsEmptyBlock = () => ({
12
9
  time: Date.now(),
@@ -14,7 +11,7 @@ const initializeEditorJsEmptyBlock = () => ({
14
11
  {
15
12
  id: 'initial',
16
13
  type: 'paragraph',
17
- data: { text: 'Start writing your study guide...' },
14
+ data: { text: 'Upload some files to begin creating your revision workspace...' },
18
15
  },
19
16
  ],
20
17
  version: '2.27.0',
@@ -34,15 +31,25 @@ export const studyguide = router({
34
31
  where: {
35
32
  workspaceId: input.workspaceId!,
36
33
  type: ArtifactType.STUDY_GUIDE,
37
- workspace: { ownerId: ctx.session.user.id },
34
+ workspace: workspaceAccessFilter(ctx.session.user.id),
38
35
  },
39
36
  include: {
40
37
  versions: { orderBy: { version: 'desc' }, take: 1 },
41
38
  },
42
39
  });
43
40
 
44
- console.log('artifact', artifact);
45
41
  if (!artifact) {
42
+ const [usage, limits] = await Promise.all([
43
+ getUserUsage(ctx.session.user.id),
44
+ getUserPlanLimits(ctx.session.user.id)
45
+ ]);
46
+ if (limits && usage.studyGuides >= limits.maxStudyGuides) {
47
+ throw new TRPCError({
48
+ code: 'FORBIDDEN',
49
+ message: 'Study Guide limit reached. Please upgrade your plan to create more workspaces with study guides.'
50
+ });
51
+ }
52
+
46
53
  artifact = await ctx.db.artifact.create({
47
54
  data: {
48
55
  workspaceId: input.workspaceId,
@@ -67,78 +74,77 @@ export const studyguide = router({
67
74
  }),
68
75
 
69
76
  // Edit study guide content by creating a new version, or create if doesn't exist
70
- edit: authedProcedure
71
- .input(
72
- z.object({
73
- workspaceId: z.string(),
74
- studyGuideId: z.string().optional(),
75
- content: z.string().min(1),
76
- data: z.record(z.string(), z.unknown()).optional(),
77
- title: z.string().min(1).optional(),
78
- })
79
- )
80
- .mutation(async ({ ctx, input }) => {
81
- let artifact;
77
+ // edit: authedProcedure
78
+ // .input(
79
+ // z.object({
80
+ // workspaceId: z.string(),
81
+ // studyGuideId: z.string().optional(),
82
+ // content: z.string().min(1),
83
+ // data: z.record(z.string(), z.unknown()).optional(),
84
+ // title: z.string().min(1).optional(),
85
+ // })
86
+ // )
87
+ // .mutation(async ({ ctx, input }) => {
88
+ // let artifact;
82
89
 
83
- if (input.studyGuideId) {
84
- // Try to find existing study guide
85
- artifact = await ctx.db.artifact.findFirst({
86
- where: {
87
- id: input.studyGuideId,
88
- type: ArtifactType.STUDY_GUIDE,
89
- workspace: { ownerId: ctx.session.user.id },
90
- },
91
- });
92
- } else {
93
- // Find by workspace if no specific studyGuideId provided
94
- artifact = await ctx.db.artifact.findFirst({
95
- where: {
96
- workspaceId: input.workspaceId,
97
- type: ArtifactType.STUDY_GUIDE,
98
- workspace: { ownerId: ctx.session.user.id },
99
- },
100
- });
101
- }
90
+ // if (input.studyGuideId) {
91
+ // // Try to find existing study guide
92
+ // artifact = await ctx.db.artifact.findFirst({
93
+ // where: {
94
+ // id: input.studyGuideId,
95
+ // type: ArtifactType.STUDY_GUIDE,
96
+ // workspace: workspaceAccessFilter(ctx.session.user.id),
97
+ // },
98
+ // });
99
+ // } else {
100
+ // // Find by workspace if no specific studyGuideId provided
101
+ // artifact = await ctx.db.artifact.findFirst({
102
+ // where: {
103
+ // workspaceId: input.workspaceId,
104
+ // type: ArtifactType.STUDY_GUIDE,
105
+ // workspace: workspaceAccessFilter(ctx.session.user.id),
106
+ // },
107
+ // });
108
+ // }
102
109
 
103
- // If no study guide found, create a new one
104
- if (!artifact) {
105
- artifact = await ctx.db.artifact.create({
106
- data: {
107
- workspaceId: input.workspaceId,
108
- type: ArtifactType.STUDY_GUIDE,
109
- title: 'Study Guide',
110
- createdById: ctx.session.user.id,
111
- },
112
- });
113
- }
110
+ // // If no study guide found, create a new one
111
+ // if (!artifact) {
112
+ // artifact = await ctx.db.artifact.create({
113
+ // data: {
114
+ // workspaceId: input.workspaceId,
115
+ // type: ArtifactType.STUDY_GUIDE,
116
+ // title: 'Study Guide',
117
+ // createdById: ctx.session.user.id,
118
+ // },
119
+ // });
120
+ // }
114
121
 
115
- const last = await ctx.db.artifactVersion.findFirst({
116
- where: { artifactId: artifact.id },
117
- orderBy: { version: 'desc' },
118
- });
122
+ // const last = await ctx.db.artifactVersion.findFirst({
123
+ // where: { artifactId: artifact.id },
124
+ // orderBy: { version: 'desc' },
125
+ // });
119
126
 
120
- if (input.title && input.title !== artifact.title) {
121
- console.log('rename')
122
- await ctx.db.artifact.update({
123
- where: { id: artifact.id },
124
- data: { title: input.title },
125
- });
126
- }
127
+ // if (input.title && input.title !== artifact.title) {
128
+ // await ctx.db.artifact.update({
129
+ // where: { id: artifact.id },
130
+ // data: { title: input.title },
131
+ // });
132
+ // }
127
133
 
128
- const nextVersion = (last?.version ?? 0) + 1;
134
+ // const nextVersion = (last?.version ?? 0) + 1;
129
135
 
130
- const version = await ctx.db.artifactVersion.create({
131
- data: {
132
- artifactId: artifact.id,
133
- content: input.content,
134
- data: input.data as any,
135
- version: nextVersion,
136
- createdById: ctx.session.user.id,
137
- },
138
- });
136
+ // const version = await ctx.db.artifactVersion.create({
137
+ // data: {
138
+ // artifactId: artifact.id,
139
+ // content: input.content,
140
+ // data: input.data ?? undefined,
141
+ // version: nextVersion,
142
+ // createdById: ctx.session.user.id,
143
+ // },
144
+ // });
139
145
 
140
- return { artifactId: artifact.id, version };
141
- }),
146
+ // return { artifactId: artifact.id, version };
147
+ // }),
142
148
  });
143
149
 
144
150