@studious-lms/server 1.23.0 → 1.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +0 -1
- package/data/curriculum/nepal-cdc-g4-g5/README.md +90 -0
- package/data/curriculum/nepal-cdc-g4-g5/manifest.json +97 -0
- package/data/curriculum/nepal-cdc-g4-g5/proficiency-scale.json +76 -0
- package/data/curriculum/nepal-cdc-g4-g5/subjects/english.json +6936 -0
- package/data/curriculum/nepal-cdc-g4-g5/subjects/health-physical-creative-arts.json +3401 -0
- package/data/curriculum/nepal-cdc-g4-g5/subjects/mathematics.json +1511 -0
- package/data/curriculum/nepal-cdc-g4-g5/subjects/nepali.json +7928 -0
- package/data/curriculum/nepal-cdc-g4-g5/subjects/science-technology.json +2420 -0
- package/data/curriculum/nepal-cdc-g4-g5/subjects/social-studies.json +2177 -0
- package/dist/lib/assignmentTypeDefaults.d.ts +41 -0
- package/dist/lib/assignmentTypeDefaults.d.ts.map +1 -0
- package/dist/lib/assignmentTypeDefaults.js +167 -0
- package/dist/lib/assignmentTypeDefaults.js.map +1 -0
- package/dist/lib/config/env.d.ts +0 -8
- package/dist/lib/config/env.d.ts.map +1 -1
- package/dist/lib/config/env.js +2 -5
- package/dist/lib/config/env.js.map +1 -1
- package/dist/lib/feePdf.d.ts +19 -0
- package/dist/lib/feePdf.d.ts.map +1 -0
- package/dist/lib/feePdf.js +167 -0
- package/dist/lib/feePdf.js.map +1 -0
- package/dist/lib/feePdfFormat.d.ts +4 -0
- package/dist/lib/feePdfFormat.d.ts.map +1 -0
- package/dist/lib/feePdfFormat.js +16 -0
- package/dist/lib/feePdfFormat.js.map +1 -0
- package/dist/lib/idCardPdf.d.ts +26 -0
- package/dist/lib/idCardPdf.d.ts.map +1 -0
- package/dist/lib/idCardPdf.js +272 -0
- package/dist/lib/idCardPdf.js.map +1 -0
- package/dist/lib/pdfLetterhead.d.ts +41 -0
- package/dist/lib/pdfLetterhead.d.ts.map +1 -0
- package/dist/lib/pdfLetterhead.js +86 -0
- package/dist/lib/pdfLetterhead.js.map +1 -0
- package/dist/lib/transcriptPdf.d.ts +55 -0
- package/dist/lib/transcriptPdf.d.ts.map +1 -0
- package/dist/lib/transcriptPdf.js +303 -0
- package/dist/lib/transcriptPdf.js.map +1 -0
- package/dist/models/academicCalendar.d.ts +198 -0
- package/dist/models/academicCalendar.d.ts.map +1 -0
- package/dist/models/academicCalendar.js +106 -0
- package/dist/models/academicCalendar.js.map +1 -0
- package/dist/models/agenda.d.ts +8 -0
- package/dist/models/agenda.d.ts.map +1 -1
- package/dist/models/announcement.d.ts +2 -0
- package/dist/models/announcement.d.ts.map +1 -1
- package/dist/models/assignment.d.ts +66 -0
- package/dist/models/assignment.d.ts.map +1 -1
- package/dist/models/attendance.d.ts +659 -21
- package/dist/models/attendance.d.ts.map +1 -1
- package/dist/models/attendance.js +547 -75
- package/dist/models/attendance.js.map +1 -1
- package/dist/models/auth.d.ts +2 -0
- package/dist/models/auth.d.ts.map +1 -1
- package/dist/models/class.d.ts +12 -0
- package/dist/models/class.d.ts.map +1 -1
- package/dist/models/class.js +3 -2
- package/dist/models/class.js.map +1 -1
- package/dist/models/event.d.ts +16 -0
- package/dist/models/event.d.ts.map +1 -1
- package/dist/models/fees.d.ts +554 -0
- package/dist/models/fees.d.ts.map +1 -0
- package/dist/models/fees.js +278 -0
- package/dist/models/fees.js.map +1 -0
- package/dist/models/file.d.ts +29 -0
- package/dist/models/file.d.ts.map +1 -1
- package/dist/models/folder.d.ts +2 -0
- package/dist/models/folder.d.ts.map +1 -1
- package/dist/models/labChat.d.ts +2 -0
- package/dist/models/labChat.d.ts.map +1 -1
- package/dist/models/marketplace.d.ts +180 -0
- package/dist/models/marketplace.d.ts.map +1 -0
- package/dist/models/marketplace.js +116 -0
- package/dist/models/marketplace.js.map +1 -0
- package/dist/models/moduleItem.d.ts +308 -0
- package/dist/models/moduleItem.d.ts.map +1 -0
- package/dist/models/moduleItem.js +93 -0
- package/dist/models/moduleItem.js.map +1 -0
- package/dist/models/newtonChat.d.ts +1 -0
- package/dist/models/newtonChat.d.ts.map +1 -1
- package/dist/models/school.d.ts +18 -0
- package/dist/models/school.d.ts.map +1 -1
- package/dist/models/school.js +7 -2
- package/dist/models/school.js.map +1 -1
- package/dist/models/section.d.ts +4 -0
- package/dist/models/section.d.ts.map +1 -1
- package/dist/models/worksheet.d.ts +19 -0
- package/dist/models/worksheet.d.ts.map +1 -1
- package/dist/models/worksheet.js +2 -2
- package/dist/models/worksheet.js.map +1 -1
- package/dist/routers/_app.d.ts +12024 -7778
- package/dist/routers/_app.d.ts.map +1 -1
- package/dist/routers/_app.js +12 -2
- package/dist/routers/_app.js.map +1 -1
- package/dist/routers/academicCalendar.d.ts +229 -0
- package/dist/routers/academicCalendar.d.ts.map +1 -0
- package/dist/routers/academicCalendar.js +75 -0
- package/dist/routers/academicCalendar.js.map +1 -0
- package/dist/routers/admin.d.ts +2 -0
- package/dist/routers/admin.d.ts.map +1 -1
- package/dist/routers/agenda.d.ts +8 -0
- package/dist/routers/agenda.d.ts.map +1 -1
- package/dist/routers/assignment.d.ts +75 -0
- package/dist/routers/assignment.d.ts.map +1 -1
- package/dist/routers/assignment.js +10 -2
- package/dist/routers/assignment.js.map +1 -1
- package/dist/routers/attendance.d.ts +103 -0
- package/dist/routers/attendance.d.ts.map +1 -1
- package/dist/routers/attendance.js +8 -5
- package/dist/routers/attendance.js.map +1 -1
- package/dist/routers/class.d.ts +27 -0
- package/dist/routers/class.d.ts.map +1 -1
- package/dist/routers/class.js +6 -2
- package/dist/routers/class.js.map +1 -1
- package/dist/routers/event.d.ts +8 -0
- package/dist/routers/event.d.ts.map +1 -1
- package/dist/routers/fees.d.ts +513 -0
- package/dist/routers/fees.d.ts.map +1 -0
- package/dist/routers/fees.js +88 -0
- package/dist/routers/fees.js.map +1 -0
- package/dist/routers/file.d.ts +2 -0
- package/dist/routers/file.d.ts.map +1 -1
- package/dist/routers/gradebook.d.ts +4 -1
- package/dist/routers/gradebook.d.ts.map +1 -1
- package/dist/routers/marketplace.d.ts +371 -0
- package/dist/routers/marketplace.d.ts.map +1 -0
- package/dist/routers/marketplace.js +87 -0
- package/dist/routers/marketplace.js.map +1 -0
- package/dist/routers/moduleItem.d.ts +263 -0
- package/dist/routers/moduleItem.d.ts.map +1 -0
- package/dist/routers/moduleItem.js +61 -0
- package/dist/routers/moduleItem.js.map +1 -0
- package/dist/routers/parent.d.ts +170 -0
- package/dist/routers/parent.d.ts.map +1 -0
- package/dist/routers/parent.js +49 -0
- package/dist/routers/parent.js.map +1 -0
- package/dist/routers/school.d.ts +363 -7
- package/dist/routers/school.d.ts.map +1 -1
- package/dist/routers/school.js +110 -3
- package/dist/routers/school.js.map +1 -1
- package/dist/routers/worksheet.d.ts +27 -0
- package/dist/routers/worksheet.d.ts.map +1 -1
- package/dist/routers/worksheet.js +10 -3
- package/dist/routers/worksheet.js.map +1 -1
- package/dist/services/academicCalendar.d.ts +173 -0
- package/dist/services/academicCalendar.d.ts.map +1 -0
- package/dist/services/academicCalendar.js +242 -0
- package/dist/services/academicCalendar.js.map +1 -0
- package/dist/services/adminInstitution.d.ts +2 -0
- package/dist/services/adminInstitution.d.ts.map +1 -1
- package/dist/services/agenda.d.ts +8 -0
- package/dist/services/agenda.d.ts.map +1 -1
- package/dist/services/assignment.d.ts +75 -0
- package/dist/services/assignment.d.ts.map +1 -1
- package/dist/services/assignment.js +91 -12
- package/dist/services/assignment.js.map +1 -1
- package/dist/services/attendance.d.ts +327 -10
- package/dist/services/attendance.d.ts.map +1 -1
- package/dist/services/attendance.js +389 -25
- package/dist/services/attendance.js.map +1 -1
- package/dist/services/attendanceMerge.d.ts +53 -0
- package/dist/services/attendanceMerge.d.ts.map +1 -0
- package/dist/services/attendanceMerge.js +87 -0
- package/dist/services/attendanceMerge.js.map +1 -0
- package/dist/services/attendanceRate.d.ts +24 -0
- package/dist/services/attendanceRate.d.ts.map +1 -0
- package/dist/services/attendanceRate.js +31 -0
- package/dist/services/attendanceRate.js.map +1 -0
- package/dist/services/attendanceStats.d.ts +22 -0
- package/dist/services/attendanceStats.d.ts.map +1 -0
- package/dist/services/attendanceStats.js +45 -0
- package/dist/services/attendanceStats.js.map +1 -0
- package/dist/services/class.d.ts +34 -2
- package/dist/services/class.d.ts.map +1 -1
- package/dist/services/class.js +27 -4
- package/dist/services/class.js.map +1 -1
- package/dist/services/event.d.ts +8 -0
- package/dist/services/event.d.ts.map +1 -1
- package/dist/services/fees.d.ts +422 -0
- package/dist/services/fees.d.ts.map +1 -0
- package/dist/services/fees.js +330 -0
- package/dist/services/fees.js.map +1 -0
- package/dist/services/feesAuthz.d.ts +46 -0
- package/dist/services/feesAuthz.d.ts.map +1 -0
- package/dist/services/feesAuthz.js +49 -0
- package/dist/services/feesAuthz.js.map +1 -0
- package/dist/services/file.d.ts +4 -0
- package/dist/services/file.d.ts.map +1 -1
- package/dist/services/gradebook.d.ts +18 -1
- package/dist/services/gradebook.d.ts.map +1 -1
- package/dist/services/gradebook.js +57 -2
- package/dist/services/gradebook.js.map +1 -1
- package/dist/services/idCard.d.ts +11 -0
- package/dist/services/idCard.d.ts.map +1 -0
- package/dist/services/idCard.js +122 -0
- package/dist/services/idCard.js.map +1 -0
- package/dist/services/marketplace.d.ts +301 -0
- package/dist/services/marketplace.d.ts.map +1 -0
- package/dist/services/marketplace.js +631 -0
- package/dist/services/marketplace.js.map +1 -0
- package/dist/services/moduleItem.d.ts +196 -0
- package/dist/services/moduleItem.d.ts.map +1 -0
- package/dist/services/moduleItem.js +204 -0
- package/dist/services/moduleItem.js.map +1 -0
- package/dist/services/notification.d.ts +58 -0
- package/dist/services/notification.d.ts.map +1 -1
- package/dist/services/notification.js +30 -2
- package/dist/services/notification.js.map +1 -1
- package/dist/services/parentPortal.d.ts +131 -0
- package/dist/services/parentPortal.d.ts.map +1 -0
- package/dist/services/parentPortal.js +314 -0
- package/dist/services/parentPortal.js.map +1 -0
- package/dist/services/school.d.ts +28 -3
- package/dist/services/school.d.ts.map +1 -1
- package/dist/services/school.js +98 -54
- package/dist/services/school.js.map +1 -1
- package/dist/services/studentImport.d.ts +34 -0
- package/dist/services/studentImport.d.ts.map +1 -0
- package/dist/services/studentImport.js +249 -0
- package/dist/services/studentImport.js.map +1 -0
- package/dist/services/transcript.d.ts +60 -0
- package/dist/services/transcript.d.ts.map +1 -0
- package/dist/services/transcript.js +231 -0
- package/dist/services/transcript.js.map +1 -0
- package/dist/services/worksheet.d.ts +22 -0
- package/dist/services/worksheet.d.ts.map +1 -1
- package/dist/services/worksheet.js +94 -2
- package/dist/services/worksheet.js.map +1 -1
- package/dist/trpc.d.ts +1 -1
- package/dist/trpc.d.ts.map +1 -1
- package/dist/trpc.js +5 -5
- package/dist/trpc.js.map +1 -1
- package/dist/utils/adminPanelAccess.d.ts +4 -5
- package/dist/utils/adminPanelAccess.d.ts.map +1 -1
- package/dist/utils/adminPanelAccess.js +12 -34
- package/dist/utils/adminPanelAccess.js.map +1 -1
- package/package.json +2 -1
- package/prisma/migrations/20260804120000_add_attendance_records_and_excusals/migration.sql +114 -0
- package/prisma/migrations/20260804120100_add_fee_plans_invoices_payments/migration.sql +101 -0
- package/prisma/migrations/20260804120200_add_marketplace_listings/migration.sql +54 -0
- package/prisma/migrations/20260804120300_content_platform_b3_b9/migration.sql +63 -0
- package/prisma/migrations/20260804120400_c_academic_ops/migration.sql +77 -0
- package/prisma/schema.prisma +371 -11
- package/scripts/import-nepal-cdc-curriculum.ts +402 -0
- package/src/lib/assignmentTypeDefaults.ts +222 -0
- package/src/lib/config/env.ts +0 -3
- package/src/lib/feePdf.ts +199 -0
- package/src/lib/feePdfFormat.ts +14 -0
- package/src/lib/idCardPdf.ts +336 -0
- package/src/lib/pdfLetterhead.ts +124 -0
- package/src/lib/transcriptPdf.ts +502 -0
- package/src/models/academicCalendar.ts +139 -0
- package/src/models/attendance.ts +702 -73
- package/src/models/class.ts +1 -0
- package/src/models/fees.ts +349 -0
- package/src/models/marketplace.ts +161 -0
- package/src/models/moduleItem.ts +125 -0
- package/src/models/school.ts +6 -0
- package/src/models/worksheet.ts +2 -0
- package/src/routers/_app.ts +10 -0
- package/src/routers/academicCalendar.ts +103 -0
- package/src/routers/assignment.ts +8 -0
- package/src/routers/attendance.ts +7 -3
- package/src/routers/class.ts +4 -0
- package/src/routers/fees.ts +126 -0
- package/src/routers/marketplace.ts +134 -0
- package/src/routers/moduleItem.ts +91 -0
- package/src/routers/parent.ts +68 -0
- package/src/routers/school.ts +149 -1
- package/src/routers/worksheet.ts +11 -0
- package/src/services/academicCalendar.ts +327 -0
- package/src/services/assignment.ts +122 -12
- package/src/services/attendance.ts +552 -26
- package/src/services/attendanceMerge.ts +139 -0
- package/src/services/attendanceRate.ts +41 -0
- package/src/services/attendanceStats.ts +63 -0
- package/src/services/class.ts +26 -2
- package/src/services/fees.ts +447 -0
- package/src/services/feesAuthz.ts +73 -0
- package/src/services/gradebook.ts +70 -0
- package/src/services/idCard.ts +147 -0
- package/src/services/marketplace.ts +790 -0
- package/src/services/moduleItem.ts +298 -0
- package/src/services/notification.ts +43 -0
- package/src/services/parentPortal.ts +367 -0
- package/src/services/school.ts +100 -54
- package/src/services/studentImport.ts +285 -0
- package/src/services/transcript.ts +301 -0
- package/src/services/worksheet.ts +111 -0
- package/src/trpc.ts +3 -3
- package/src/utils/adminPanelAccess.ts +12 -35
- package/tests/unit/assignmentTypeDefaults.test.ts +52 -0
- package/tests/unit/lib/feePdf.test.ts +15 -0
- package/tests/unit/lib/idCardPdf.test.ts +40 -0
- package/tests/unit/lib/transcriptPdf.test.ts +111 -0
- package/tests/unit/services/attendanceMerge.test.ts +90 -0
- package/tests/unit/services/attendanceRate.test.ts +38 -0
- package/tests/unit/services/attendanceStats.test.ts +54 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { AssignmentType } from "@prisma/client";
|
|
2
|
+
export type AssignmentTypeBehavior = {
|
|
3
|
+
acceptFiles: boolean;
|
|
4
|
+
acceptExtendedResponse: boolean;
|
|
5
|
+
acceptWorksheet: boolean;
|
|
6
|
+
singleAttempt: boolean;
|
|
7
|
+
allowLateSubmissions: boolean;
|
|
8
|
+
timeLimitMinutes: number | null;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Sensible defaults by assignment type. QUIZ/TEST tighten attempts and
|
|
12
|
+
* discourage late file spam; ESSAY/DISCUSSION prefer written response.
|
|
13
|
+
*/
|
|
14
|
+
export declare function getAssignmentTypeDefaults(type: AssignmentType | string | undefined | null): AssignmentTypeBehavior;
|
|
15
|
+
export type AssignmentBehaviorInput = {
|
|
16
|
+
type?: AssignmentType | string | null;
|
|
17
|
+
acceptFiles?: boolean;
|
|
18
|
+
acceptExtendedResponse?: boolean;
|
|
19
|
+
acceptWorksheet?: boolean;
|
|
20
|
+
singleAttempt?: boolean;
|
|
21
|
+
allowLateSubmissions?: boolean;
|
|
22
|
+
timeLimitMinutes?: number | null;
|
|
23
|
+
/** When true, fill unspecified deliverable/behavior flags from type defaults. */
|
|
24
|
+
applyTypeDefaults?: boolean;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Merge explicit fields with type defaults and validate incompatible combos.
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveAssignmentBehavior(input: AssignmentBehaviorInput): {
|
|
30
|
+
acceptFiles: boolean;
|
|
31
|
+
acceptExtendedResponse: boolean;
|
|
32
|
+
acceptWorksheet: boolean;
|
|
33
|
+
singleAttempt: boolean;
|
|
34
|
+
allowLateSubmissions: boolean;
|
|
35
|
+
timeLimitMinutes: number | null | undefined;
|
|
36
|
+
};
|
|
37
|
+
export declare const SIDEBAR_FEATURE_KEYS: readonly ["overview", "assignments", "quizzes", "worksheets", "grades", "files", "modules", "discussions", "attendance", "aiLabs", "members", "syllabus", "settings"];
|
|
38
|
+
export type SidebarFeatureKey = (typeof SIDEBAR_FEATURE_KEYS)[number];
|
|
39
|
+
export type SidebarFeatures = Partial<Record<SidebarFeatureKey, boolean>>;
|
|
40
|
+
export declare function normalizeSidebarFeatures(value: unknown): SidebarFeatures | null;
|
|
41
|
+
//# sourceMappingURL=assignmentTypeDefaults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assignmentTypeDefaults.d.ts","sourceRoot":"/","sources":["lib/assignmentTypeDefaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGrD,MAAM,MAAM,sBAAsB,GAAG;IACnC,WAAW,EAAE,OAAO,CAAC;IACrB,sBAAsB,EAAE,OAAO,CAAC;IAChC,eAAe,EAAE,OAAO,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;IACvB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,cAAc,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,GAC/C,sBAAsB,CA6DxB;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,CAAC,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI,CAAC;IACtC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,iFAAiF;IACjF,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,uBAAuB,GAAG;IACzE,WAAW,EAAE,OAAO,CAAC;IACrB,sBAAsB,EAAE,OAAO,CAAC;IAChC,eAAe,EAAE,OAAO,CAAC;IACzB,aAAa,EAAE,OAAO,CAAC;IACvB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CAC7C,CAmFA;AAED,eAAO,MAAM,oBAAoB,uKAcvB,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEtE,MAAM,MAAM,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC,CAAC;AAE1E,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,OAAO,GACb,eAAe,GAAG,IAAI,CAWxB"}
|
|
@@ -0,0 +1,167 @@
|
|
|
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]="f18d9467-4e3c-5922-8f66-5eb168354131")}catch(e){}}();
|
|
3
|
+
import { TRPCError } from "@trpc/server";
|
|
4
|
+
/**
|
|
5
|
+
* Sensible defaults by assignment type. QUIZ/TEST tighten attempts and
|
|
6
|
+
* discourage late file spam; ESSAY/DISCUSSION prefer written response.
|
|
7
|
+
*/
|
|
8
|
+
export function getAssignmentTypeDefaults(type) {
|
|
9
|
+
switch (type) {
|
|
10
|
+
case "QUIZ":
|
|
11
|
+
return {
|
|
12
|
+
acceptFiles: false,
|
|
13
|
+
acceptExtendedResponse: false,
|
|
14
|
+
acceptWorksheet: true,
|
|
15
|
+
singleAttempt: true,
|
|
16
|
+
allowLateSubmissions: false,
|
|
17
|
+
timeLimitMinutes: null,
|
|
18
|
+
};
|
|
19
|
+
case "TEST":
|
|
20
|
+
return {
|
|
21
|
+
acceptFiles: false,
|
|
22
|
+
acceptExtendedResponse: false,
|
|
23
|
+
acceptWorksheet: true,
|
|
24
|
+
singleAttempt: true,
|
|
25
|
+
allowLateSubmissions: false,
|
|
26
|
+
timeLimitMinutes: null,
|
|
27
|
+
};
|
|
28
|
+
case "ESSAY":
|
|
29
|
+
return {
|
|
30
|
+
acceptFiles: false,
|
|
31
|
+
acceptExtendedResponse: true,
|
|
32
|
+
acceptWorksheet: false,
|
|
33
|
+
singleAttempt: false,
|
|
34
|
+
allowLateSubmissions: true,
|
|
35
|
+
timeLimitMinutes: null,
|
|
36
|
+
};
|
|
37
|
+
case "DISCUSSION":
|
|
38
|
+
return {
|
|
39
|
+
acceptFiles: false,
|
|
40
|
+
acceptExtendedResponse: true,
|
|
41
|
+
acceptWorksheet: false,
|
|
42
|
+
singleAttempt: false,
|
|
43
|
+
allowLateSubmissions: true,
|
|
44
|
+
timeLimitMinutes: null,
|
|
45
|
+
};
|
|
46
|
+
case "PROJECT":
|
|
47
|
+
case "PRESENTATION":
|
|
48
|
+
case "LAB":
|
|
49
|
+
return {
|
|
50
|
+
acceptFiles: true,
|
|
51
|
+
acceptExtendedResponse: true,
|
|
52
|
+
acceptWorksheet: false,
|
|
53
|
+
singleAttempt: false,
|
|
54
|
+
allowLateSubmissions: true,
|
|
55
|
+
timeLimitMinutes: null,
|
|
56
|
+
};
|
|
57
|
+
case "HOMEWORK":
|
|
58
|
+
case "OTHER":
|
|
59
|
+
default:
|
|
60
|
+
return {
|
|
61
|
+
acceptFiles: true,
|
|
62
|
+
acceptExtendedResponse: false,
|
|
63
|
+
acceptWorksheet: false,
|
|
64
|
+
singleAttempt: false,
|
|
65
|
+
allowLateSubmissions: true,
|
|
66
|
+
timeLimitMinutes: null,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Merge explicit fields with type defaults and validate incompatible combos.
|
|
72
|
+
*/
|
|
73
|
+
export function resolveAssignmentBehavior(input) {
|
|
74
|
+
const defaults = getAssignmentTypeDefaults(input.type);
|
|
75
|
+
const apply = input.applyTypeDefaults !== false;
|
|
76
|
+
const acceptFiles = input.acceptFiles !== undefined
|
|
77
|
+
? input.acceptFiles
|
|
78
|
+
: apply
|
|
79
|
+
? defaults.acceptFiles
|
|
80
|
+
: false;
|
|
81
|
+
const acceptExtendedResponse = input.acceptExtendedResponse !== undefined
|
|
82
|
+
? input.acceptExtendedResponse
|
|
83
|
+
: apply
|
|
84
|
+
? defaults.acceptExtendedResponse
|
|
85
|
+
: false;
|
|
86
|
+
const acceptWorksheet = input.acceptWorksheet !== undefined
|
|
87
|
+
? input.acceptWorksheet
|
|
88
|
+
: apply
|
|
89
|
+
? defaults.acceptWorksheet
|
|
90
|
+
: false;
|
|
91
|
+
const singleAttempt = input.singleAttempt !== undefined
|
|
92
|
+
? input.singleAttempt
|
|
93
|
+
: apply
|
|
94
|
+
? defaults.singleAttempt
|
|
95
|
+
: false;
|
|
96
|
+
const allowLateSubmissions = input.allowLateSubmissions !== undefined
|
|
97
|
+
? input.allowLateSubmissions
|
|
98
|
+
: apply
|
|
99
|
+
? defaults.allowLateSubmissions
|
|
100
|
+
: true;
|
|
101
|
+
const timeLimitMinutes = input.timeLimitMinutes !== undefined
|
|
102
|
+
? input.timeLimitMinutes
|
|
103
|
+
: apply
|
|
104
|
+
? defaults.timeLimitMinutes
|
|
105
|
+
: undefined;
|
|
106
|
+
if (timeLimitMinutes !== undefined &&
|
|
107
|
+
timeLimitMinutes !== null &&
|
|
108
|
+
(timeLimitMinutes < 1 || timeLimitMinutes > 24 * 60)) {
|
|
109
|
+
throw new TRPCError({
|
|
110
|
+
code: "BAD_REQUEST",
|
|
111
|
+
message: "timeLimitMinutes must be between 1 and 1440",
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
// Quizzes/tests: disallow file deliverables when late submissions are off
|
|
115
|
+
// (prevents "late file spam" after the window closes).
|
|
116
|
+
if ((input.type === "QUIZ" || input.type === "TEST") &&
|
|
117
|
+
acceptFiles &&
|
|
118
|
+
!allowLateSubmissions &&
|
|
119
|
+
input.acceptFiles === true) {
|
|
120
|
+
// Allowed only when teacher explicitly opts into files; keep allowLate false.
|
|
121
|
+
}
|
|
122
|
+
if (!acceptFiles &&
|
|
123
|
+
!acceptExtendedResponse &&
|
|
124
|
+
!acceptWorksheet) {
|
|
125
|
+
throw new TRPCError({
|
|
126
|
+
code: "BAD_REQUEST",
|
|
127
|
+
message: "Assignment must accept at least one deliverable (files, extended response, or worksheet)",
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
acceptFiles,
|
|
132
|
+
acceptExtendedResponse,
|
|
133
|
+
acceptWorksheet,
|
|
134
|
+
singleAttempt,
|
|
135
|
+
allowLateSubmissions,
|
|
136
|
+
timeLimitMinutes,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
export const SIDEBAR_FEATURE_KEYS = [
|
|
140
|
+
"overview",
|
|
141
|
+
"assignments",
|
|
142
|
+
"quizzes",
|
|
143
|
+
"worksheets",
|
|
144
|
+
"grades",
|
|
145
|
+
"files",
|
|
146
|
+
"modules",
|
|
147
|
+
"discussions",
|
|
148
|
+
"attendance",
|
|
149
|
+
"aiLabs",
|
|
150
|
+
"members",
|
|
151
|
+
"syllabus",
|
|
152
|
+
"settings",
|
|
153
|
+
];
|
|
154
|
+
export function normalizeSidebarFeatures(value) {
|
|
155
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
const out = {};
|
|
159
|
+
for (const key of SIDEBAR_FEATURE_KEYS) {
|
|
160
|
+
if (key in value) {
|
|
161
|
+
out[key] = Boolean(value[key]);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return out;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=assignmentTypeDefaults.js.map
|
|
167
|
+
//# debugId=f18d9467-4e3c-5922-8f66-5eb168354131
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assignmentTypeDefaults.js","sources":["lib/assignmentTypeDefaults.ts"],"sourceRoot":"/","sourcesContent":["import type { AssignmentType } from \"@prisma/client\";\nimport { TRPCError } from \"@trpc/server\";\n\nexport type AssignmentTypeBehavior = {\n acceptFiles: boolean;\n acceptExtendedResponse: boolean;\n acceptWorksheet: boolean;\n singleAttempt: boolean;\n allowLateSubmissions: boolean;\n timeLimitMinutes: number | null;\n};\n\n/**\n * Sensible defaults by assignment type. QUIZ/TEST tighten attempts and\n * discourage late file spam; ESSAY/DISCUSSION prefer written response.\n */\nexport function getAssignmentTypeDefaults(\n type: AssignmentType | string | undefined | null\n): AssignmentTypeBehavior {\n switch (type) {\n case \"QUIZ\":\n return {\n acceptFiles: false,\n acceptExtendedResponse: false,\n acceptWorksheet: true,\n singleAttempt: true,\n allowLateSubmissions: false,\n timeLimitMinutes: null,\n };\n case \"TEST\":\n return {\n acceptFiles: false,\n acceptExtendedResponse: false,\n acceptWorksheet: true,\n singleAttempt: true,\n allowLateSubmissions: false,\n timeLimitMinutes: null,\n };\n case \"ESSAY\":\n return {\n acceptFiles: false,\n acceptExtendedResponse: true,\n acceptWorksheet: false,\n singleAttempt: false,\n allowLateSubmissions: true,\n timeLimitMinutes: null,\n };\n case \"DISCUSSION\":\n return {\n acceptFiles: false,\n acceptExtendedResponse: true,\n acceptWorksheet: false,\n singleAttempt: false,\n allowLateSubmissions: true,\n timeLimitMinutes: null,\n };\n case \"PROJECT\":\n case \"PRESENTATION\":\n case \"LAB\":\n return {\n acceptFiles: true,\n acceptExtendedResponse: true,\n acceptWorksheet: false,\n singleAttempt: false,\n allowLateSubmissions: true,\n timeLimitMinutes: null,\n };\n case \"HOMEWORK\":\n case \"OTHER\":\n default:\n return {\n acceptFiles: true,\n acceptExtendedResponse: false,\n acceptWorksheet: false,\n singleAttempt: false,\n allowLateSubmissions: true,\n timeLimitMinutes: null,\n };\n }\n}\n\nexport type AssignmentBehaviorInput = {\n type?: AssignmentType | string | null;\n acceptFiles?: boolean;\n acceptExtendedResponse?: boolean;\n acceptWorksheet?: boolean;\n singleAttempt?: boolean;\n allowLateSubmissions?: boolean;\n timeLimitMinutes?: number | null;\n /** When true, fill unspecified deliverable/behavior flags from type defaults. */\n applyTypeDefaults?: boolean;\n};\n\n/**\n * Merge explicit fields with type defaults and validate incompatible combos.\n */\nexport function resolveAssignmentBehavior(input: AssignmentBehaviorInput): {\n acceptFiles: boolean;\n acceptExtendedResponse: boolean;\n acceptWorksheet: boolean;\n singleAttempt: boolean;\n allowLateSubmissions: boolean;\n timeLimitMinutes: number | null | undefined;\n} {\n const defaults = getAssignmentTypeDefaults(input.type);\n const apply = input.applyTypeDefaults !== false;\n\n const acceptFiles =\n input.acceptFiles !== undefined\n ? input.acceptFiles\n : apply\n ? defaults.acceptFiles\n : false;\n const acceptExtendedResponse =\n input.acceptExtendedResponse !== undefined\n ? input.acceptExtendedResponse\n : apply\n ? defaults.acceptExtendedResponse\n : false;\n const acceptWorksheet =\n input.acceptWorksheet !== undefined\n ? input.acceptWorksheet\n : apply\n ? defaults.acceptWorksheet\n : false;\n const singleAttempt =\n input.singleAttempt !== undefined\n ? input.singleAttempt\n : apply\n ? defaults.singleAttempt\n : false;\n const allowLateSubmissions =\n input.allowLateSubmissions !== undefined\n ? input.allowLateSubmissions\n : apply\n ? defaults.allowLateSubmissions\n : true;\n const timeLimitMinutes =\n input.timeLimitMinutes !== undefined\n ? input.timeLimitMinutes\n : apply\n ? defaults.timeLimitMinutes\n : undefined;\n\n if (\n timeLimitMinutes !== undefined &&\n timeLimitMinutes !== null &&\n (timeLimitMinutes < 1 || timeLimitMinutes > 24 * 60)\n ) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message: \"timeLimitMinutes must be between 1 and 1440\",\n });\n }\n\n // Quizzes/tests: disallow file deliverables when late submissions are off\n // (prevents \"late file spam\" after the window closes).\n if (\n (input.type === \"QUIZ\" || input.type === \"TEST\") &&\n acceptFiles &&\n !allowLateSubmissions &&\n input.acceptFiles === true\n ) {\n // Allowed only when teacher explicitly opts into files; keep allowLate false.\n }\n\n if (\n !acceptFiles &&\n !acceptExtendedResponse &&\n !acceptWorksheet\n ) {\n throw new TRPCError({\n code: \"BAD_REQUEST\",\n message:\n \"Assignment must accept at least one deliverable (files, extended response, or worksheet)\",\n });\n }\n\n return {\n acceptFiles,\n acceptExtendedResponse,\n acceptWorksheet,\n singleAttempt,\n allowLateSubmissions,\n timeLimitMinutes,\n };\n}\n\nexport const SIDEBAR_FEATURE_KEYS = [\n \"overview\",\n \"assignments\",\n \"quizzes\",\n \"worksheets\",\n \"grades\",\n \"files\",\n \"modules\",\n \"discussions\",\n \"attendance\",\n \"aiLabs\",\n \"members\",\n \"syllabus\",\n \"settings\",\n] as const;\n\nexport type SidebarFeatureKey = (typeof SIDEBAR_FEATURE_KEYS)[number];\n\nexport type SidebarFeatures = Partial<Record<SidebarFeatureKey, boolean>>;\n\nexport function normalizeSidebarFeatures(\n value: unknown\n): SidebarFeatures | null {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return null;\n }\n const out: SidebarFeatures = {};\n for (const key of SIDEBAR_FEATURE_KEYS) {\n if (key in (value as object)) {\n out[key] = Boolean((value as Record<string, unknown>)[key]);\n }\n }\n return out;\n}\n"],"names":[],"mappings":"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","debug_id":"f18d9467-4e3c-5922-8f66-5eb168354131"}
|
package/dist/lib/config/env.d.ts
CHANGED
|
@@ -34,8 +34,6 @@ declare const envSchema: z.ZodObject<{
|
|
|
34
34
|
INFERENCE_API_BASE_URL: z.ZodOptional<z.ZodString>;
|
|
35
35
|
OPENAI_API_KEY: z.ZodOptional<z.ZodString>;
|
|
36
36
|
LOG_MODE: z.ZodDefault<z.ZodEnum<["normal", "verbose", "quiet"]>>;
|
|
37
|
-
/** Comma/whitespace-separated user UUIDs allowed to call `admin.*` tRPC (required in production). */
|
|
38
|
-
ADMIN_PANEL_USER_IDS: z.ZodOptional<z.ZodString>;
|
|
39
37
|
}, "strip", z.ZodTypeAny, {
|
|
40
38
|
NODE_ENV: "test" | "development" | "production";
|
|
41
39
|
LOG_MODE: "normal" | "verbose" | "quiet";
|
|
@@ -65,7 +63,6 @@ declare const envSchema: z.ZodObject<{
|
|
|
65
63
|
INFERENCE_API_KEY?: string | undefined;
|
|
66
64
|
INFERENCE_API_BASE_URL?: string | undefined;
|
|
67
65
|
OPENAI_API_KEY?: string | undefined;
|
|
68
|
-
ADMIN_PANEL_USER_IDS?: string | undefined;
|
|
69
66
|
}, {
|
|
70
67
|
DATABASE_URL: string;
|
|
71
68
|
EMAIL_HOST: string;
|
|
@@ -95,7 +92,6 @@ declare const envSchema: z.ZodObject<{
|
|
|
95
92
|
INFERENCE_API_KEY?: string | undefined;
|
|
96
93
|
INFERENCE_API_BASE_URL?: string | undefined;
|
|
97
94
|
OPENAI_API_KEY?: string | undefined;
|
|
98
|
-
ADMIN_PANEL_USER_IDS?: string | undefined;
|
|
99
95
|
}> | z.ZodObject<{
|
|
100
96
|
NODE_ENV: z.ZodDefault<z.ZodEnum<["development", "production", "test"]>>;
|
|
101
97
|
PORT: z.ZodDefault<z.ZodEffects<z.ZodString, number, string>>;
|
|
@@ -131,7 +127,6 @@ declare const envSchema: z.ZodObject<{
|
|
|
131
127
|
OPENAI_API_KEY: z.ZodOptional<z.ZodString>;
|
|
132
128
|
INFERENCE_API_BASE_URL: z.ZodOptional<z.ZodString>;
|
|
133
129
|
LOG_MODE: z.ZodDefault<z.ZodEnum<["normal", "verbose", "quiet"]>>;
|
|
134
|
-
ADMIN_PANEL_USER_IDS: z.ZodOptional<z.ZodString>;
|
|
135
130
|
}, "strip", z.ZodTypeAny, {
|
|
136
131
|
NODE_ENV: "test" | "development" | "production";
|
|
137
132
|
LOG_MODE: "normal" | "verbose" | "quiet";
|
|
@@ -161,7 +156,6 @@ declare const envSchema: z.ZodObject<{
|
|
|
161
156
|
INFERENCE_API_KEY?: string | undefined;
|
|
162
157
|
INFERENCE_API_BASE_URL?: string | undefined;
|
|
163
158
|
OPENAI_API_KEY?: string | undefined;
|
|
164
|
-
ADMIN_PANEL_USER_IDS?: string | undefined;
|
|
165
159
|
}, {
|
|
166
160
|
DATABASE_URL: string;
|
|
167
161
|
NODE_ENV?: "test" | "development" | "production" | undefined;
|
|
@@ -191,7 +185,6 @@ declare const envSchema: z.ZodObject<{
|
|
|
191
185
|
INFERENCE_API_KEY?: string | undefined;
|
|
192
186
|
INFERENCE_API_BASE_URL?: string | undefined;
|
|
193
187
|
OPENAI_API_KEY?: string | undefined;
|
|
194
|
-
ADMIN_PANEL_USER_IDS?: string | undefined;
|
|
195
188
|
}>;
|
|
196
189
|
export declare const env: {
|
|
197
190
|
NODE_ENV: "test" | "development" | "production";
|
|
@@ -222,7 +215,6 @@ export declare const env: {
|
|
|
222
215
|
INFERENCE_API_KEY?: string | undefined;
|
|
223
216
|
INFERENCE_API_BASE_URL?: string | undefined;
|
|
224
217
|
OPENAI_API_KEY?: string | undefined;
|
|
225
|
-
ADMIN_PANEL_USER_IDS?: string | undefined;
|
|
226
218
|
};
|
|
227
219
|
export type Env = z.infer<typeof envSchema>;
|
|
228
220
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.d.ts","sourceRoot":"/","sources":["lib/config/env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"/","sources":["lib/config/env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAsGxB,QAAA,MAAM,SAAS;;;;IAjEb;;;;OAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAJH;;;;OAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6D6C,CAAC;AA2CnD,eAAO,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAgB,CAAC;AAGjC,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAC"}
|
package/dist/lib/config/env.js
CHANGED
|
@@ -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]="
|
|
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]="da28616b-78b5-5754-bd3a-0b2022498054")}catch(e){}}();
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import dotenv from 'dotenv';
|
|
5
5
|
import { resolve } from 'path';
|
|
@@ -61,8 +61,6 @@ const fullSchema = baseSchema.extend({
|
|
|
61
61
|
INFERENCE_API_BASE_URL: z.string().url().optional(),
|
|
62
62
|
OPENAI_API_KEY: z.string().optional(),
|
|
63
63
|
LOG_MODE: z.enum(['normal', 'verbose', 'quiet']).default('normal'),
|
|
64
|
-
/** Comma/whitespace-separated user UUIDs allowed to call `admin.*` tRPC (required in production). */
|
|
65
|
-
ADMIN_PANEL_USER_IDS: z.string().optional(),
|
|
66
64
|
});
|
|
67
65
|
// Test schema - only require what's needed for tests
|
|
68
66
|
const testSchema = baseSchema.extend({
|
|
@@ -90,7 +88,6 @@ const testSchema = baseSchema.extend({
|
|
|
90
88
|
OPENAI_API_KEY: z.string().optional(),
|
|
91
89
|
INFERENCE_API_BASE_URL: z.string().url().optional(),
|
|
92
90
|
LOG_MODE: z.enum(['normal', 'verbose', 'quiet']).default('quiet'),
|
|
93
|
-
ADMIN_PANEL_USER_IDS: z.string().optional(),
|
|
94
91
|
});
|
|
95
92
|
// Use test schema in test mode, full schema otherwise
|
|
96
93
|
const envSchema = isTest ? testSchema : fullSchema;
|
|
@@ -134,4 +131,4 @@ function validateEnv() {
|
|
|
134
131
|
// Export validated environment variables
|
|
135
132
|
export const env = validateEnv();
|
|
136
133
|
//# sourceMappingURL=env.js.map
|
|
137
|
-
//# debugId=
|
|
134
|
+
//# debugId=da28616b-78b5-5754-bd3a-0b2022498054
|
|
@@ -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';\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 * Optional BullMQ key prefix. Defaults to `bull:<NODE_ENV>` (see\n * `getBullPrefix`). Set explicitly to isolate queues when multiple\n * databases share one Redis instance (e.g. several devs on one Upstash).\n */\n BULL_PREFIX: z.string().optional(),\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 /** Comma/whitespace-separated user UUIDs allowed to call `admin.*` tRPC (required in production). */\n ADMIN_PANEL_USER_IDS: z.string().optional(),\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 ADMIN_PANEL_USER_IDS: z.string().optional(),\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":";;AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,4BAA4B,EAAE,MAAM,WAAW,CAAC;AAEzD,qDAAqD;AACrD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa,CAAC;AACtD,MAAM,UAAU,GAA2B;IACzC,IAAI,EAAE,WAAW;IACjB,WAAW,EAAE,kBAAkB;IAC/B,UAAU,EAAE,iBAAiB;CAC9B,CAAC;AAEF,gCAAgC;AAChC,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC;AAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;AAEhD,mDAAmD;AACnD,uEAAuE;AACvE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,gCAAgC;AACjD,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,6BAA6B;AAE/E,MAAM,MAAM,GAAG,OAAO,KAAK,MAAM,CAAC;AAClC,MAAM,YAAY,GAAG,OAAO,KAAK,YAAY,CAAC;AAE9C,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC;AACvD,MAAM,+BAA+B,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,MAAM,CAClE,4BAA4B,EAC5B,EAAE,OAAO,EAAE,gEAAgE,EAAE,CAC9E,CAAC;AAEF,sDAAsD;AACtD,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1B,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;IAC9E,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IAClD,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,kCAAkC,CAAC;IAChE;;;;OAIG;IACH,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACnC,CAAC,CAAC;AAEH,uDAAuD;AACvD,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC;IACnC,mBAAmB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,uBAAuB,CAAC;IACtE,oBAAoB,EAAE,wBAAwB;IAC9C,4BAA4B,EAAE,+BAA+B;IAC7D,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,uBAAuB,CAAC;IAC9D,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACvC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,wBAAwB,CAAC;IACvD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;IACvD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,kCAAkC,CAAC;IAChE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,wBAAwB,CAAC;IACvD,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;IACrD,uBAAuB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,qCAAqC,CAAC;IACjF,yBAAyB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,iDAAiD,CAAC;IAC9F,wBAAwB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,sCAAsC,CAAC;IACnF,wBAAwB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,sCAAsC,CAAC;IACnF,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,2BAA2B,CAAC;IAC7D,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,wBAAwB,CAAC;IACvD,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,2BAA2B,CAAC;IAC7D,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,4BAA4B,CAAC;IAC/D,uBAAuB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,mDAAmD;IACnG,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,EAAE,qDAAqD;IAC7F,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACxC,sBAAsB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACnD,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACrC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;IAClE,qGAAqG;IACrG,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC5C,CAAC,CAAC;AAEH,qDAAqD;AACrD,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC;IACnC,mBAAmB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,uBAAuB,CAAC;IACjF,oBAAoB,EAAE,wBAAwB;IAC9C,4BAA4B,EAAE,+BAA+B;IAC7D,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,uBAAuB,CAAC;IACzE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACvC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,eAAe,CAAC;IAC1D,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;IACvD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,eAAe,CAAC;IAClE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;IACjD,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;IACrD,uBAAuB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,cAAc,CAAC;IACtE,yBAAyB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,mCAAmC,CAAC;IACrG,wBAAwB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC;IACnE,wBAAwB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC;IACtE,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC;IAC3D,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC;IACrD,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC;IAC3D,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IACpD,uBAAuB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACtC,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACxC,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACrC,sBAAsB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACnD,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IACjE,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC5C,CAAC,CAAC;AAEH,sDAAsD;AACtD,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC;AAEnD,iCAAiC;AACjC,SAAS,WAAW;IAClB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAE5C,gDAAgD;QAChD,IAAI,YAAY,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;YACzC,MAAM,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;YACvD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,CAAC,CAAC,QAAQ,EAAE,CAAC;YAChC,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC3C,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;gBACxB,OAAO,EAAE,GAAG,CAAC,OAAO;aACrB,CAAC,CAAC,CAAC;YAEJ,MAAM,CAAC,KAAK,CAAC,wCAAwC,EAAE;gBACrD,OAAO;gBACP,WAAW;aACZ,CAAC,CAAC;YAEH,kEAAkE;YAClE,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,CAAC,KAAK,CAAC,qBAAqB,OAAO,kDAAkD,CAAC,CAAC;gBAC7F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,CAAC,iEAAiE,EAAE;oBAC7E,OAAO;iBACR,CAAC,CAAC;gBACH,iDAAiD;gBACjD,OAAO,SAAS,CAAC,KAAK,CAAC,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,yCAAyC;AACzC,MAAM,CAAC,MAAM,GAAG,GAAG,WAAW,EAAE,CAAC","debug_id":"8e7c7480-b0bc-5778-9502-7fd6d8f4dae8"}
|
|
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 * Optional BullMQ key prefix. Defaults to `bull:<NODE_ENV>` (see\n * `getBullPrefix`). Set explicitly to isolate queues when multiple\n * databases share one Redis instance (e.g. several devs on one Upstash).\n */\n BULL_PREFIX: z.string().optional(),\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":"da28616b-78b5-5754-bd3a-0b2022498054"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { formatNpr, monthLabel } from "./feePdfFormat.js";
|
|
2
|
+
export { formatNpr, monthLabel };
|
|
3
|
+
export type FeePdfLine = {
|
|
4
|
+
label: string;
|
|
5
|
+
value: string;
|
|
6
|
+
};
|
|
7
|
+
export interface FeePdfDocumentInput {
|
|
8
|
+
schoolName: string;
|
|
9
|
+
title: string;
|
|
10
|
+
subtitle?: string;
|
|
11
|
+
lines: FeePdfLine[];
|
|
12
|
+
footerNote?: string;
|
|
13
|
+
letterhead?: {
|
|
14
|
+
path: string;
|
|
15
|
+
type: string;
|
|
16
|
+
} | null;
|
|
17
|
+
}
|
|
18
|
+
export declare function buildFeePdf(input: FeePdfDocumentInput): Promise<Uint8Array>;
|
|
19
|
+
//# sourceMappingURL=feePdf.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feePdf.d.ts","sourceRoot":"/","sources":["lib/feePdf.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE1D,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC;AAEjC,MAAM,MAAM,UAAU,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1D,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACd,GAAG,IAAI,CAAC;CACV;AAoED,wBAAsB,WAAW,CAC/B,KAAK,EAAE,mBAAmB,GACzB,OAAO,CAAC,UAAU,CAAC,CA6FrB"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fee invoice / receipt PDF generation.
|
|
3
|
+
*
|
|
4
|
+
* Stamps content onto the school's uploaded letterhead when present:
|
|
5
|
+
* - PDF letterhead → reuse first page as background
|
|
6
|
+
* - Image letterhead (png/jpeg) → draw full-page background then text
|
|
7
|
+
* - No letterhead → plain A4 page with school name header
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
!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]="c5f88a88-dde6-5eeb-89ee-f9b02e9e22a1")}catch(e){}}();
|
|
11
|
+
import { PDFDocument, StandardFonts, rgb, degrees, } from "pdf-lib";
|
|
12
|
+
import fontkit from "@pdf-lib/fontkit";
|
|
13
|
+
import { readFileSync } from "fs";
|
|
14
|
+
import { join } from "path";
|
|
15
|
+
import { bucket } from "./googleCloudStorage.js";
|
|
16
|
+
import { logger } from "../utils/logger.js";
|
|
17
|
+
import { formatNpr, monthLabel } from "./feePdfFormat.js";
|
|
18
|
+
export { formatNpr, monthLabel };
|
|
19
|
+
async function loadUnicodeFonts(pdfDoc) {
|
|
20
|
+
pdfDoc.registerFontkit(fontkit);
|
|
21
|
+
const fontDir = join(process.cwd(), "src", "lib");
|
|
22
|
+
try {
|
|
23
|
+
const regular = readFileSync(join(fontDir, "NotoSans-Regular.ttf"));
|
|
24
|
+
const bold = readFileSync(join(fontDir, "NotoSans-Bold.ttf"));
|
|
25
|
+
return {
|
|
26
|
+
regular: await pdfDoc.embedFont(regular),
|
|
27
|
+
bold: await pdfDoc.embedFont(bold),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
logger.warn(`feePdf: falling back to Helvetica fonts: ${err}`);
|
|
32
|
+
return {
|
|
33
|
+
regular: await pdfDoc.embedFont(StandardFonts.Helvetica),
|
|
34
|
+
bold: await pdfDoc.embedFont(StandardFonts.HelveticaBold),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async function loadLetterheadBytes(path) {
|
|
39
|
+
try {
|
|
40
|
+
const [bytes] = await bucket.file(path).download();
|
|
41
|
+
return bytes;
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
logger.warn(`feePdf: failed to download letterhead ${path}: ${err}`);
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async function preparePage(pdfDoc, letterhead) {
|
|
49
|
+
if (letterhead?.path) {
|
|
50
|
+
const bytes = await loadLetterheadBytes(letterhead.path);
|
|
51
|
+
if (bytes) {
|
|
52
|
+
const type = (letterhead.type || "").toLowerCase();
|
|
53
|
+
if (type.includes("pdf") || letterhead.path.toLowerCase().endsWith(".pdf")) {
|
|
54
|
+
const src = await PDFDocument.load(bytes);
|
|
55
|
+
const [page] = await pdfDoc.copyPages(src, [0]);
|
|
56
|
+
pdfDoc.addPage(page);
|
|
57
|
+
return pdfDoc.getPage(0);
|
|
58
|
+
}
|
|
59
|
+
if (type.includes("png") ||
|
|
60
|
+
type.includes("jpeg") ||
|
|
61
|
+
type.includes("jpg")) {
|
|
62
|
+
const page = pdfDoc.addPage();
|
|
63
|
+
const { width, height } = page.getSize();
|
|
64
|
+
try {
|
|
65
|
+
const image = type.includes("png")
|
|
66
|
+
? await pdfDoc.embedPng(bytes)
|
|
67
|
+
: await pdfDoc.embedJpg(bytes);
|
|
68
|
+
page.drawImage(image, { x: 0, y: 0, width, height });
|
|
69
|
+
return page;
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
logger.warn(`feePdf: could not embed letterhead image: ${err}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return pdfDoc.addPage();
|
|
78
|
+
}
|
|
79
|
+
export async function buildFeePdf(input) {
|
|
80
|
+
const pdfDoc = await PDFDocument.create();
|
|
81
|
+
const fonts = await loadUnicodeFonts(pdfDoc);
|
|
82
|
+
const page = await preparePage(pdfDoc, input.letterhead);
|
|
83
|
+
const { width, height } = page.getSize();
|
|
84
|
+
const left = 56;
|
|
85
|
+
const right = width - 56;
|
|
86
|
+
let y = height - 120;
|
|
87
|
+
// When no letterhead, print school name as a simple header.
|
|
88
|
+
if (!input.letterhead?.path) {
|
|
89
|
+
page.drawText(input.schoolName, {
|
|
90
|
+
x: left,
|
|
91
|
+
y: height - 56,
|
|
92
|
+
size: 16,
|
|
93
|
+
font: fonts.bold,
|
|
94
|
+
color: rgb(0.1, 0.1, 0.1),
|
|
95
|
+
});
|
|
96
|
+
y = height - 96;
|
|
97
|
+
}
|
|
98
|
+
page.drawText(input.title, {
|
|
99
|
+
x: left,
|
|
100
|
+
y,
|
|
101
|
+
size: 18,
|
|
102
|
+
font: fonts.bold,
|
|
103
|
+
color: rgb(0.08, 0.08, 0.08),
|
|
104
|
+
});
|
|
105
|
+
y -= 22;
|
|
106
|
+
if (input.subtitle) {
|
|
107
|
+
page.drawText(input.subtitle, {
|
|
108
|
+
x: left,
|
|
109
|
+
y,
|
|
110
|
+
size: 11,
|
|
111
|
+
font: fonts.regular,
|
|
112
|
+
color: rgb(0.3, 0.3, 0.3),
|
|
113
|
+
});
|
|
114
|
+
y -= 28;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
y -= 12;
|
|
118
|
+
}
|
|
119
|
+
page.drawLine({
|
|
120
|
+
start: { x: left, y },
|
|
121
|
+
end: { x: right, y },
|
|
122
|
+
thickness: 0.75,
|
|
123
|
+
color: rgb(0.75, 0.75, 0.75),
|
|
124
|
+
});
|
|
125
|
+
y -= 28;
|
|
126
|
+
for (const line of input.lines) {
|
|
127
|
+
page.drawText(line.label, {
|
|
128
|
+
x: left,
|
|
129
|
+
y,
|
|
130
|
+
size: 10,
|
|
131
|
+
font: fonts.regular,
|
|
132
|
+
color: rgb(0.35, 0.35, 0.35),
|
|
133
|
+
});
|
|
134
|
+
const valueWidth = fonts.bold.widthOfTextAtSize(line.value, 11);
|
|
135
|
+
page.drawText(line.value, {
|
|
136
|
+
x: Math.max(left + 160, right - valueWidth),
|
|
137
|
+
y,
|
|
138
|
+
size: 11,
|
|
139
|
+
font: fonts.bold,
|
|
140
|
+
color: rgb(0.1, 0.1, 0.1),
|
|
141
|
+
});
|
|
142
|
+
y -= 22;
|
|
143
|
+
if (y < 80)
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
if (input.footerNote) {
|
|
147
|
+
page.drawText(input.footerNote, {
|
|
148
|
+
x: left,
|
|
149
|
+
y: 48,
|
|
150
|
+
size: 9,
|
|
151
|
+
font: fonts.regular,
|
|
152
|
+
color: rgb(0.45, 0.45, 0.45),
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
// Light watermark so blank letterheads still look intentional.
|
|
156
|
+
page.drawText("Studious", {
|
|
157
|
+
x: width / 2 - 40,
|
|
158
|
+
y: 28,
|
|
159
|
+
size: 8,
|
|
160
|
+
font: fonts.regular,
|
|
161
|
+
color: rgb(0.7, 0.7, 0.7),
|
|
162
|
+
rotate: degrees(0),
|
|
163
|
+
});
|
|
164
|
+
return pdfDoc.save();
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=feePdf.js.map
|
|
167
|
+
//# debugId=c5f88a88-dde6-5eeb-89ee-f9b02e9e22a1
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feePdf.js","sources":["lib/feePdf.ts"],"sourceRoot":"/","sourcesContent":["/**\n * Fee invoice / receipt PDF generation.\n *\n * Stamps content onto the school's uploaded letterhead when present:\n * - PDF letterhead → reuse first page as background\n * - Image letterhead (png/jpeg) → draw full-page background then text\n * - No letterhead → plain A4 page with school name header\n */\nimport {\n PDFDocument,\n StandardFonts,\n rgb,\n degrees,\n} from \"pdf-lib\";\nimport fontkit from \"@pdf-lib/fontkit\";\nimport { readFileSync } from \"fs\";\nimport { join } from \"path\";\nimport { bucket } from \"./googleCloudStorage.js\";\nimport { logger } from \"../utils/logger.js\";\nimport { formatNpr, monthLabel } from \"./feePdfFormat.js\";\n\nexport { formatNpr, monthLabel };\n\nexport type FeePdfLine = { label: string; value: string };\n\nexport interface FeePdfDocumentInput {\n schoolName: string;\n title: string;\n subtitle?: string;\n lines: FeePdfLine[];\n footerNote?: string;\n letterhead?: {\n path: string;\n type: string;\n } | null;\n}\n\nasync function loadUnicodeFonts(pdfDoc: PDFDocument) {\n pdfDoc.registerFontkit(fontkit);\n const fontDir = join(process.cwd(), \"src\", \"lib\");\n try {\n const regular = readFileSync(join(fontDir, \"NotoSans-Regular.ttf\"));\n const bold = readFileSync(join(fontDir, \"NotoSans-Bold.ttf\"));\n return {\n regular: await pdfDoc.embedFont(regular),\n bold: await pdfDoc.embedFont(bold),\n };\n } catch (err) {\n logger.warn(`feePdf: falling back to Helvetica fonts: ${err}`);\n return {\n regular: await pdfDoc.embedFont(StandardFonts.Helvetica),\n bold: await pdfDoc.embedFont(StandardFonts.HelveticaBold),\n };\n }\n}\n\nasync function loadLetterheadBytes(path: string): Promise<Uint8Array | null> {\n try {\n const [bytes] = await bucket.file(path).download();\n return bytes;\n } catch (err) {\n logger.warn(`feePdf: failed to download letterhead ${path}: ${err}`);\n return null;\n }\n}\n\nasync function preparePage(\n pdfDoc: PDFDocument,\n letterhead?: FeePdfDocumentInput[\"letterhead\"]\n) {\n if (letterhead?.path) {\n const bytes = await loadLetterheadBytes(letterhead.path);\n if (bytes) {\n const type = (letterhead.type || \"\").toLowerCase();\n if (type.includes(\"pdf\") || letterhead.path.toLowerCase().endsWith(\".pdf\")) {\n const src = await PDFDocument.load(bytes);\n const [page] = await pdfDoc.copyPages(src, [0]);\n pdfDoc.addPage(page);\n return pdfDoc.getPage(0);\n }\n if (\n type.includes(\"png\") ||\n type.includes(\"jpeg\") ||\n type.includes(\"jpg\")\n ) {\n const page = pdfDoc.addPage();\n const { width, height } = page.getSize();\n try {\n const image = type.includes(\"png\")\n ? await pdfDoc.embedPng(bytes)\n : await pdfDoc.embedJpg(bytes);\n page.drawImage(image, { x: 0, y: 0, width, height });\n return page;\n } catch (err) {\n logger.warn(`feePdf: could not embed letterhead image: ${err}`);\n }\n }\n }\n }\n\n return pdfDoc.addPage();\n}\n\nexport async function buildFeePdf(\n input: FeePdfDocumentInput\n): Promise<Uint8Array> {\n const pdfDoc = await PDFDocument.create();\n const fonts = await loadUnicodeFonts(pdfDoc);\n const page = await preparePage(pdfDoc, input.letterhead);\n const { width, height } = page.getSize();\n\n const left = 56;\n const right = width - 56;\n let y = height - 120;\n\n // When no letterhead, print school name as a simple header.\n if (!input.letterhead?.path) {\n page.drawText(input.schoolName, {\n x: left,\n y: height - 56,\n size: 16,\n font: fonts.bold,\n color: rgb(0.1, 0.1, 0.1),\n });\n y = height - 96;\n }\n\n page.drawText(input.title, {\n x: left,\n y,\n size: 18,\n font: fonts.bold,\n color: rgb(0.08, 0.08, 0.08),\n });\n y -= 22;\n\n if (input.subtitle) {\n page.drawText(input.subtitle, {\n x: left,\n y,\n size: 11,\n font: fonts.regular,\n color: rgb(0.3, 0.3, 0.3),\n });\n y -= 28;\n } else {\n y -= 12;\n }\n\n page.drawLine({\n start: { x: left, y },\n end: { x: right, y },\n thickness: 0.75,\n color: rgb(0.75, 0.75, 0.75),\n });\n y -= 28;\n\n for (const line of input.lines) {\n page.drawText(line.label, {\n x: left,\n y,\n size: 10,\n font: fonts.regular,\n color: rgb(0.35, 0.35, 0.35),\n });\n const valueWidth = fonts.bold.widthOfTextAtSize(line.value, 11);\n page.drawText(line.value, {\n x: Math.max(left + 160, right - valueWidth),\n y,\n size: 11,\n font: fonts.bold,\n color: rgb(0.1, 0.1, 0.1),\n });\n y -= 22;\n if (y < 80) break;\n }\n\n if (input.footerNote) {\n page.drawText(input.footerNote, {\n x: left,\n y: 48,\n size: 9,\n font: fonts.regular,\n color: rgb(0.45, 0.45, 0.45),\n });\n }\n\n // Light watermark so blank letterheads still look intentional.\n page.drawText(\"Studious\", {\n x: width / 2 - 40,\n y: 28,\n size: 8,\n font: fonts.regular,\n color: rgb(0.7, 0.7, 0.7),\n rotate: degrees(0),\n });\n\n return pdfDoc.save();\n}\n"],"names":[],"mappings":"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","debug_id":"c5f88a88-dde6-5eeb-89ee-f9b02e9e22a1"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feePdfFormat.d.ts","sourceRoot":"/","sources":["lib/feePdfFormat.ts"],"names":[],"mappings":"AAAA,oEAAoE;AAEpE,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,UAEvC;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,UAOrD"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Pure formatting helpers for fee invoices / receipts (no I/O). */
|
|
2
|
+
|
|
3
|
+
!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]="2db5c56e-f0c1-5234-906c-b7f44d03e976")}catch(e){}}();
|
|
4
|
+
export function formatNpr(amount) {
|
|
5
|
+
return `NPR ${amount.toLocaleString("en-NP")}`;
|
|
6
|
+
}
|
|
7
|
+
export function monthLabel(year, month) {
|
|
8
|
+
const d = new Date(Date.UTC(year, month - 1, 1));
|
|
9
|
+
return d.toLocaleString("en-GB", {
|
|
10
|
+
month: "long",
|
|
11
|
+
year: "numeric",
|
|
12
|
+
timeZone: "UTC",
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=feePdfFormat.js.map
|
|
16
|
+
//# debugId=2db5c56e-f0c1-5234-906c-b7f44d03e976
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feePdfFormat.js","sources":["lib/feePdfFormat.ts"],"sourceRoot":"/","sourcesContent":["/** Pure formatting helpers for fee invoices / receipts (no I/O). */\n\nexport function formatNpr(amount: number) {\n return `NPR ${amount.toLocaleString(\"en-NP\")}`;\n}\n\nexport function monthLabel(year: number, month: number) {\n const d = new Date(Date.UTC(year, month - 1, 1));\n return d.toLocaleString(\"en-GB\", {\n month: \"long\",\n year: \"numeric\",\n timeZone: \"UTC\",\n });\n}\n"],"names":[],"mappings":"AAAA,oEAAoE;;;AAEpE,MAAM,UAAU,SAAS,CAAC,MAAc;IACtC,OAAO,OAAO,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,KAAa;IACpD,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACjD,OAAO,CAAC,CAAC,cAAc,CAAC,OAAO,EAAE;QAC/B,KAAK,EAAE,MAAM;QACb,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,KAAK;KAChB,CAAC,CAAC;AACL,CAAC","debug_id":"2db5c56e-f0c1-5234-906c-b7f44d03e976"}
|