@studious-lms/server 1.0.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 (103) hide show
  1. package/LICENSE.txt +8 -0
  2. package/README.md +143 -0
  3. package/dist/exportType.d.ts +9 -0
  4. package/dist/exportType.d.ts.map +1 -0
  5. package/dist/exportType.js +7 -0
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +82 -0
  9. package/dist/lib/fileUpload.d.ts +38 -0
  10. package/dist/lib/fileUpload.d.ts.map +1 -0
  11. package/dist/lib/fileUpload.js +136 -0
  12. package/dist/lib/googleCloudStorage.d.ts +20 -0
  13. package/dist/lib/googleCloudStorage.d.ts.map +1 -0
  14. package/dist/lib/googleCloudStorage.js +88 -0
  15. package/dist/lib/prisma.d.ts +8 -0
  16. package/dist/lib/prisma.d.ts.map +1 -0
  17. package/dist/lib/prisma.js +11 -0
  18. package/dist/lib/thumbnailGenerator.d.ts +23 -0
  19. package/dist/lib/thumbnailGenerator.d.ts.map +1 -0
  20. package/dist/lib/thumbnailGenerator.js +180 -0
  21. package/dist/logger.d.ts +26 -0
  22. package/dist/logger.d.ts.map +1 -0
  23. package/dist/logger.js +135 -0
  24. package/dist/middleware/auth.d.ts +7 -0
  25. package/dist/middleware/auth.d.ts.map +1 -0
  26. package/dist/middleware/auth.js +170 -0
  27. package/dist/middleware/logging.d.ts +2 -0
  28. package/dist/middleware/logging.d.ts.map +1 -0
  29. package/dist/middleware/logging.js +51 -0
  30. package/dist/routers/_app.d.ts +4369 -0
  31. package/dist/routers/_app.d.ts.map +1 -0
  32. package/dist/routers/_app.js +29 -0
  33. package/dist/routers/agenda.d.ts +66 -0
  34. package/dist/routers/agenda.d.ts.map +1 -0
  35. package/dist/routers/agenda.js +78 -0
  36. package/dist/routers/announcement.d.ts +79 -0
  37. package/dist/routers/announcement.d.ts.map +1 -0
  38. package/dist/routers/announcement.js +122 -0
  39. package/dist/routers/assignment.d.ts +1051 -0
  40. package/dist/routers/assignment.d.ts.map +1 -0
  41. package/dist/routers/assignment.js +1497 -0
  42. package/dist/routers/attendance.d.ts +99 -0
  43. package/dist/routers/attendance.d.ts.map +1 -0
  44. package/dist/routers/attendance.js +269 -0
  45. package/dist/routers/auth.d.ts +87 -0
  46. package/dist/routers/auth.d.ts.map +1 -0
  47. package/dist/routers/auth.js +255 -0
  48. package/dist/routers/class.d.ts +427 -0
  49. package/dist/routers/class.d.ts.map +1 -0
  50. package/dist/routers/class.js +693 -0
  51. package/dist/routers/event.d.ts +249 -0
  52. package/dist/routers/event.d.ts.map +1 -0
  53. package/dist/routers/event.js +467 -0
  54. package/dist/routers/file.d.ts +27 -0
  55. package/dist/routers/file.d.ts.map +1 -0
  56. package/dist/routers/file.js +88 -0
  57. package/dist/routers/section.d.ts +51 -0
  58. package/dist/routers/section.d.ts.map +1 -0
  59. package/dist/routers/section.js +123 -0
  60. package/dist/routers/user.d.ts +49 -0
  61. package/dist/routers/user.d.ts.map +1 -0
  62. package/dist/routers/user.js +74 -0
  63. package/dist/socket/handlers.d.ts +3 -0
  64. package/dist/socket/handlers.d.ts.map +1 -0
  65. package/dist/socket/handlers.js +130 -0
  66. package/dist/trpc.d.ts +147 -0
  67. package/dist/trpc.d.ts.map +1 -0
  68. package/dist/trpc.js +67 -0
  69. package/dist/types/trpc.d.ts +16 -0
  70. package/dist/types/trpc.d.ts.map +1 -0
  71. package/dist/types/trpc.js +2 -0
  72. package/dist/utils/email.d.ts +3 -0
  73. package/dist/utils/email.d.ts.map +1 -0
  74. package/dist/utils/email.js +16 -0
  75. package/dist/utils/generateInviteCode.d.ts +6 -0
  76. package/dist/utils/generateInviteCode.d.ts.map +1 -0
  77. package/dist/utils/generateInviteCode.js +11 -0
  78. package/dist/utils/logger.d.ts +27 -0
  79. package/dist/utils/logger.d.ts.map +1 -0
  80. package/dist/utils/logger.js +124 -0
  81. package/generated/prisma/client.d.ts +1 -0
  82. package/generated/prisma/client.js +4 -0
  83. package/generated/prisma/default.d.ts +1 -0
  84. package/generated/prisma/default.js +4 -0
  85. package/generated/prisma/edge.d.ts +1 -0
  86. package/generated/prisma/edge.js +389 -0
  87. package/generated/prisma/index-browser.js +375 -0
  88. package/generated/prisma/index.d.ts +34865 -0
  89. package/generated/prisma/index.js +410 -0
  90. package/generated/prisma/libquery_engine-darwin-arm64.dylib.node +0 -0
  91. package/generated/prisma/package.json +140 -0
  92. package/generated/prisma/runtime/edge-esm.js +34 -0
  93. package/generated/prisma/runtime/edge.js +34 -0
  94. package/generated/prisma/runtime/index-browser.d.ts +370 -0
  95. package/generated/prisma/runtime/index-browser.js +16 -0
  96. package/generated/prisma/runtime/library.d.ts +3647 -0
  97. package/generated/prisma/runtime/library.js +146 -0
  98. package/generated/prisma/runtime/react-native.js +83 -0
  99. package/generated/prisma/runtime/wasm.js +35 -0
  100. package/generated/prisma/schema.prisma +304 -0
  101. package/generated/prisma/wasm.d.ts +1 -0
  102. package/generated/prisma/wasm.js +375 -0
  103. package/package.json +46 -0
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sectionRouter = void 0;
4
+ const zod_1 = require("zod");
5
+ const trpc_1 = require("../trpc");
6
+ const server_1 = require("@trpc/server");
7
+ const prisma_1 = require("@lib/prisma");
8
+ const createSectionSchema = zod_1.z.object({
9
+ classId: zod_1.z.string(),
10
+ name: zod_1.z.string(),
11
+ });
12
+ const updateSectionSchema = zod_1.z.object({
13
+ id: zod_1.z.string(),
14
+ classId: zod_1.z.string(),
15
+ name: zod_1.z.string(),
16
+ });
17
+ const deleteSectionSchema = zod_1.z.object({
18
+ id: zod_1.z.string(),
19
+ classId: zod_1.z.string(),
20
+ });
21
+ exports.sectionRouter = (0, trpc_1.createTRPCRouter)({
22
+ create: trpc_1.protectedProcedure
23
+ .input(createSectionSchema)
24
+ .mutation(async ({ ctx, input }) => {
25
+ if (!ctx.user) {
26
+ throw new server_1.TRPCError({
27
+ code: "UNAUTHORIZED",
28
+ message: "User must be authenticated",
29
+ });
30
+ }
31
+ // Verify user is a teacher of the class
32
+ const classData = await prisma_1.prisma.class.findFirst({
33
+ where: {
34
+ id: input.classId,
35
+ teachers: {
36
+ some: {
37
+ id: ctx.user.id,
38
+ },
39
+ },
40
+ },
41
+ });
42
+ if (!classData) {
43
+ throw new server_1.TRPCError({
44
+ code: "NOT_FOUND",
45
+ message: "Class not found or you are not a teacher",
46
+ });
47
+ }
48
+ const section = await prisma_1.prisma.section.create({
49
+ data: {
50
+ name: input.name,
51
+ class: {
52
+ connect: { id: input.classId },
53
+ },
54
+ },
55
+ });
56
+ return section;
57
+ }),
58
+ update: trpc_1.protectedProcedure
59
+ .input(updateSectionSchema)
60
+ .mutation(async ({ ctx, input }) => {
61
+ if (!ctx.user) {
62
+ throw new server_1.TRPCError({
63
+ code: "UNAUTHORIZED",
64
+ message: "User must be authenticated",
65
+ });
66
+ }
67
+ // Verify user is a teacher of the class
68
+ const classData = await prisma_1.prisma.class.findFirst({
69
+ where: {
70
+ id: input.classId,
71
+ teachers: {
72
+ some: {
73
+ id: ctx.user.id,
74
+ },
75
+ },
76
+ },
77
+ });
78
+ if (!classData) {
79
+ throw new server_1.TRPCError({
80
+ code: "NOT_FOUND",
81
+ message: "Class not found or you are not a teacher",
82
+ });
83
+ }
84
+ const section = await prisma_1.prisma.section.update({
85
+ where: { id: input.id },
86
+ data: {
87
+ name: input.name,
88
+ },
89
+ });
90
+ return section;
91
+ }),
92
+ delete: trpc_1.protectedProcedure
93
+ .input(deleteSectionSchema)
94
+ .mutation(async ({ ctx, input }) => {
95
+ if (!ctx.user) {
96
+ throw new server_1.TRPCError({
97
+ code: "UNAUTHORIZED",
98
+ message: "User must be authenticated",
99
+ });
100
+ }
101
+ // Verify user is a teacher of the class
102
+ const classData = await prisma_1.prisma.class.findFirst({
103
+ where: {
104
+ id: input.classId,
105
+ teachers: {
106
+ some: {
107
+ id: ctx.user.id,
108
+ },
109
+ },
110
+ },
111
+ });
112
+ if (!classData) {
113
+ throw new server_1.TRPCError({
114
+ code: "NOT_FOUND",
115
+ message: "Class not found or you are not a teacher",
116
+ });
117
+ }
118
+ await prisma_1.prisma.section.delete({
119
+ where: { id: input.id },
120
+ });
121
+ return { id: input.id };
122
+ }),
123
+ });
@@ -0,0 +1,49 @@
1
+ import { z } from "zod";
2
+ export declare const userRouter: import("@trpc/server/dist/unstable-core-do-not-import").BuiltRouter<{
3
+ ctx: import("../trpc").Context;
4
+ meta: object;
5
+ errorShape: {
6
+ data: {
7
+ zodError: z.typeToFlattenedError<any, string> | null;
8
+ code: import("@trpc/server/dist/unstable-core-do-not-import").TRPC_ERROR_CODE_KEY;
9
+ httpStatus: number;
10
+ path?: string;
11
+ stack?: string;
12
+ };
13
+ message: string;
14
+ code: import("@trpc/server/dist/unstable-core-do-not-import").TRPC_ERROR_CODE_NUMBER;
15
+ };
16
+ transformer: false;
17
+ }, import("@trpc/server/dist/unstable-core-do-not-import").DecorateCreateRouterOptions<{
18
+ getProfile: import("@trpc/server").TRPCQueryProcedure<{
19
+ input: void;
20
+ output: {
21
+ id: string;
22
+ username: string;
23
+ profile: {
24
+ id: string;
25
+ userId: string;
26
+ } | null;
27
+ };
28
+ }>;
29
+ updateProfile: import("@trpc/server").TRPCMutationProcedure<{
30
+ input: {
31
+ profile: Record<string, any>;
32
+ profilePicture?: {
33
+ type: string;
34
+ name: string;
35
+ data: string;
36
+ size: number;
37
+ } | undefined;
38
+ };
39
+ output: {
40
+ id: string;
41
+ username: string;
42
+ profile: {
43
+ id: string;
44
+ userId: string;
45
+ } | null;
46
+ };
47
+ }>;
48
+ }>>;
49
+ //# sourceMappingURL=user.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../src/routers/user.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAkBxB,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DrB,CAAC"}
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.userRouter = void 0;
4
+ const zod_1 = require("zod");
5
+ const trpc_1 = require("../trpc");
6
+ const server_1 = require("@trpc/server");
7
+ const prisma_1 = require("@lib/prisma");
8
+ const fileUpload_1 = require("@lib/fileUpload");
9
+ const fileSchema = zod_1.z.object({
10
+ name: zod_1.z.string(),
11
+ type: zod_1.z.string(),
12
+ size: zod_1.z.number(),
13
+ data: zod_1.z.string(), // base64 encoded file data
14
+ });
15
+ const updateProfileSchema = zod_1.z.object({
16
+ profile: zod_1.z.record(zod_1.z.any()),
17
+ profilePicture: fileSchema.optional(),
18
+ });
19
+ exports.userRouter = (0, trpc_1.createTRPCRouter)({
20
+ getProfile: trpc_1.protectedProcedure
21
+ .query(async ({ ctx }) => {
22
+ if (!ctx.user) {
23
+ throw new server_1.TRPCError({
24
+ code: "UNAUTHORIZED",
25
+ message: "User must be authenticated",
26
+ });
27
+ }
28
+ const user = await prisma_1.prisma.user.findUnique({
29
+ where: { id: ctx.user.id },
30
+ select: {
31
+ id: true,
32
+ username: true,
33
+ profile: true,
34
+ },
35
+ });
36
+ if (!user) {
37
+ throw new server_1.TRPCError({
38
+ code: "NOT_FOUND",
39
+ message: "User not found",
40
+ });
41
+ }
42
+ return user;
43
+ }),
44
+ updateProfile: trpc_1.protectedProcedure
45
+ .input(updateProfileSchema)
46
+ .mutation(async ({ ctx, input }) => {
47
+ if (!ctx.user) {
48
+ throw new server_1.TRPCError({
49
+ code: "UNAUTHORIZED",
50
+ message: "User must be authenticated",
51
+ });
52
+ }
53
+ let uploadedFiles = [];
54
+ if (input.profilePicture) {
55
+ // Store profile picture in a user-specific directory
56
+ uploadedFiles = await (0, fileUpload_1.uploadFiles)([input.profilePicture], ctx.user.id, `users/${ctx.user.id}/profile`);
57
+ // Add profile picture path to profile data
58
+ input.profile.profilePicture = uploadedFiles[0].path;
59
+ input.profile.profilePictureThumbnail = uploadedFiles[0].thumbnailId;
60
+ }
61
+ const updatedUser = await prisma_1.prisma.user.update({
62
+ where: { id: ctx.user.id },
63
+ data: {
64
+ profile: input.profile,
65
+ },
66
+ select: {
67
+ id: true,
68
+ username: true,
69
+ profile: true,
70
+ },
71
+ });
72
+ return updatedUser;
73
+ }),
74
+ });
@@ -0,0 +1,3 @@
1
+ import { Server } from 'socket.io';
2
+ export declare const setupSocketHandlers: (io: Server) => void;
3
+ //# sourceMappingURL=handlers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/socket/handlers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,MAAM,EAAE,MAAM,WAAW,CAAC;AAG3C,eAAO,MAAM,mBAAmB,GAAI,IAAI,MAAM,SA2I7C,CAAC"}
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setupSocketHandlers = void 0;
4
+ const logger_1 = require("../utils/logger");
5
+ const setupSocketHandlers = (io) => {
6
+ io.on('connection', (socket) => {
7
+ logger_1.logger.info('Client connected', { socketId: socket.id });
8
+ socket.on('disconnect', (reason) => {
9
+ logger_1.logger.info('Client disconnected', { socketId: socket.id, reason });
10
+ });
11
+ socket.on('error', (error) => {
12
+ logger_1.logger.error('Socket error', { socketId: socket.id, error });
13
+ });
14
+ // Class Room Management
15
+ socket.on('create-class', (data) => {
16
+ io.emit('class-created', data.class);
17
+ logger_1.logger.info('Class created', { class: data.class });
18
+ });
19
+ socket.on('delete-class', (data) => {
20
+ io.emit('class-deleted', data.classId);
21
+ logger_1.logger.info('Class deleted', { classId: data.classId });
22
+ });
23
+ socket.on('update-class', (data) => {
24
+ io.emit('class-updated', data.class);
25
+ logger_1.logger.info('Class updated', { class: data.class });
26
+ });
27
+ socket.on('join-class', (classId, callback) => {
28
+ try {
29
+ socket.join(`class-${classId}`);
30
+ logger_1.logger.info('Client joined class room', { socketId: socket.id, classId });
31
+ if (callback) {
32
+ callback(classId);
33
+ }
34
+ else {
35
+ socket.emit('joined-class', classId);
36
+ }
37
+ }
38
+ catch (error) {
39
+ logger_1.logger.error('Error joining class room', { socketId: socket.id, classId, error });
40
+ if (callback) {
41
+ callback(null);
42
+ }
43
+ }
44
+ });
45
+ // Assignment Events
46
+ socket.on('assignment-create', (data) => {
47
+ if (data.classId && data.assignment) {
48
+ io.in(`class-${data.classId}`).emit('assignment-created', data.assignment);
49
+ logger_1.logger.info('Assignment created', { classId: data.classId, assignmentId: data.assignment.id });
50
+ }
51
+ else {
52
+ logger_1.logger.error('Invalid assignment data format', { data });
53
+ }
54
+ });
55
+ socket.on('assignment-update', (data) => {
56
+ io.in(`class-${data.classId}`).emit('assignment-updated', data.assignment);
57
+ logger_1.logger.info('Assignment updated', { classId: data.classId, assignmentId: data.assignment.id });
58
+ });
59
+ socket.on('assignment-delete', (data) => {
60
+ io.in(`class-${data.classId}`).emit('assignment-deleted', data.assignmentId);
61
+ logger_1.logger.info('Assignment deleted', { classId: data.classId, assignmentId: data.assignmentId });
62
+ });
63
+ // Submission Events
64
+ socket.on('submission-update', (data) => {
65
+ io.in(`class-${data.classId}`).emit('submission-updated', data.submission);
66
+ logger_1.logger.info('Submission updated', { classId: data.classId, submissionId: data.submission.id });
67
+ });
68
+ // Announcement Events
69
+ socket.on('new-announcement', (data) => {
70
+ io.in(`class-${data.classId}`).emit('announcement-created', data.announcement);
71
+ logger_1.logger.info('New announcement created', { classId: data.classId, announcementId: data.announcement.id });
72
+ });
73
+ // Section Events
74
+ socket.on('section-create', (data) => {
75
+ io.in(`class-${data.classId}`).emit('section-created', data.section);
76
+ logger_1.logger.info('Section created', { classId: data.classId, sectionId: data.section.id });
77
+ });
78
+ socket.on('section-update', (data) => {
79
+ io.in(`class-${data.classId}`).emit('section-updated', data.section);
80
+ logger_1.logger.info('Section updated', { classId: data.classId, sectionId: data.section.id });
81
+ });
82
+ socket.on('section-delete', (data) => {
83
+ io.in(`class-${data.classId}`).emit('section-deleted', data.sectionId);
84
+ logger_1.logger.info('Section deleted', { classId: data.classId, sectionId: data.sectionId });
85
+ });
86
+ // Member Events
87
+ socket.on('member-update', (data) => {
88
+ io.in(`class-${data.classId}`).emit('member-updated', data.member);
89
+ logger_1.logger.info('Member updated', { classId: data.classId, memberId: data.member.id });
90
+ });
91
+ socket.on('member-delete', (data) => {
92
+ io.in(`class-${data.classId}`).emit('member-deleted', data.memberId);
93
+ logger_1.logger.info('Member deleted', { classId: data.classId, memberId: data.memberId });
94
+ });
95
+ // Attendance Events
96
+ socket.on('attendance-update', (data) => {
97
+ io.in(`class-${data.classId}`).emit('attendance-updated', data.attendance);
98
+ logger_1.logger.info('Attendance updated', { classId: data.classId, attendanceId: data.attendance.id });
99
+ });
100
+ // Event Events
101
+ socket.on('event-create', (data) => {
102
+ if (data.classId) {
103
+ io.in(`class-${data.classId}`).emit('event-created', data.event);
104
+ }
105
+ else {
106
+ io.emit('event-created', data.event);
107
+ }
108
+ logger_1.logger.info('Event created', { classId: data.classId, eventId: data.event.id });
109
+ });
110
+ socket.on('event-update', (data) => {
111
+ if (data.classId) {
112
+ io.in(`class-${data.classId}`).emit('event-updated', data.event);
113
+ }
114
+ else {
115
+ io.emit('event-updated', data.event);
116
+ }
117
+ logger_1.logger.info('Event updated', { classId: data.classId, eventId: data.event.id });
118
+ });
119
+ socket.on('event-delete', (data) => {
120
+ if (data.classId) {
121
+ io.in(`class-${data.classId}`).emit('event-deleted', data.eventId);
122
+ }
123
+ else {
124
+ io.emit('event-deleted', data.eventId);
125
+ }
126
+ logger_1.logger.info('Event deleted', { classId: data.classId, eventId: data.eventId });
127
+ });
128
+ });
129
+ };
130
+ exports.setupSocketHandlers = setupSocketHandlers;
package/dist/trpc.d.ts ADDED
@@ -0,0 +1,147 @@
1
+ import { Request, Response } from 'express';
2
+ import { z } from 'zod';
3
+ interface CreateContextOptions {
4
+ req: Request;
5
+ res: Response;
6
+ }
7
+ export type Context = {
8
+ req: Request;
9
+ res: Response;
10
+ user: {
11
+ id: string;
12
+ } | null;
13
+ meta?: {
14
+ classId?: string;
15
+ institutionId?: string;
16
+ };
17
+ };
18
+ export declare const createTRPCContext: (opts: CreateContextOptions) => Promise<Context>;
19
+ export declare const t: {
20
+ _config: import("@trpc/server/dist/unstable-core-do-not-import").RootConfig<{
21
+ ctx: Context;
22
+ meta: object;
23
+ errorShape: {
24
+ data: {
25
+ zodError: z.typeToFlattenedError<any, string> | null;
26
+ code: import("@trpc/server/dist/unstable-core-do-not-import").TRPC_ERROR_CODE_KEY;
27
+ httpStatus: number;
28
+ path?: string;
29
+ stack?: string;
30
+ };
31
+ message: string;
32
+ code: import("@trpc/server/dist/unstable-core-do-not-import").TRPC_ERROR_CODE_NUMBER;
33
+ };
34
+ transformer: false;
35
+ }>;
36
+ procedure: import("@trpc/server/dist/unstable-core-do-not-import").ProcedureBuilder<Context, object, object, typeof import("@trpc/server/dist/unstable-core-do-not-import").unsetMarker, typeof import("@trpc/server/dist/unstable-core-do-not-import").unsetMarker, typeof import("@trpc/server/dist/unstable-core-do-not-import").unsetMarker, typeof import("@trpc/server/dist/unstable-core-do-not-import").unsetMarker, false>;
37
+ middleware: <$ContextOverrides>(fn: import("@trpc/server/dist/unstable-core-do-not-import").MiddlewareFunction<Context, object, object, $ContextOverrides, unknown>) => import("@trpc/server/dist/unstable-core-do-not-import").MiddlewareBuilder<Context, object, $ContextOverrides, unknown>;
38
+ router: <TInput extends import("@trpc/server/dist/unstable-core-do-not-import").CreateRouterOptions>(input: TInput) => import("@trpc/server/dist/unstable-core-do-not-import").BuiltRouter<{
39
+ ctx: Context;
40
+ meta: object;
41
+ errorShape: {
42
+ data: {
43
+ zodError: z.typeToFlattenedError<any, string> | null;
44
+ code: import("@trpc/server/dist/unstable-core-do-not-import").TRPC_ERROR_CODE_KEY;
45
+ httpStatus: number;
46
+ path?: string;
47
+ stack?: string;
48
+ };
49
+ message: string;
50
+ code: import("@trpc/server/dist/unstable-core-do-not-import").TRPC_ERROR_CODE_NUMBER;
51
+ };
52
+ transformer: false;
53
+ }, import("@trpc/server/dist/unstable-core-do-not-import").DecorateCreateRouterOptions<TInput>>;
54
+ mergeRouters: typeof import("@trpc/server/dist/unstable-core-do-not-import").mergeRouters;
55
+ createCallerFactory: <TRecord extends import("@trpc/server").RouterRecord>(router: Pick<import("@trpc/server/dist/unstable-core-do-not-import").Router<{
56
+ ctx: Context;
57
+ meta: object;
58
+ errorShape: {
59
+ data: {
60
+ zodError: z.typeToFlattenedError<any, string> | null;
61
+ code: import("@trpc/server/dist/unstable-core-do-not-import").TRPC_ERROR_CODE_KEY;
62
+ httpStatus: number;
63
+ path?: string;
64
+ stack?: string;
65
+ };
66
+ message: string;
67
+ code: import("@trpc/server/dist/unstable-core-do-not-import").TRPC_ERROR_CODE_NUMBER;
68
+ };
69
+ transformer: false;
70
+ }, TRecord>, "_def">) => import("@trpc/server/dist/unstable-core-do-not-import").RouterCaller<{
71
+ ctx: Context;
72
+ meta: object;
73
+ errorShape: {
74
+ data: {
75
+ zodError: z.typeToFlattenedError<any, string> | null;
76
+ code: import("@trpc/server/dist/unstable-core-do-not-import").TRPC_ERROR_CODE_KEY;
77
+ httpStatus: number;
78
+ path?: string;
79
+ stack?: string;
80
+ };
81
+ message: string;
82
+ code: import("@trpc/server/dist/unstable-core-do-not-import").TRPC_ERROR_CODE_NUMBER;
83
+ };
84
+ transformer: false;
85
+ }, TRecord>;
86
+ };
87
+ export declare const createTRPCRouter: <TInput extends import("@trpc/server/dist/unstable-core-do-not-import").CreateRouterOptions>(input: TInput) => import("@trpc/server/dist/unstable-core-do-not-import").BuiltRouter<{
88
+ ctx: Context;
89
+ meta: object;
90
+ errorShape: {
91
+ data: {
92
+ zodError: z.typeToFlattenedError<any, string> | null;
93
+ code: import("@trpc/server/dist/unstable-core-do-not-import").TRPC_ERROR_CODE_KEY;
94
+ httpStatus: number;
95
+ path?: string;
96
+ stack?: string;
97
+ };
98
+ message: string;
99
+ code: import("@trpc/server/dist/unstable-core-do-not-import").TRPC_ERROR_CODE_NUMBER;
100
+ };
101
+ transformer: false;
102
+ }, import("@trpc/server/dist/unstable-core-do-not-import").DecorateCreateRouterOptions<TInput>>;
103
+ export declare const publicProcedure: import("@trpc/server/dist/unstable-core-do-not-import").ProcedureBuilder<Context, object, {}, typeof import("@trpc/server/dist/unstable-core-do-not-import").unsetMarker, typeof import("@trpc/server/dist/unstable-core-do-not-import").unsetMarker, typeof import("@trpc/server/dist/unstable-core-do-not-import").unsetMarker, typeof import("@trpc/server/dist/unstable-core-do-not-import").unsetMarker, false>;
104
+ export declare const protectedProcedure: import("@trpc/server/dist/unstable-core-do-not-import").ProcedureBuilder<Context, object, {}, typeof import("@trpc/server/dist/unstable-core-do-not-import").unsetMarker, typeof import("@trpc/server/dist/unstable-core-do-not-import").unsetMarker, typeof import("@trpc/server/dist/unstable-core-do-not-import").unsetMarker, typeof import("@trpc/server/dist/unstable-core-do-not-import").unsetMarker, false>;
105
+ export declare const protectedClassMemberProcedure: import("@trpc/server/dist/unstable-core-do-not-import").ProcedureBuilder<Context, object, {}, z.objectInputType<{
106
+ classId: z.ZodString;
107
+ }, z.ZodTypeAny, "passthrough">, z.objectOutputType<{
108
+ classId: z.ZodString;
109
+ }, z.ZodTypeAny, "passthrough">, typeof import("@trpc/server/dist/unstable-core-do-not-import").unsetMarker, typeof import("@trpc/server/dist/unstable-core-do-not-import").unsetMarker, false>;
110
+ export declare const protectedTeacherProcedure: import("@trpc/server/dist/unstable-core-do-not-import").ProcedureBuilder<Context, object, {}, z.objectInputType<{
111
+ classId: z.ZodString;
112
+ }, z.ZodTypeAny, "passthrough">, z.objectOutputType<{
113
+ classId: z.ZodString;
114
+ }, z.ZodTypeAny, "passthrough">, typeof import("@trpc/server/dist/unstable-core-do-not-import").unsetMarker, typeof import("@trpc/server/dist/unstable-core-do-not-import").unsetMarker, false>;
115
+ export declare const createCallerFactory: <TRecord extends import("@trpc/server").RouterRecord>(router: Pick<import("@trpc/server/dist/unstable-core-do-not-import").Router<{
116
+ ctx: Context;
117
+ meta: object;
118
+ errorShape: {
119
+ data: {
120
+ zodError: z.typeToFlattenedError<any, string> | null;
121
+ code: import("@trpc/server/dist/unstable-core-do-not-import").TRPC_ERROR_CODE_KEY;
122
+ httpStatus: number;
123
+ path?: string;
124
+ stack?: string;
125
+ };
126
+ message: string;
127
+ code: import("@trpc/server/dist/unstable-core-do-not-import").TRPC_ERROR_CODE_NUMBER;
128
+ };
129
+ transformer: false;
130
+ }, TRecord>, "_def">) => import("@trpc/server/dist/unstable-core-do-not-import").RouterCaller<{
131
+ ctx: Context;
132
+ meta: object;
133
+ errorShape: {
134
+ data: {
135
+ zodError: z.typeToFlattenedError<any, string> | null;
136
+ code: import("@trpc/server/dist/unstable-core-do-not-import").TRPC_ERROR_CODE_KEY;
137
+ httpStatus: number;
138
+ path?: string;
139
+ stack?: string;
140
+ };
141
+ message: string;
142
+ code: import("@trpc/server/dist/unstable-core-do-not-import").TRPC_ERROR_CODE_NUMBER;
143
+ };
144
+ transformer: false;
145
+ }, TRecord>;
146
+ export {};
147
+ //# sourceMappingURL=trpc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trpc.d.ts","sourceRoot":"","sources":["../src/trpc.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,UAAU,oBAAoB;IAC5B,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,EAAE,QAAQ,CAAC;CACf;AAED,MAAM,MAAM,OAAO,GAAG;IACpB,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,EAAE,QAAQ,CAAC;IACd,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC5B,IAAI,CAAC,EAAE;QACL,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;CACH,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAU,MAAM,oBAAoB,KAAG,OAAO,CAAC,OAAO,CAwBnF,CAAC;AAEF,eAAO,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkBZ,CAAC;AAOH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;+FAAW,CAAC;AACzC,eAAO,MAAM,eAAe,sZAAqC,CAAC;AAGlE,eAAO,MAAM,kBAAkB,sZAAgC,CAAC;AAChE,eAAO,MAAM,6BAA6B;;;;+LAEnB,CAAC;AACxB,eAAO,MAAM,yBAAyB;;;;+LAEd,CAAC;AAIzB,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAAwB,CAAC"}
package/dist/trpc.js ADDED
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createCallerFactory = exports.protectedTeacherProcedure = exports.protectedClassMemberProcedure = exports.protectedProcedure = exports.publicProcedure = exports.createTRPCRouter = exports.t = exports.createTRPCContext = void 0;
4
+ const server_1 = require("@trpc/server");
5
+ const zod_1 = require("zod");
6
+ const logger_1 = require("@utils/logger");
7
+ const prisma_1 = require("@lib/prisma");
8
+ const logging_1 = require("./middleware/logging");
9
+ const auth_1 = require("./middleware/auth");
10
+ const zod_2 = require("zod");
11
+ const createTRPCContext = async (opts) => {
12
+ const { req, res } = opts;
13
+ // Get user from session/token
14
+ const token = req.headers.authorization?.split(' ')[1];
15
+ const user = token ? await prisma_1.prisma.user.findFirst({
16
+ where: {
17
+ sessions: {
18
+ some: {
19
+ id: token
20
+ }
21
+ },
22
+ },
23
+ select: {
24
+ id: true,
25
+ }
26
+ }) : null;
27
+ return {
28
+ req,
29
+ res,
30
+ user,
31
+ meta: {},
32
+ };
33
+ };
34
+ exports.createTRPCContext = createTRPCContext;
35
+ exports.t = server_1.initTRPC.context().create({
36
+ errorFormatter({ shape, error }) {
37
+ logger_1.logger.error('tRPC Error', {
38
+ code: shape.code,
39
+ message: error.message,
40
+ cause: error.cause,
41
+ stack: error.stack,
42
+ });
43
+ return {
44
+ ...shape,
45
+ data: {
46
+ ...shape.data,
47
+ zodError: error.cause instanceof zod_1.ZodError ? error.cause.flatten() : null,
48
+ },
49
+ };
50
+ },
51
+ });
52
+ // Create middleware
53
+ const loggingMiddleware = (0, logging_1.createLoggingMiddleware)(exports.t);
54
+ const { isAuthed, isMemberInClass, isTeacherInClass } = (0, auth_1.createAuthMiddleware)(exports.t);
55
+ // Base procedures
56
+ exports.createTRPCRouter = exports.t.router;
57
+ exports.publicProcedure = exports.t.procedure.use(loggingMiddleware);
58
+ // Protected procedures
59
+ exports.protectedProcedure = exports.publicProcedure.use(isAuthed);
60
+ exports.protectedClassMemberProcedure = exports.protectedProcedure
61
+ .input(zod_2.z.object({ classId: zod_2.z.string() }).passthrough())
62
+ .use(isMemberInClass);
63
+ exports.protectedTeacherProcedure = exports.protectedProcedure
64
+ .input(zod_2.z.object({ classId: zod_2.z.string() }).passthrough())
65
+ .use(isTeacherInClass);
66
+ // Create caller factory
67
+ exports.createCallerFactory = exports.t.createCallerFactory;
@@ -0,0 +1,16 @@
1
+ import { inferAsyncReturnType } from '@trpc/server';
2
+ import { createTRPCContext } from '../trpc';
3
+ export type Context = inferAsyncReturnType<typeof createTRPCContext> & {
4
+ isTeacher?: boolean;
5
+ teacherClassIds?: string[];
6
+ };
7
+ export interface MiddlewareContext {
8
+ ctx: Context;
9
+ next: (opts?: {
10
+ ctx: Partial<Context>;
11
+ }) => Promise<any>;
12
+ input?: any;
13
+ path?: string;
14
+ type?: string;
15
+ }
16
+ //# sourceMappingURL=trpc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trpc.d.ts","sourceRoot":"","sources":["../../src/types/trpc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAE5C,MAAM,MAAM,OAAO,GAAG,oBAAoB,CAAC,OAAO,iBAAiB,CAAC,GAAG;IACrE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,OAAO,CAAC;IACb,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE;QAAE,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;KAAE,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IACzD,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,3 @@
1
+ import nodemailer from 'nodemailer';
2
+ export declare const transport: nodemailer.Transporter<import("nodemailer/lib/smtp-transport").SentMessageInfo, import("nodemailer/lib/smtp-transport").Options>;
3
+ //# sourceMappingURL=email.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email.d.ts","sourceRoot":"","sources":["../../src/utils/email.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,YAAY,CAAC;AAEpC,eAAO,MAAM,SAAS,kIAQlB,CAAC"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.transport = void 0;
7
+ const nodemailer_1 = __importDefault(require("nodemailer"));
8
+ exports.transport = nodemailer_1.default.createTransport({
9
+ host: process.env.EMAIL_HOST,
10
+ port: 587,
11
+ secure: false,
12
+ auth: {
13
+ user: process.env.EMAIL_USER,
14
+ pass: process.env.EMAIL_PASS,
15
+ },
16
+ });
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Generates a random invite code
3
+ * @returns {string} The invite code with length 5
4
+ */
5
+ export declare const generateInviteCode: () => string;
6
+ //# sourceMappingURL=generateInviteCode.d.ts.map