@studious-lms/server 1.4.0 → 1.4.2

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 (166) hide show
  1. package/.env.example +6 -0
  2. package/.env.test.example +2 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +36 -50
  5. package/dist/index.js.map +1 -1
  6. package/dist/lib/config/cors.d.ts +16 -0
  7. package/dist/lib/config/cors.d.ts.map +1 -0
  8. package/dist/lib/config/cors.js +75 -0
  9. package/dist/lib/config/cors.js.map +1 -0
  10. package/dist/lib/config/env.d.ts +14 -0
  11. package/dist/lib/config/env.d.ts.map +1 -1
  12. package/dist/lib/config/env.js +9 -2
  13. package/dist/lib/config/env.js.map +1 -1
  14. package/dist/lib/prisma.d.ts +14 -2
  15. package/dist/lib/prisma.d.ts.map +1 -1
  16. package/dist/lib/prisma.js +27 -8
  17. package/dist/lib/prisma.js.map +1 -1
  18. package/dist/middleware/security.d.ts.map +1 -1
  19. package/dist/middleware/security.js +3 -3
  20. package/dist/middleware/security.js.map +1 -1
  21. package/dist/models/agenda.d.ts +16 -16
  22. package/dist/models/announcement.d.ts +59 -23
  23. package/dist/models/announcement.d.ts.map +1 -1
  24. package/dist/models/assignment.d.ts +363 -276
  25. package/dist/models/assignment.d.ts.map +1 -1
  26. package/dist/models/attendance.d.ts +63 -21
  27. package/dist/models/attendance.d.ts.map +1 -1
  28. package/dist/models/auth.d.ts +102 -18
  29. package/dist/models/auth.d.ts.map +1 -1
  30. package/dist/models/class.d.ts +112 -64
  31. package/dist/models/class.d.ts.map +1 -1
  32. package/dist/models/comment.d.ts +52 -16
  33. package/dist/models/comment.d.ts.map +1 -1
  34. package/dist/models/conversation.d.ts +46 -16
  35. package/dist/models/conversation.d.ts.map +1 -1
  36. package/dist/models/event.d.ts +107 -53
  37. package/dist/models/event.d.ts.map +1 -1
  38. package/dist/models/file.d.ts +213 -165
  39. package/dist/models/file.d.ts.map +1 -1
  40. package/dist/models/folder.d.ts +161 -77
  41. package/dist/models/folder.d.ts.map +1 -1
  42. package/dist/models/labChat.d.ts +73 -31
  43. package/dist/models/labChat.d.ts.map +1 -1
  44. package/dist/models/marketing.d.ts +25 -7
  45. package/dist/models/marketing.d.ts.map +1 -1
  46. package/dist/models/message.d.ts +31 -13
  47. package/dist/models/message.d.ts.map +1 -1
  48. package/dist/models/newtonChat.d.ts +34 -10
  49. package/dist/models/newtonChat.d.ts.map +1 -1
  50. package/dist/models/notification.d.ts +25 -7
  51. package/dist/models/notification.d.ts.map +1 -1
  52. package/dist/models/section.d.ts +71 -23
  53. package/dist/models/section.d.ts.map +1 -1
  54. package/dist/models/user.d.ts +27 -9
  55. package/dist/models/user.d.ts.map +1 -1
  56. package/dist/models/worksheet.d.ts +237 -108
  57. package/dist/models/worksheet.d.ts.map +1 -1
  58. package/dist/pipelines/aiLabChat.d.ts +30 -6
  59. package/dist/pipelines/aiLabChat.d.ts.map +1 -1
  60. package/dist/pipelines/aiLabChat.js +157 -234
  61. package/dist/pipelines/aiLabChat.js.map +1 -1
  62. package/dist/pipelines/aiLabChatContract.d.ts +413 -0
  63. package/dist/pipelines/aiLabChatContract.d.ts.map +1 -0
  64. package/dist/pipelines/aiLabChatContract.js +74 -0
  65. package/dist/pipelines/aiLabChatContract.js.map +1 -0
  66. package/dist/pipelines/gradeWorksheet.d.ts +8 -8
  67. package/dist/pipelines/gradeWorksheet.js +4 -4
  68. package/dist/pipelines/gradeWorksheet.js.map +1 -1
  69. package/dist/pipelines/labChatPrompt.d.ts +29 -0
  70. package/dist/pipelines/labChatPrompt.d.ts.map +1 -0
  71. package/dist/pipelines/labChatPrompt.js +146 -0
  72. package/dist/pipelines/labChatPrompt.js.map +1 -0
  73. package/dist/routers/_app.d.ts +1622 -1260
  74. package/dist/routers/_app.d.ts.map +1 -1
  75. package/dist/routers/_app.js +4 -2
  76. package/dist/routers/_app.js.map +1 -1
  77. package/dist/routers/agenda.d.ts +16 -16
  78. package/dist/routers/announcement.d.ts +19 -19
  79. package/dist/routers/assignment.d.ts +307 -291
  80. package/dist/routers/assignment.d.ts.map +1 -1
  81. package/dist/routers/assignment.js +3 -2
  82. package/dist/routers/assignment.js.map +1 -1
  83. package/dist/routers/attendance.d.ts +7 -7
  84. package/dist/routers/auth.d.ts +1 -1
  85. package/dist/routers/class.d.ts +77 -71
  86. package/dist/routers/class.d.ts.map +1 -1
  87. package/dist/routers/comment.d.ts +6 -6
  88. package/dist/routers/conversation.d.ts +11 -11
  89. package/dist/routers/event.d.ts +35 -35
  90. package/dist/routers/file.d.ts +12 -12
  91. package/dist/routers/folder.d.ts +54 -54
  92. package/dist/routers/labChat.d.ts +12 -12
  93. package/dist/routers/marketing.d.ts +2 -2
  94. package/dist/routers/message.d.ts +2 -2
  95. package/dist/routers/newtonChat.d.ts +1 -1
  96. package/dist/routers/notifications.d.ts +4 -4
  97. package/dist/routers/section.d.ts +7 -7
  98. package/dist/routers/studentProgress.d.ts +161 -0
  99. package/dist/routers/studentProgress.d.ts.map +1 -0
  100. package/dist/routers/studentProgress.js +43 -0
  101. package/dist/routers/studentProgress.js.map +1 -0
  102. package/dist/routers/user.d.ts +1 -1
  103. package/dist/routers/worksheet.d.ts +58 -58
  104. package/dist/seedDatabase.d.ts +1 -1
  105. package/dist/services/agenda.d.ts +16 -16
  106. package/dist/services/announcement.d.ts +8 -8
  107. package/dist/services/assignment.d.ts +299 -283
  108. package/dist/services/assignment.d.ts.map +1 -1
  109. package/dist/services/assignment.js +24 -5
  110. package/dist/services/assignment.js.map +1 -1
  111. package/dist/services/attendance.d.ts +7 -7
  112. package/dist/services/auth.d.ts +1 -1
  113. package/dist/services/class.d.ts +73 -67
  114. package/dist/services/class.d.ts.map +1 -1
  115. package/dist/services/comment.d.ts +6 -6
  116. package/dist/services/conversation.d.ts +11 -11
  117. package/dist/services/event.d.ts +31 -31
  118. package/dist/services/file.d.ts +12 -12
  119. package/dist/services/folder.d.ts +52 -52
  120. package/dist/services/labChat.d.ts +12 -12
  121. package/dist/services/labChat.d.ts.map +1 -1
  122. package/dist/services/labChat.js +31 -15
  123. package/dist/services/labChat.js.map +1 -1
  124. package/dist/services/marketing.d.ts +2 -2
  125. package/dist/services/message.d.ts.map +1 -1
  126. package/dist/services/message.js +90 -48
  127. package/dist/services/message.js.map +1 -1
  128. package/dist/services/notification.d.ts +4 -4
  129. package/dist/services/section.d.ts +6 -6
  130. package/dist/services/studentProgress.d.ts +120 -0
  131. package/dist/services/studentProgress.d.ts.map +1 -0
  132. package/dist/services/studentProgress.js +481 -0
  133. package/dist/services/studentProgress.js.map +1 -0
  134. package/dist/services/worksheet.d.ts +49 -49
  135. package/dist/utils/inference.d.ts +0 -11
  136. package/dist/utils/inference.d.ts.map +1 -1
  137. package/dist/utils/inference.js +2 -50
  138. package/dist/utils/inference.js.map +1 -1
  139. package/package.json +2 -2
  140. package/prisma/migrations/20260410124000_add_submission_recommendation_state/migration.sql +14 -0
  141. package/prisma/schema.prisma +14 -0
  142. package/sentry.properties +3 -0
  143. package/src/index.ts +39 -51
  144. package/src/lib/config/cors.ts +96 -0
  145. package/src/lib/config/env.ts +12 -1
  146. package/src/lib/prisma.ts +25 -6
  147. package/src/middleware/security.ts +1 -1
  148. package/src/pipelines/aiLabChat.ts +206 -246
  149. package/src/pipelines/aiLabChatContract.ts +75 -0
  150. package/src/pipelines/gradeWorksheet.ts +2 -2
  151. package/src/pipelines/labChatPrompt.ts +196 -0
  152. package/src/routers/_app.ts +4 -2
  153. package/src/routers/assignment.ts +1 -0
  154. package/src/routers/studentProgress.ts +71 -0
  155. package/src/services/assignment.ts +30 -2
  156. package/src/services/labChat.ts +31 -22
  157. package/src/services/message.ts +97 -48
  158. package/src/services/studentProgress.ts +691 -0
  159. package/src/utils/inference.ts +0 -61
  160. package/tests/lib/aiLabChatContract.test.ts +32 -0
  161. package/tests/lib/cors.test.ts +103 -0
  162. package/tests/pipelines/aiLabChat.test.ts +75 -0
  163. package/tests/routers/studentProgress.test.ts +254 -0
  164. package/tests/utils/aiLabChatPrompt.test.ts +126 -0
  165. package/tests/utils/studentProgress.test.ts +361 -0
  166. package/vitest.unit.config.ts +8 -1
@@ -1 +1 @@
1
- {"version":3,"file":"env.js","sources":["lib/config/env.ts"],"sourceRoot":"/","sourcesContent":["import { z } from 'zod';\nimport dotenv from 'dotenv';\nimport { resolve } from 'path';\nimport { logger } from '../../utils/logger.js';\n\n// Determine which env file to load based on NODE_ENV\nconst nodeEnv = process.env.NODE_ENV || 'development';\nconst envFileMap: Record<string, string> = {\n test: '.env.test',\n development: '.env.development',\n production: '.env.production',\n};\n\n// Load the appropriate env file\nconst envFile = envFileMap[nodeEnv] || '.env';\nconst envPath = resolve(process.cwd(), envFile);\n\n// Load environment variables from the correct file\n// First load .env (base), then override with environment-specific file\ndotenv.config(); // Load .env first (base config)\ndotenv.config({ path: envPath, override: true }); // Override with env-specific\n\nconst isTest = nodeEnv === 'test';\nconst isProduction = nodeEnv === 'production';\n\n// Base schema with required vars for all environments\nconst baseSchema = z.object({\n NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),\n PORT: z.string().transform(Number).default('3001'),\n DATABASE_URL: z.string().url('DATABASE_URL must be a valid URL'),\n});\n\n// Production/development schema with all required vars\nconst fullSchema = baseSchema.extend({\n NEXT_PUBLIC_APP_URL: z.string().url().default('http://localhost:3000'),\n BACKEND_URL: z.string().url().default('http://localhost:3001'),\n SENTRY_DSN: z.string().url().optional(),\n EMAIL_HOST: z.string().min(1, 'EMAIL_HOST is required'),\n EMAIL_PORT: z.string().transform(Number).default('587'),\n EMAIL_USER: z.string().email('EMAIL_USER must be a valid email'),\n EMAIL_PASS: z.string().min(1, 'EMAIL_PASS is required'),\n EMAIL_DRY_RUN: z.string().optional().default('false'),\n GOOGLE_CLOUD_PROJECT_ID: z.string().min(1, 'GOOGLE_CLOUD_PROJECT_ID is required'),\n GOOGLE_CLOUD_CLIENT_EMAIL: z.string().email('GOOGLE_CLOUD_CLIENT_EMAIL must be a valid email'),\n GOOGLE_CLOUD_PRIVATE_KEY: z.string().min(1, 'GOOGLE_CLOUD_PRIVATE_KEY is required'),\n GOOGLE_CLOUD_BUCKET_NAME: z.string().min(1, 'GOOGLE_CLOUD_BUCKET_NAME is required'),\n PUSHER_APP_ID: z.string().min(1, 'PUSHER_APP_ID is required'),\n PUSHER_KEY: z.string().min(1, 'PUSHER_KEY is required'),\n PUSHER_SECRET: z.string().min(1, 'PUSHER_SECRET is required'),\n PUSHER_CLUSTER: z.string().min(1, 'PUSHER_CLUSTER is required'),\n PUSHER_AUTH_COOKIE_NAME: z.string().optional(), // Cookie name for session token (default: 'token')\n REDIS_URL: z.string().url().optional(), // Redis connection URL (e.g. redis://localhost:6379)\n INFERENCE_API_KEY: z.string().optional(),\n INFERENCE_API_BASE_URL: z.string().url().optional(),\n OPENAI_API_KEY: z.string().optional(),\n LOG_MODE: z.enum(['normal', 'verbose', 'quiet']).default('normal'),\n});\n\n// Test schema - only require what's needed for tests\nconst testSchema = baseSchema.extend({\n NEXT_PUBLIC_APP_URL: z.string().url().optional().default('http://localhost:3000'),\n BACKEND_URL: z.string().url().optional().default('http://localhost:3001'),\n SENTRY_DSN: z.string().url().optional(),\n EMAIL_HOST: z.string().optional().default('smtp.test.com'),\n EMAIL_PORT: z.string().transform(Number).default('587'),\n EMAIL_USER: z.string().email().optional().default('test@test.com'),\n EMAIL_PASS: z.string().optional().default('test'),\n EMAIL_DRY_RUN: z.string().optional().default('false'),\n GOOGLE_CLOUD_PROJECT_ID: z.string().optional().default('test-project'),\n GOOGLE_CLOUD_CLIENT_EMAIL: z.string().email().optional().default('test@test.iam.gserviceaccount.com'),\n GOOGLE_CLOUD_PRIVATE_KEY: z.string().optional().default('test-key'),\n GOOGLE_CLOUD_BUCKET_NAME: z.string().optional().default('test-bucket'),\n PUSHER_APP_ID: z.string().optional().default('test-app-id'),\n PUSHER_KEY: z.string().optional().default('test-key'),\n PUSHER_SECRET: z.string().optional().default('test-secret'),\n PUSHER_CLUSTER: z.string().optional().default('us2'),\n PUSHER_AUTH_COOKIE_NAME: z.string().optional(),\n REDIS_URL: z.string().url().optional(),\n INFERENCE_API_KEY: z.string().optional(),\n OPENAI_API_KEY: z.string().optional(),\n INFERENCE_API_BASE_URL: z.string().url().optional(),\n LOG_MODE: z.enum(['normal', 'verbose', 'quiet']).default('quiet'),\n});\n\n// Use test schema in test mode, full schema otherwise\nconst envSchema = isTest ? testSchema : fullSchema;\n\n// Validate environment variables\nfunction validateEnv() {\n try {\n const parsed = envSchema.parse(process.env);\n \n // Only exit on validation failure in production\n if (isProduction && !parsed.DATABASE_URL) {\n logger.error('DATABASE_URL is required in production');\n process.exit(1);\n }\n \n return parsed;\n } catch (error) {\n if (error instanceof z.ZodError) {\n const missingVars = error.errors.map(err => ({\n path: err.path.join('.'),\n message: err.message,\n }));\n \n logger.error('Environment variable validation failed', {\n envFile,\n missingVars,\n });\n \n // Only exit in production - in test/dev, log warning but continue\n if (isProduction) {\n logger.error(`Please check your ${envFile} file and ensure all required variables are set.`);\n process.exit(1);\n } else {\n logger.warn('Continuing with defaults - some features may not work correctly', {\n envFile,\n });\n // Return parsed with defaults for non-production\n return envSchema.parse({ ...process.env });\n }\n }\n throw error;\n }\n}\n\n// Export validated environment variables\nexport const env = validateEnv();\n\n// Type-safe environment access\nexport type Env = z.infer<typeof envSchema>;"],"names":[],"mappings":"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","debug_id":"6fe796c8-7781-5540-892a-a320464bfbae"}
1
+ {"version":3,"file":"env.js","sources":["lib/config/env.ts"],"sourceRoot":"/","sourcesContent":["import { z } from 'zod';\nimport dotenv from 'dotenv';\nimport { resolve } from 'path';\nimport { logger } from '../../utils/logger.js';\nimport { isValidCorsOriginPatternList } from './cors.js';\n\n// Determine which env file to load based on NODE_ENV\nconst nodeEnv = process.env.NODE_ENV || 'development';\nconst envFileMap: Record<string, string> = {\n test: '.env.test',\n development: '.env.development',\n production: '.env.production',\n};\n\n// Load the appropriate env file\nconst envFile = envFileMap[nodeEnv] || '.env';\nconst envPath = resolve(process.cwd(), envFile);\n\n// Load environment variables from the correct file\n// First load .env (base), then override with environment-specific file\ndotenv.config(); // Load .env first (base config)\ndotenv.config({ path: envPath, override: true }); // Override with env-specific\n\nconst isTest = nodeEnv === 'test';\nconst isProduction = nodeEnv === 'production';\n\nconst corsAllowedOriginsSchema = z.string().optional();\nconst corsAllowedOriginPatternsSchema = z.string().optional().refine(\n isValidCorsOriginPatternList,\n { message: 'CORS_ALLOWED_ORIGIN_PATTERNS must contain valid regex patterns' }\n);\n\n// Base schema with required vars for all environments\nconst baseSchema = z.object({\n NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),\n PORT: z.string().transform(Number).default('3001'),\n DATABASE_URL: z.string().url('DATABASE_URL must be a valid URL'),\n});\n\n// Production/development schema with all required vars\nconst fullSchema = baseSchema.extend({\n NEXT_PUBLIC_APP_URL: z.string().url().default('http://localhost:3000'),\n CORS_ALLOWED_ORIGINS: corsAllowedOriginsSchema,\n CORS_ALLOWED_ORIGIN_PATTERNS: corsAllowedOriginPatternsSchema,\n BACKEND_URL: z.string().url().default('http://localhost:3001'),\n SENTRY_DSN: z.string().url().optional(),\n EMAIL_HOST: z.string().min(1, 'EMAIL_HOST is required'),\n EMAIL_PORT: z.string().transform(Number).default('587'),\n EMAIL_USER: z.string().email('EMAIL_USER must be a valid email'),\n EMAIL_PASS: z.string().min(1, 'EMAIL_PASS is required'),\n EMAIL_DRY_RUN: z.string().optional().default('false'),\n GOOGLE_CLOUD_PROJECT_ID: z.string().min(1, 'GOOGLE_CLOUD_PROJECT_ID is required'),\n GOOGLE_CLOUD_CLIENT_EMAIL: z.string().email('GOOGLE_CLOUD_CLIENT_EMAIL must be a valid email'),\n GOOGLE_CLOUD_PRIVATE_KEY: z.string().min(1, 'GOOGLE_CLOUD_PRIVATE_KEY is required'),\n GOOGLE_CLOUD_BUCKET_NAME: z.string().min(1, 'GOOGLE_CLOUD_BUCKET_NAME is required'),\n PUSHER_APP_ID: z.string().min(1, 'PUSHER_APP_ID is required'),\n PUSHER_KEY: z.string().min(1, 'PUSHER_KEY is required'),\n PUSHER_SECRET: z.string().min(1, 'PUSHER_SECRET is required'),\n PUSHER_CLUSTER: z.string().min(1, 'PUSHER_CLUSTER is required'),\n PUSHER_AUTH_COOKIE_NAME: z.string().optional(), // Cookie name for session token (default: 'token')\n REDIS_URL: z.string().url().optional(), // Redis connection URL (e.g. redis://localhost:6379)\n INFERENCE_API_KEY: z.string().optional(),\n INFERENCE_API_BASE_URL: z.string().url().optional(),\n OPENAI_API_KEY: z.string().optional(),\n LOG_MODE: z.enum(['normal', 'verbose', 'quiet']).default('normal'),\n});\n\n// Test schema - only require what's needed for tests\nconst testSchema = baseSchema.extend({\n NEXT_PUBLIC_APP_URL: z.string().url().optional().default('http://localhost:3000'),\n CORS_ALLOWED_ORIGINS: corsAllowedOriginsSchema,\n CORS_ALLOWED_ORIGIN_PATTERNS: corsAllowedOriginPatternsSchema,\n BACKEND_URL: z.string().url().optional().default('http://localhost:3001'),\n SENTRY_DSN: z.string().url().optional(),\n EMAIL_HOST: z.string().optional().default('smtp.test.com'),\n EMAIL_PORT: z.string().transform(Number).default('587'),\n EMAIL_USER: z.string().email().optional().default('test@test.com'),\n EMAIL_PASS: z.string().optional().default('test'),\n EMAIL_DRY_RUN: z.string().optional().default('false'),\n GOOGLE_CLOUD_PROJECT_ID: z.string().optional().default('test-project'),\n GOOGLE_CLOUD_CLIENT_EMAIL: z.string().email().optional().default('test@test.iam.gserviceaccount.com'),\n GOOGLE_CLOUD_PRIVATE_KEY: z.string().optional().default('test-key'),\n GOOGLE_CLOUD_BUCKET_NAME: z.string().optional().default('test-bucket'),\n PUSHER_APP_ID: z.string().optional().default('test-app-id'),\n PUSHER_KEY: z.string().optional().default('test-key'),\n PUSHER_SECRET: z.string().optional().default('test-secret'),\n PUSHER_CLUSTER: z.string().optional().default('us2'),\n PUSHER_AUTH_COOKIE_NAME: z.string().optional(),\n REDIS_URL: z.string().url().optional(),\n INFERENCE_API_KEY: z.string().optional(),\n OPENAI_API_KEY: z.string().optional(),\n INFERENCE_API_BASE_URL: z.string().url().optional(),\n LOG_MODE: z.enum(['normal', 'verbose', 'quiet']).default('quiet'),\n});\n\n// Use test schema in test mode, full schema otherwise\nconst envSchema = isTest ? testSchema : fullSchema;\n\n// Validate environment variables\nfunction validateEnv() {\n try {\n const parsed = envSchema.parse(process.env);\n \n // Only exit on validation failure in production\n if (isProduction && !parsed.DATABASE_URL) {\n logger.error('DATABASE_URL is required in production');\n process.exit(1);\n }\n \n return parsed;\n } catch (error) {\n if (error instanceof z.ZodError) {\n const missingVars = error.errors.map(err => ({\n path: err.path.join('.'),\n message: err.message,\n }));\n \n logger.error('Environment variable validation failed', {\n envFile,\n missingVars,\n });\n \n // Only exit in production - in test/dev, log warning but continue\n if (isProduction) {\n logger.error(`Please check your ${envFile} file and ensure all required variables are set.`);\n process.exit(1);\n } else {\n logger.warn('Continuing with defaults - some features may not work correctly', {\n envFile,\n });\n // Return parsed with defaults for non-production\n return envSchema.parse({ ...process.env });\n }\n }\n throw error;\n }\n}\n\n// Export validated environment variables\nexport const env = validateEnv();\n\n// Type-safe environment access\nexport type Env = z.infer<typeof envSchema>;\n"],"names":[],"mappings":"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","debug_id":"2c09f0e4-0311-5ba3-bfea-895c59d8b314"}
@@ -1,8 +1,20 @@
1
1
  import { PrismaClient } from '@prisma/client';
2
- declare const prismaClientSingleton: () => PrismaClient<import(".prisma/client").Prisma.PrismaClientOptions, never, import("@prisma/client/runtime/library.js").DefaultArgs>;
2
+ declare const prismaClientSingleton: () => PrismaClient<{
3
+ datasources: {
4
+ db: {
5
+ url: string;
6
+ };
7
+ };
8
+ }, never, import("@prisma/client/runtime/library.js").DefaultArgs>;
3
9
  declare global {
4
10
  var prisma: undefined | ReturnType<typeof prismaClientSingleton>;
5
11
  }
6
- export declare const prisma: PrismaClient<import(".prisma/client").Prisma.PrismaClientOptions, never, import("@prisma/client/runtime/library.js").DefaultArgs>;
12
+ export declare const prisma: PrismaClient<{
13
+ datasources: {
14
+ db: {
15
+ url: string;
16
+ };
17
+ };
18
+ }, never, import("@prisma/client/runtime/library.js").DefaultArgs>;
7
19
  export {};
8
20
  //# sourceMappingURL=prisma.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"prisma.d.ts","sourceRoot":"/","sources":["lib/prisma.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAc9C,QAAA,MAAM,qBAAqB,yIAO1B,CAAC;AAGF,OAAO,CAAC,MAAM,CAAC;IACb,IAAI,MAAM,EAAE,SAAS,GAAG,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC;CAClE;AAED,eAAO,MAAM,MAAM,mIAA+C,CAAC"}
1
+ {"version":3,"file":"prisma.d.ts","sourceRoot":"/","sources":["lib/prisma.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAgC9C,QAAA,MAAM,qBAAqB;;;;;;kEAQ1B,CAAC;AAGF,OAAO,CAAC,MAAM,CAAC;IACb,IAAI,MAAM,EAAE,SAAS,GAAG,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC;CAClE;AAED,eAAO,MAAM,MAAM;;;;;;kEAA+C,CAAC"}
@@ -1,5 +1,5 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="ccd03fae-35bf-58da-b672-e834ceba3cc9")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="fee0859e-cfe1-5496-aa37-3bbf9aa0f3bb")}catch(e){}}();
3
3
  import { PrismaClient } from '@prisma/client';
4
4
  import { env } from './config/env.js';
5
5
  const getLogLevel = () => {
@@ -12,13 +12,32 @@ const getLogLevel = () => {
12
12
  return ['error'];
13
13
  }
14
14
  };
15
+ const getDatabaseUrl = () => {
16
+ try {
17
+ const url = new URL(env.DATABASE_URL);
18
+ // Reduce per-instance DB pressure in hosted/serverless environments.
19
+ if (env.NODE_ENV === 'production') {
20
+ if (!url.searchParams.has('connection_limit')) {
21
+ url.searchParams.set('connection_limit', '1');
22
+ }
23
+ if (!url.searchParams.has('pool_timeout')) {
24
+ url.searchParams.set('pool_timeout', '20');
25
+ }
26
+ }
27
+ return url.toString();
28
+ }
29
+ catch {
30
+ return env.DATABASE_URL;
31
+ }
32
+ };
15
33
  const prismaClientSingleton = () => {
16
- // return new PrismaClient({
17
- // log: env.NODE_ENV === 'development'
18
- // ? ['query', 'error', 'warn']
19
- // : ['error'],
20
- // });
21
- return new PrismaClient();
34
+ return new PrismaClient({
35
+ datasources: {
36
+ db: {
37
+ url: getDatabaseUrl(),
38
+ },
39
+ },
40
+ });
22
41
  };
23
42
  export const prisma = globalThis.prisma ?? prismaClientSingleton();
24
43
  if (env.NODE_ENV !== 'production') {
@@ -28,4 +47,4 @@ process.on('beforeExit', async () => {
28
47
  await prisma.$disconnect();
29
48
  });
30
49
  //# sourceMappingURL=prisma.js.map
31
- //# debugId=ccd03fae-35bf-58da-b672-e834ceba3cc9
50
+ //# debugId=fee0859e-cfe1-5496-aa37-3bbf9aa0f3bb
@@ -1 +1 @@
1
- {"version":3,"file":"prisma.js","sources":["lib/prisma.ts"],"sourceRoot":"/","sourcesContent":["import { PrismaClient } from '@prisma/client';\nimport { env } from './config/env.js';\n\nconst getLogLevel = () => {\n switch (env.NODE_ENV) {\n case 'development':\n return ['query', 'error', 'warn'];\n case 'production':\n return ['error'];\n default:\n return ['error'];\n }\n}\n\nconst prismaClientSingleton = () => {\n // return new PrismaClient({\n // log: env.NODE_ENV === 'development' \n // ? ['query', 'error', 'warn'] \n // : ['error'],\n // });\n return new PrismaClient();\n};\n\n// Prevent multiple instances of Prisma Client in development\ndeclare global {\n var prisma: undefined | ReturnType<typeof prismaClientSingleton>;\n}\n\nexport const prisma = globalThis.prisma ?? prismaClientSingleton();\n\nif (env.NODE_ENV !== 'production') {\n globalThis.prisma = prisma;\n}\n\nprocess.on('beforeExit', async () => {\n await prisma.$disconnect();\n});"],"names":[],"mappings":";;AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAEtC,MAAM,WAAW,GAAG,GAAG,EAAE;IACvB,QAAQ,GAAG,CAAC,QAAQ,EAAE,CAAC;QACrB,KAAK,aAAa;YAChB,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QACpC,KAAK,YAAY;YACf,OAAO,CAAC,OAAO,CAAC,CAAC;QACnB;YACE,OAAO,CAAC,OAAO,CAAC,CAAC;IACrB,CAAC;AACH,CAAC,CAAA;AAED,MAAM,qBAAqB,GAAG,GAAG,EAAE;IACjC,4BAA4B;IAC5B,yCAAyC;IACzC,oCAAoC;IACpC,mBAAmB;IACnB,MAAM;IACN,OAAO,IAAI,YAAY,EAAE,CAAC;AAC5B,CAAC,CAAC;AAOF,MAAM,CAAC,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,IAAI,qBAAqB,EAAE,CAAC;AAEnE,IAAI,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;IAClC,UAAU,CAAC,MAAM,GAAG,MAAM,CAAC;AAC7B,CAAC;AAED,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE;IAClC,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;AAC7B,CAAC,CAAC,CAAC","debug_id":"ccd03fae-35bf-58da-b672-e834ceba3cc9"}
1
+ {"version":3,"file":"prisma.js","sources":["lib/prisma.ts"],"sourceRoot":"/","sourcesContent":["import { PrismaClient } from '@prisma/client';\nimport { env } from './config/env.js';\n\nconst getLogLevel = () => {\n switch (env.NODE_ENV) {\n case 'development':\n return ['query', 'error', 'warn'];\n case 'production':\n return ['error'];\n default:\n return ['error'];\n }\n}\n\nconst getDatabaseUrl = () => {\n try {\n const url = new URL(env.DATABASE_URL);\n // Reduce per-instance DB pressure in hosted/serverless environments.\n if (env.NODE_ENV === 'production') {\n if (!url.searchParams.has('connection_limit')) {\n url.searchParams.set('connection_limit', '1');\n }\n if (!url.searchParams.has('pool_timeout')) {\n url.searchParams.set('pool_timeout', '20');\n }\n }\n return url.toString();\n } catch {\n return env.DATABASE_URL;\n }\n};\n\nconst prismaClientSingleton = () => {\n return new PrismaClient({\n datasources: {\n db: {\n url: getDatabaseUrl(),\n },\n },\n });\n};\n\n// Prevent multiple instances of Prisma Client in development\ndeclare global {\n var prisma: undefined | ReturnType<typeof prismaClientSingleton>;\n}\n\nexport const prisma = globalThis.prisma ?? prismaClientSingleton();\n\nif (env.NODE_ENV !== 'production') {\n globalThis.prisma = prisma;\n}\n\nprocess.on('beforeExit', async () => {\n await prisma.$disconnect();\n});"],"names":[],"mappings":";;AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAEtC,MAAM,WAAW,GAAG,GAAG,EAAE;IACvB,QAAQ,GAAG,CAAC,QAAQ,EAAE,CAAC;QACrB,KAAK,aAAa;YAChB,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QACpC,KAAK,YAAY;YACf,OAAO,CAAC,OAAO,CAAC,CAAC;QACnB;YACE,OAAO,CAAC,OAAO,CAAC,CAAC;IACrB,CAAC;AACH,CAAC,CAAA;AAED,MAAM,cAAc,GAAG,GAAG,EAAE;IAC1B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACtC,qEAAqE;QACrE,IAAI,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;YAClC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,CAAC;gBAC9C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;YAChD,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;gBAC1C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;QACD,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC,YAAY,CAAC;IAC1B,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,GAAG,EAAE;IACjC,OAAO,IAAI,YAAY,CAAC;QACtB,WAAW,EAAE;YACX,EAAE,EAAE;gBACF,GAAG,EAAE,cAAc,EAAE;aACtB;SACF;KACF,CAAC,CAAC;AACL,CAAC,CAAC;AAOF,MAAM,CAAC,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,IAAI,qBAAqB,EAAE,CAAC;AAEnE,IAAI,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;IAClC,UAAU,CAAC,MAAM,GAAG,MAAM,CAAC;AAC7B,CAAC;AAED,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE;IAClC,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;AAC7B,CAAC,CAAC,CAAC","debug_id":"fee0859e-cfe1-5496-aa37-3bbf9aa0f3bb"}
@@ -1 +1 @@
1
- {"version":3,"file":"security.d.ts","sourceRoot":"/","sources":["middleware/security.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,cAAc,sDAWzB,CAAC;AAGH,eAAO,MAAM,WAAW,sDAQtB,CAAC;AAGH,eAAO,MAAM,aAAa,sDAOxB,CAAC;AAGH,eAAO,MAAM,YAAY,sFAwB2mF,CAAC,2BAAnoF,CAAC"}
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"/","sources":["middleware/security.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,cAAc,sDAWzB,CAAC;AAGH,eAAO,MAAM,WAAW,sDAQtB,CAAC;AAGH,eAAO,MAAM,aAAa,sDAOxB,CAAC;AAGH,eAAO,MAAM,YAAY,sFAwBomF,CAAC,2BAA5nF,CAAC"}
@@ -1,5 +1,5 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="d9abebcd-0879-54b7-8f35-66b5ee7a0544")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="e27a3dc9-6e2a-5b94-b404-01bf23ea1d5f")}catch(e){}}();
3
3
  import helmet from 'helmet';
4
4
  import rateLimit from 'express-rate-limit';
5
5
  const isDevelopment = process.env.NODE_ENV === 'development';
@@ -17,7 +17,7 @@ const rateLimitHandler = (req, res) => {
17
17
  };
18
18
  // General API rate limiter - applies to all routes
19
19
  export const generalLimiter = rateLimit({
20
- windowMs: 10 * 60, // 10 minutes
20
+ windowMs: 10 * 60 * 1000, // 10 minutes
21
21
  max: 100, // Limit each IP to 100 requests per windowMs
22
22
  message: 'Too many requests from this IP, please try again later.',
23
23
  standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
@@ -74,4 +74,4 @@ export const helmetConfig = helmet({
74
74
  },
75
75
  });
76
76
  //# sourceMappingURL=security.js.map
77
- //# debugId=d9abebcd-0879-54b7-8f35-66b5ee7a0544
77
+ //# debugId=e27a3dc9-6e2a-5b94-b404-01bf23ea1d5f
@@ -1 +1 @@
1
- {"version":3,"file":"security.js","sources":["middleware/security.ts"],"sourceRoot":"/","sourcesContent":["import helmet from 'helmet';\nimport rateLimit from 'express-rate-limit';\nimport type { Request, Response } from 'express';\n\nconst isDevelopment = process.env.NODE_ENV === 'development';\n\n// Custom handler for rate limit errors that returns JSON\n// This format can be intercepted on the frontend with:\n// error.data?.code === 'TOO_MANY_REQUESTS' || error.data?.httpStatus === 429\nconst rateLimitHandler = (req: Request, res: Response) => {\n // Return JSON structure that can be intercepted on frontend with:\n // error.data?.code === 'TOO_MANY_REQUESTS' || error.data?.httpStatus === 429\n // When tRPC wraps this, the response body becomes error.data, so we put code/httpStatus at top level\n res.status(429).json({\n code: 'TOO_MANY_REQUESTS',\n message: 'Too many requests, please try again later.',\n });\n};\n\n// General API rate limiter - applies to all routes\nexport const generalLimiter = rateLimit({\n windowMs: 10 * 60, // 10 minutes\n max: 100, // Limit each IP to 100 requests per windowMs\n message: 'Too many requests from this IP, please try again later.',\n standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers\n legacyHeaders: false, // Disable the `X-RateLimit-*` headers\n handler: rateLimitHandler,\n skip: (req) => {\n // Skip rate limiting for health checks\n return req.path === '/health' || req.method === 'OPTIONS';\n },\n});\n\n// Stricter rate limiter for authentication endpoints\nexport const authLimiter = rateLimit({\n windowMs: 5 * 60 * 1000, // 5 minutes\n max: 5, // Limit each IP to 5 login attempts per windowMs\n message: 'Too many authentication attempts, please try again later.',\n standardHeaders: true,\n legacyHeaders: false,\n skipSuccessfulRequests: true, // Don't count successful requests\n handler: rateLimitHandler,\n});\n\n// File upload rate limiter\nexport const uploadLimiter = rateLimit({\n windowMs: 30 * 60 * 1000, // 30 minutes\n max: 50, // Limit each IP to 50 uploads per hour\n message: 'Too many file uploads, please try again later.',\n standardHeaders: true,\n legacyHeaders: false,\n handler: rateLimitHandler,\n});\n\n// Helmet configuration\nexport const helmetConfig = helmet({\n contentSecurityPolicy: {\n directives: {\n defaultSrc: [\"'self'\"],\n styleSrc: [\"'self'\", \"'unsafe-inline'\"], // Allow inline styles for tRPC panel\n // Allow inline scripts only in development (for tRPC panel)\n // In production, keep strict CSP without unsafe-inline\n scriptSrc: isDevelopment \n ? [\"'self'\", \"'unsafe-inline'\"] \n : [\"'self'\"],\n imgSrc: [\"'self'\", \"data:\", \"https:\"], // Allow images from any HTTPS source\n connectSrc: [\"'self'\", \"https://*.sentry.io\"], // Allow Sentry connections\n fontSrc: [\"'self'\", \"data:\"],\n objectSrc: [\"'none'\"],\n mediaSrc: [\"'self'\"],\n frameSrc: [\"'none'\"],\n },\n },\n crossOriginEmbedderPolicy: false, // Disable if you need to embed resources\n hsts: {\n maxAge: 31536000, // 1 year\n includeSubDomains: true,\n preload: true,\n },\n});"],"names":[],"mappings":";;AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,SAAS,MAAM,oBAAoB,CAAC;AAG3C,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,CAAC;AAE7D,yDAAyD;AACzD,uDAAuD;AACvD,6EAA6E;AAC7E,MAAM,gBAAgB,GAAG,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;IACvD,kEAAkE;IAClE,6EAA6E;IAC7E,qGAAqG;IACrG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;QACnB,IAAI,EAAE,mBAAmB;QACzB,OAAO,EAAE,4CAA4C;KACtD,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,mDAAmD;AACnD,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,CAAC;IACtC,QAAQ,EAAE,EAAE,GAAG,EAAE,EAAE,aAAa;IAChC,GAAG,EAAE,GAAG,EAAE,6CAA6C;IACvD,OAAO,EAAE,yDAAyD;IAClE,eAAe,EAAE,IAAI,EAAE,sDAAsD;IAC7E,aAAa,EAAE,KAAK,EAAE,sCAAsC;IAC5D,OAAO,EAAE,gBAAgB;IACzB,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE;QACZ,uCAAuC;QACvC,OAAO,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC;IAC5D,CAAC;CACF,CAAC,CAAC;AAEH,qDAAqD;AACrD,MAAM,CAAC,MAAM,WAAW,GAAG,SAAS,CAAC;IACnC,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,YAAY;IACrC,GAAG,EAAE,CAAC,EAAE,iDAAiD;IACzD,OAAO,EAAE,2DAA2D;IACpE,eAAe,EAAE,IAAI;IACrB,aAAa,EAAE,KAAK;IACpB,sBAAsB,EAAE,IAAI,EAAE,kCAAkC;IAChE,OAAO,EAAE,gBAAgB;CAC1B,CAAC,CAAC;AAEH,2BAA2B;AAC3B,MAAM,CAAC,MAAM,aAAa,GAAG,SAAS,CAAC;IACrC,QAAQ,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,aAAa;IACvC,GAAG,EAAE,EAAE,EAAE,uCAAuC;IAChD,OAAO,EAAE,gDAAgD;IACzD,eAAe,EAAE,IAAI;IACrB,aAAa,EAAE,KAAK;IACpB,OAAO,EAAE,gBAAgB;CAC1B,CAAC,CAAC;AAEH,uBAAuB;AACvB,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC;IACjC,qBAAqB,EAAE;QACrB,UAAU,EAAE;YACV,UAAU,EAAE,CAAC,QAAQ,CAAC;YACtB,QAAQ,EAAE,CAAC,QAAQ,EAAE,iBAAiB,CAAC,EAAE,qCAAqC;YAC9E,4DAA4D;YAC5D,uDAAuD;YACvD,SAAS,EAAE,aAAa;gBACtB,CAAC,CAAC,CAAC,QAAQ,EAAE,iBAAiB,CAAC;gBAC/B,CAAC,CAAC,CAAC,QAAQ,CAAC;YACd,MAAM,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,qCAAqC;YAC5E,UAAU,EAAE,CAAC,QAAQ,EAAE,qBAAqB,CAAC,EAAE,2BAA2B;YAC1E,OAAO,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;YAC5B,SAAS,EAAE,CAAC,QAAQ,CAAC;YACrB,QAAQ,EAAE,CAAC,QAAQ,CAAC;YACpB,QAAQ,EAAE,CAAC,QAAQ,CAAC;SACrB;KACF;IACD,yBAAyB,EAAE,KAAK,EAAE,yCAAyC;IAC3E,IAAI,EAAE;QACJ,MAAM,EAAE,QAAQ,EAAE,SAAS;QAC3B,iBAAiB,EAAE,IAAI;QACvB,OAAO,EAAE,IAAI;KACd;CACF,CAAC,CAAC","debug_id":"d9abebcd-0879-54b7-8f35-66b5ee7a0544"}
1
+ {"version":3,"file":"security.js","sources":["middleware/security.ts"],"sourceRoot":"/","sourcesContent":["import helmet from 'helmet';\nimport rateLimit from 'express-rate-limit';\nimport type { Request, Response } from 'express';\n\nconst isDevelopment = process.env.NODE_ENV === 'development';\n\n// Custom handler for rate limit errors that returns JSON\n// This format can be intercepted on the frontend with:\n// error.data?.code === 'TOO_MANY_REQUESTS' || error.data?.httpStatus === 429\nconst rateLimitHandler = (req: Request, res: Response) => {\n // Return JSON structure that can be intercepted on frontend with:\n // error.data?.code === 'TOO_MANY_REQUESTS' || error.data?.httpStatus === 429\n // When tRPC wraps this, the response body becomes error.data, so we put code/httpStatus at top level\n res.status(429).json({\n code: 'TOO_MANY_REQUESTS',\n message: 'Too many requests, please try again later.',\n });\n};\n\n// General API rate limiter - applies to all routes\nexport const generalLimiter = rateLimit({\n windowMs: 10 * 60 * 1000, // 10 minutes\n max: 100, // Limit each IP to 100 requests per windowMs\n message: 'Too many requests from this IP, please try again later.',\n standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers\n legacyHeaders: false, // Disable the `X-RateLimit-*` headers\n handler: rateLimitHandler,\n skip: (req) => {\n // Skip rate limiting for health checks\n return req.path === '/health' || req.method === 'OPTIONS';\n },\n});\n\n// Stricter rate limiter for authentication endpoints\nexport const authLimiter = rateLimit({\n windowMs: 5 * 60 * 1000, // 5 minutes\n max: 5, // Limit each IP to 5 login attempts per windowMs\n message: 'Too many authentication attempts, please try again later.',\n standardHeaders: true,\n legacyHeaders: false,\n skipSuccessfulRequests: true, // Don't count successful requests\n handler: rateLimitHandler,\n});\n\n// File upload rate limiter\nexport const uploadLimiter = rateLimit({\n windowMs: 30 * 60 * 1000, // 30 minutes\n max: 50, // Limit each IP to 50 uploads per hour\n message: 'Too many file uploads, please try again later.',\n standardHeaders: true,\n legacyHeaders: false,\n handler: rateLimitHandler,\n});\n\n// Helmet configuration\nexport const helmetConfig = helmet({\n contentSecurityPolicy: {\n directives: {\n defaultSrc: [\"'self'\"],\n styleSrc: [\"'self'\", \"'unsafe-inline'\"], // Allow inline styles for tRPC panel\n // Allow inline scripts only in development (for tRPC panel)\n // In production, keep strict CSP without unsafe-inline\n scriptSrc: isDevelopment \n ? [\"'self'\", \"'unsafe-inline'\"] \n : [\"'self'\"],\n imgSrc: [\"'self'\", \"data:\", \"https:\"], // Allow images from any HTTPS source\n connectSrc: [\"'self'\", \"https://*.sentry.io\"], // Allow Sentry connections\n fontSrc: [\"'self'\", \"data:\"],\n objectSrc: [\"'none'\"],\n mediaSrc: [\"'self'\"],\n frameSrc: [\"'none'\"],\n },\n },\n crossOriginEmbedderPolicy: false, // Disable if you need to embed resources\n hsts: {\n maxAge: 31536000, // 1 year\n includeSubDomains: true,\n preload: true,\n },\n});"],"names":[],"mappings":";;AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,SAAS,MAAM,oBAAoB,CAAC;AAG3C,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,CAAC;AAE7D,yDAAyD;AACzD,uDAAuD;AACvD,6EAA6E;AAC7E,MAAM,gBAAgB,GAAG,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;IACvD,kEAAkE;IAClE,6EAA6E;IAC7E,qGAAqG;IACrG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;QACnB,IAAI,EAAE,mBAAmB;QACzB,OAAO,EAAE,4CAA4C;KACtD,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,mDAAmD;AACnD,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,CAAC;IACtC,QAAQ,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,aAAa;IACvC,GAAG,EAAE,GAAG,EAAE,6CAA6C;IACvD,OAAO,EAAE,yDAAyD;IAClE,eAAe,EAAE,IAAI,EAAE,sDAAsD;IAC7E,aAAa,EAAE,KAAK,EAAE,sCAAsC;IAC5D,OAAO,EAAE,gBAAgB;IACzB,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE;QACZ,uCAAuC;QACvC,OAAO,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC;IAC5D,CAAC;CACF,CAAC,CAAC;AAEH,qDAAqD;AACrD,MAAM,CAAC,MAAM,WAAW,GAAG,SAAS,CAAC;IACnC,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,YAAY;IACrC,GAAG,EAAE,CAAC,EAAE,iDAAiD;IACzD,OAAO,EAAE,2DAA2D;IACpE,eAAe,EAAE,IAAI;IACrB,aAAa,EAAE,KAAK;IACpB,sBAAsB,EAAE,IAAI,EAAE,kCAAkC;IAChE,OAAO,EAAE,gBAAgB;CAC1B,CAAC,CAAC;AAEH,2BAA2B;AAC3B,MAAM,CAAC,MAAM,aAAa,GAAG,SAAS,CAAC;IACrC,QAAQ,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,aAAa;IACvC,GAAG,EAAE,EAAE,EAAE,uCAAuC;IAChD,OAAO,EAAE,gDAAgD;IACzD,eAAe,EAAE,IAAI;IACrB,aAAa,EAAE,KAAK;IACpB,OAAO,EAAE,gBAAgB;CAC1B,CAAC,CAAC;AAEH,uBAAuB;AACvB,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC;IACjC,qBAAqB,EAAE;QACrB,UAAU,EAAE;YACV,UAAU,EAAE,CAAC,QAAQ,CAAC;YACtB,QAAQ,EAAE,CAAC,QAAQ,EAAE,iBAAiB,CAAC,EAAE,qCAAqC;YAC9E,4DAA4D;YAC5D,uDAAuD;YACvD,SAAS,EAAE,aAAa;gBACtB,CAAC,CAAC,CAAC,QAAQ,EAAE,iBAAiB,CAAC;gBAC/B,CAAC,CAAC,CAAC,QAAQ,CAAC;YACd,MAAM,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,qCAAqC;YAC5E,UAAU,EAAE,CAAC,QAAQ,EAAE,qBAAqB,CAAC,EAAE,2BAA2B;YAC1E,OAAO,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;YAC5B,SAAS,EAAE,CAAC,QAAQ,CAAC;YACrB,QAAQ,EAAE,CAAC,QAAQ,CAAC;YACpB,QAAQ,EAAE,CAAC,QAAQ,CAAC;SACrB;KACF;IACD,yBAAyB,EAAE,KAAK,EAAE,yCAAyC;IAC3E,IAAI,EAAE;QACJ,MAAM,EAAE,QAAQ,EAAE,SAAS;QAC3B,iBAAiB,EAAE,IAAI;QACvB,OAAO,EAAE,IAAI;KACd;CACF,CAAC,CAAC","debug_id":"e27a3dc9-6e2a-5b94-b404-01bf23ea1d5f"}
@@ -1,9 +1,9 @@
1
1
  /** @returns Personal events (no class) for user in date range. */
2
2
  export declare function findPersonalEvents(userId: string, rangeStart: Date, rangeEnd: Date): import(".prisma/client").Prisma.PrismaPromise<({
3
3
  class: {
4
+ name: string;
4
5
  id: string;
5
6
  schoolId: string | null;
6
- name: string;
7
7
  subject: string;
8
8
  color: string | null;
9
9
  section: string;
@@ -13,13 +13,11 @@ export declare function findPersonalEvents(userId: string, rangeStart: Date, ran
13
13
  type: import(".prisma/client").$Enums.AssignmentType;
14
14
  id: string;
15
15
  createdAt: Date | null;
16
+ modifiedAt: Date | null;
16
17
  classId: string;
17
18
  title: string;
18
- dueDate: Date;
19
- maxGrade: number | null;
20
- eventId: string | null;
21
19
  instructions: string;
22
- modifiedAt: Date | null;
20
+ dueDate: Date;
23
21
  teacherId: string;
24
22
  acceptFiles: boolean;
25
23
  acceptExtendedResponse: boolean;
@@ -28,30 +26,32 @@ export declare function findPersonalEvents(userId: string, rangeStart: Date, ran
28
26
  aiPolicyLevel: number;
29
27
  sectionId: string | null;
30
28
  graded: boolean;
29
+ maxGrade: number | null;
31
30
  weight: number;
32
31
  inProgress: boolean;
33
32
  template: boolean;
33
+ eventId: string | null;
34
34
  markSchemeId: string | null;
35
35
  order: number | null;
36
36
  gradingBoundaryId: string | null;
37
37
  }[];
38
38
  } & {
39
+ name: string | null;
39
40
  id: string;
40
41
  userId: string | null;
41
- location: string | null;
42
- classId: string | null;
43
- name: string | null;
44
42
  color: string | null;
43
+ classId: string | null;
45
44
  startTime: Date;
46
45
  endTime: Date;
46
+ location: string | null;
47
47
  remarks: string | null;
48
48
  })[]>;
49
49
  /** @returns Class events for user's classes in date range. */
50
50
  export declare function findClassEvents(userId: string, rangeStart: Date, rangeEnd: Date): import(".prisma/client").Prisma.PrismaPromise<({
51
51
  class: {
52
+ name: string;
52
53
  id: string;
53
54
  schoolId: string | null;
54
- name: string;
55
55
  subject: string;
56
56
  color: string | null;
57
57
  section: string;
@@ -61,13 +61,11 @@ export declare function findClassEvents(userId: string, rangeStart: Date, rangeE
61
61
  type: import(".prisma/client").$Enums.AssignmentType;
62
62
  id: string;
63
63
  createdAt: Date | null;
64
+ modifiedAt: Date | null;
64
65
  classId: string;
65
66
  title: string;
66
- dueDate: Date;
67
- maxGrade: number | null;
68
- eventId: string | null;
69
67
  instructions: string;
70
- modifiedAt: Date | null;
68
+ dueDate: Date;
71
69
  teacherId: string;
72
70
  acceptFiles: boolean;
73
71
  acceptExtendedResponse: boolean;
@@ -76,22 +74,24 @@ export declare function findClassEvents(userId: string, rangeStart: Date, rangeE
76
74
  aiPolicyLevel: number;
77
75
  sectionId: string | null;
78
76
  graded: boolean;
77
+ maxGrade: number | null;
79
78
  weight: number;
80
79
  inProgress: boolean;
81
80
  template: boolean;
81
+ eventId: string | null;
82
82
  markSchemeId: string | null;
83
83
  order: number | null;
84
84
  gradingBoundaryId: string | null;
85
85
  }[];
86
86
  } & {
87
+ name: string | null;
87
88
  id: string;
88
89
  userId: string | null;
89
- location: string | null;
90
- classId: string | null;
91
- name: string | null;
92
90
  color: string | null;
91
+ classId: string | null;
93
92
  startTime: Date;
94
93
  endTime: Date;
94
+ location: string | null;
95
95
  remarks: string | null;
96
96
  })[]>;
97
97
  //# sourceMappingURL=agenda.d.ts.map
@@ -35,8 +35,8 @@ export declare function findAnnouncementsByClassId(classId: string): import(".pr
35
35
  comments: number;
36
36
  };
37
37
  createdAt: Date;
38
- remarks: string;
39
38
  modifiedAt: Date | null;
39
+ remarks: string;
40
40
  teacher: {
41
41
  id: string;
42
42
  username: string;
@@ -49,8 +49,8 @@ export declare function findAnnouncementsByClassId(classId: string): import(".pr
49
49
  attachments: {
50
50
  path: string;
51
51
  type: string;
52
- id: string;
53
52
  name: string;
53
+ id: string;
54
54
  size: number | null;
55
55
  uploadedAt: Date | null;
56
56
  thumbnailId: string | null;
@@ -60,8 +60,8 @@ export declare function findAnnouncementsByClassId(classId: string): import(".pr
60
60
  export declare function findAnnouncementByIdAndClass(id: string, classId: string): import(".prisma/client").Prisma.Prisma__AnnouncementClient<{
61
61
  id: string;
62
62
  createdAt: Date;
63
- remarks: string;
64
63
  modifiedAt: Date | null;
64
+ remarks: string;
65
65
  teacher: {
66
66
  id: string;
67
67
  username: string;
@@ -74,13 +74,19 @@ export declare function findAnnouncementByIdAndClass(id: string, classId: string
74
74
  attachments: {
75
75
  path: string;
76
76
  type: string;
77
- id: string;
78
77
  name: string;
78
+ id: string;
79
79
  size: number | null;
80
80
  uploadedAt: Date | null;
81
81
  thumbnailId: string | null;
82
82
  }[];
83
- } | null, null, import("@prisma/client/runtime/library.js").DefaultArgs, import(".prisma/client").Prisma.PrismaClientOptions>;
83
+ } | null, null, import("@prisma/client/runtime/library.js").DefaultArgs, {
84
+ datasources: {
85
+ db: {
86
+ url: string;
87
+ };
88
+ };
89
+ }>;
84
90
  /** @returns Announcement by ID with class and teachers. */
85
91
  export declare function findAnnouncementWithClass(id: string): import(".prisma/client").Prisma.Prisma__AnnouncementClient<({
86
92
  class: {
@@ -94,9 +100,9 @@ export declare function findAnnouncementWithClass(id: string): import(".prisma/c
94
100
  schoolId: string | null;
95
101
  }[];
96
102
  } & {
103
+ name: string;
97
104
  id: string;
98
105
  schoolId: string | null;
99
- name: string;
100
106
  subject: string;
101
107
  color: string | null;
102
108
  section: string;
@@ -105,22 +111,28 @@ export declare function findAnnouncementWithClass(id: string): import(".prisma/c
105
111
  attachments: {
106
112
  path: string;
107
113
  type: string;
108
- id: string;
109
114
  name: string;
115
+ id: string;
110
116
  size: number | null;
117
+ uploadStatus: import(".prisma/client").$Enums.UploadStatus;
111
118
  thumbnail: {
112
119
  path: string;
113
120
  } | null;
114
- uploadStatus: import(".prisma/client").$Enums.UploadStatus;
115
121
  }[];
116
122
  } & {
117
123
  id: string;
118
124
  createdAt: Date;
119
- classId: string;
120
- remarks: string;
121
125
  modifiedAt: Date | null;
126
+ classId: string;
122
127
  teacherId: string;
123
- }) | null, null, import("@prisma/client/runtime/library.js").DefaultArgs, import(".prisma/client").Prisma.PrismaClientOptions>;
128
+ remarks: string;
129
+ }) | null, null, import("@prisma/client/runtime/library.js").DefaultArgs, {
130
+ datasources: {
131
+ db: {
132
+ url: string;
133
+ };
134
+ };
135
+ }>;
124
136
  /** Create an announcement. */
125
137
  export declare function createAnnouncement(data: {
126
138
  remarks: string;
@@ -129,8 +141,8 @@ export declare function createAnnouncement(data: {
129
141
  }): import(".prisma/client").Prisma.Prisma__AnnouncementClient<{
130
142
  id: string;
131
143
  createdAt: Date;
132
- remarks: string;
133
144
  modifiedAt: Date | null;
145
+ remarks: string;
134
146
  teacher: {
135
147
  id: string;
136
148
  username: string;
@@ -143,13 +155,19 @@ export declare function createAnnouncement(data: {
143
155
  attachments: {
144
156
  path: string;
145
157
  type: string;
146
- id: string;
147
158
  name: string;
159
+ id: string;
148
160
  size: number | null;
149
161
  uploadedAt: Date | null;
150
162
  thumbnailId: string | null;
151
163
  }[];
152
- }, never, import("@prisma/client/runtime/library.js").DefaultArgs, import(".prisma/client").Prisma.PrismaClientOptions>;
164
+ }, never, import("@prisma/client/runtime/library.js").DefaultArgs, {
165
+ datasources: {
166
+ db: {
167
+ url: string;
168
+ };
169
+ };
170
+ }>;
153
171
  /** Update announcement attachments. */
154
172
  export declare function updateAnnouncementAttachments(id: string, data: {
155
173
  connect?: {
@@ -163,8 +181,8 @@ export declare function updateAnnouncementAttachments(id: string, data: {
163
181
  }): import(".prisma/client").Prisma.Prisma__AnnouncementClient<{
164
182
  id: string;
165
183
  createdAt: Date;
166
- remarks: string;
167
184
  modifiedAt: Date | null;
185
+ remarks: string;
168
186
  teacher: {
169
187
  id: string;
170
188
  username: string;
@@ -177,21 +195,27 @@ export declare function updateAnnouncementAttachments(id: string, data: {
177
195
  attachments: {
178
196
  path: string;
179
197
  type: string;
180
- id: string;
181
198
  name: string;
199
+ id: string;
182
200
  size: number | null;
183
201
  uploadedAt: Date | null;
184
202
  thumbnailId: string | null;
185
203
  }[];
186
- }, never, import("@prisma/client/runtime/library.js").DefaultArgs, import(".prisma/client").Prisma.PrismaClientOptions>;
204
+ }, never, import("@prisma/client/runtime/library.js").DefaultArgs, {
205
+ datasources: {
206
+ db: {
207
+ url: string;
208
+ };
209
+ };
210
+ }>;
187
211
  /** Update announcement remarks. */
188
212
  export declare function updateAnnouncement(id: string, data: {
189
213
  remarks?: string;
190
214
  }): import(".prisma/client").Prisma.Prisma__AnnouncementClient<{
191
215
  id: string;
192
216
  createdAt: Date;
193
- remarks: string;
194
217
  modifiedAt: Date | null;
218
+ remarks: string;
195
219
  teacher: {
196
220
  id: string;
197
221
  username: string;
@@ -204,20 +228,32 @@ export declare function updateAnnouncement(id: string, data: {
204
228
  attachments: {
205
229
  path: string;
206
230
  type: string;
207
- id: string;
208
231
  name: string;
232
+ id: string;
209
233
  size: number | null;
210
234
  uploadedAt: Date | null;
211
235
  thumbnailId: string | null;
212
236
  }[];
213
- }, never, import("@prisma/client/runtime/library.js").DefaultArgs, import(".prisma/client").Prisma.PrismaClientOptions>;
237
+ }, never, import("@prisma/client/runtime/library.js").DefaultArgs, {
238
+ datasources: {
239
+ db: {
240
+ url: string;
241
+ };
242
+ };
243
+ }>;
214
244
  /** Delete an announcement. */
215
245
  export declare function deleteAnnouncement(id: string): import(".prisma/client").Prisma.Prisma__AnnouncementClient<{
216
246
  id: string;
217
247
  createdAt: Date;
218
- classId: string;
219
- remarks: string;
220
248
  modifiedAt: Date | null;
249
+ classId: string;
221
250
  teacherId: string;
222
- }, never, import("@prisma/client/runtime/library.js").DefaultArgs, import(".prisma/client").Prisma.PrismaClientOptions>;
251
+ remarks: string;
252
+ }, never, import("@prisma/client/runtime/library.js").DefaultArgs, {
253
+ datasources: {
254
+ db: {
255
+ url: string;
256
+ };
257
+ };
258
+ }>;
223
259
  //# sourceMappingURL=announcement.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"announcement.d.ts","sourceRoot":"/","sources":["models/announcement.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6B9B,CAAC;AAEF,0CAA0C;AAC1C,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;KAWzD;AAED,6CAA6C;AAC7C,wBAAgB,4BAA4B,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;8HAKvE;AAED,2DAA2D;AAC3D,wBAAgB,yBAAyB,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+HAoBnD;AAED,8BAA8B;AAC9B,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;;;;;;;;;;;;;;;;;;;;;;;wHASA;AAED,uCAAuC;AACvC,wBAAgB,6BAA6B,CAC3C,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IACJ,OAAO,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE;QAAE,EAAE,EAAE;YAAE,EAAE,EAAE,MAAM,EAAE,CAAA;SAAE,CAAA;KAAE,CAAC;CACvC;;;;;;;;;;;;;;;;;;;;;;;wHAcF;AAED,mCAAmC;AACnC,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;;wHAMxE;AAED,8BAA8B;AAC9B,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM;;;;;;;wHAI5C"}
1
+ {"version":3,"file":"announcement.d.ts","sourceRoot":"/","sources":["models/announcement.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6B9B,CAAC;AAEF,0CAA0C;AAC1C,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;KAWzD;AAED,6CAA6C;AAC7C,wBAAgB,4BAA4B,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAKvE;AAED,2DAA2D;AAC3D,wBAAgB,yBAAyB,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoBnD;AAED,8BAA8B;AAC9B,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GASA;AAED,uCAAuC;AACvC,wBAAgB,6BAA6B,CAC3C,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IACJ,OAAO,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE;QAAE,EAAE,EAAE;YAAE,EAAE,EAAE,MAAM,EAAE,CAAA;SAAE,CAAA;KAAE,CAAC;CACvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAcF;AAED,mCAAmC;AACnC,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAMxE;AAED,8BAA8B;AAC9B,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;;GAI5C"}