@litusarchieve18/agricore-utils 1.0.12 → 1.0.14

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/dist/index.js CHANGED
@@ -30,8 +30,12 @@ __export(index_exports, {
30
30
  AuditStatus: () => AuditStatus,
31
31
  AuditType: () => AuditType,
32
32
  CAT: () => CAT,
33
+ CATEGORY_TABS: () => CATEGORY_TABS,
33
34
  Converter: () => Converter,
34
35
  CropCycleStatus: () => CropCycleStatus,
36
+ DOCUMENT_DISPLAY_INFO: () => DOCUMENT_DISPLAY_INFO,
37
+ DOCUMENT_MENU_MAP: () => DOCUMENT_MENU_MAP,
38
+ DocumentCategory: () => DocumentCategory,
35
39
  DocumentType: () => DocumentType,
36
40
  ERROR_DICTIONARY: () => ERROR_DICTIONARY,
37
41
  EVERYONE: () => EVERYONE,
@@ -287,7 +291,7 @@ var Converter = {
287
291
  }
288
292
  };
289
293
 
290
- // src/index.ts
294
+ // src/constants.ts
291
295
  var MOD = {
292
296
  OPERATIONS: "OPR",
293
297
  EQUIPMENT: "EQP",
@@ -301,7 +305,6 @@ var MOD = {
301
305
  ALERTS: "ALT",
302
306
  INFRA: "INF",
303
307
  SESSION: "SES"
304
- // ← added: used in generateSessionContext but was missing from errorRegistry.js
305
308
  };
306
309
  var CAT = {
307
310
  SUBSCRIPTION: "1",
@@ -318,43 +321,6 @@ var ACT = {
318
321
  UPLOAD: "05"
319
322
  };
320
323
  var SENTINEL_UUID = "00000000-0000-0000-0000-000000000000";
321
- var AppError = class extends Error {
322
- status;
323
- appCode;
324
- isOperational;
325
- constructor(status, mod, cat, act, message) {
326
- super(message);
327
- this.status = status;
328
- this.appCode = `${mod}-${status}-${cat}${act}`;
329
- this.isOperational = true;
330
- Object.setPrototypeOf(this, new.target.prototype);
331
- }
332
- };
333
- var ErrorFactory = {
334
- unauthorized: (mod, msg = "Authentication required") => new AppError(401, mod, CAT.PERMISSION, ACT.GENERIC, msg),
335
- forbidden: (mod, act, msg = "Access denied") => new AppError(403, mod, CAT.PERMISSION, act, msg),
336
- badRequest: (mod, act, msg = "Bad request") => new AppError(400, mod, CAT.VALIDATION, act, msg),
337
- notFound: (mod, act = ACT.GENERIC, msg = "Record not found") => new AppError(404, mod, CAT.VALIDATION, act, msg),
338
- conflict: (mod, act, msg = "Record already exists") => new AppError(409, mod, CAT.INTEGRITY, act, msg),
339
- integrity: (mod, act = ACT.GENERIC, msg = "Data integrity violation") => new AppError(409, mod, CAT.INTEGRITY, act, msg),
340
- subscription: (mod, msg = "Module locked or subscription required") => new AppError(403, mod, CAT.SUBSCRIPTION, ACT.GENERIC, msg),
341
- internal: (mod, msg = "Internal server error") => new AppError(500, mod, CAT.INTEGRITY, ACT.GENERIC, msg)
342
- };
343
- var handleAppErrorResponse = (error, mod = MOD.ADMIN) => {
344
- if (error instanceof AppError && error.isOperational) {
345
- return Response.json(
346
- { error: { appCode: error.appCode, message: error.message } },
347
- { status: error.status }
348
- );
349
- }
350
- const e = error;
351
- console.error(`[${mod}] UNEXPECTED ERROR:`, e?.message);
352
- console.error(`[${mod}] STACK:`, e?.stack);
353
- return Response.json(
354
- { error: { appCode: `${mod}-500-000`, message: "An unexpected server error occurred. Please try again." } },
355
- { status: 500 }
356
- );
357
- };
358
324
  var MODULE_LABELS = {
359
325
  [MOD.OPERATIONS]: "Operations",
360
326
  [MOD.EQUIPMENT]: "Equipment & Fleet",
@@ -392,147 +358,6 @@ var ERROR_DICTIONARY = {
392
358
  "403": { title: "Edit Conflict", text: "This record was recently updated by someone else. Please refresh and try again." },
393
359
  "404": { title: "Record In Use", text: "This record cannot be deleted because it is referenced by other data." }
394
360
  };
395
- var FALLBACK = {
396
- title: "Something Went Wrong",
397
- text: "An unexpected error occurred. Please try again or contact your administrator."
398
- };
399
- var resolveAppError = (appCode) => {
400
- if (!appCode || typeof appCode !== "string") {
401
- return { ...FALLBACK, module: "UNK", moduleLabel: "Unknown", status: 500, catAct: "000", isSubscriptionIssue: false, isPermissionIssue: false };
402
- }
403
- const parts = appCode.split("-");
404
- if (parts.length !== 3) {
405
- return { ...FALLBACK, module: "UNK", moduleLabel: "Unknown", status: 500, catAct: "000", isSubscriptionIssue: false, isPermissionIssue: false };
406
- }
407
- const [mod, status, catAct] = parts;
408
- const details = ERROR_DICTIONARY[catAct] || FALLBACK;
409
- return {
410
- title: details.title,
411
- text: details.text,
412
- module: mod,
413
- moduleLabel: MODULE_LABELS[mod] || mod,
414
- status: parseInt(status, 10),
415
- catAct,
416
- isSubscriptionIssue: catAct.startsWith("1"),
417
- isPermissionIssue: catAct.startsWith("2")
418
- };
419
- };
420
- var extractAppCode = (error) => {
421
- const e = error;
422
- return e?.response?.data?.error?.appCode ?? e?.data?.error?.appCode ?? null;
423
- };
424
- var resolveError = (error) => {
425
- const appCode = extractAppCode(error);
426
- if (appCode) return resolveAppError(appCode);
427
- const e = error;
428
- return { ...FALLBACK, module: "UNK", moduleLabel: "Unknown", status: e?.status || 500, catAct: "000", isSubscriptionIssue: false, isPermissionIssue: false };
429
- };
430
- function generateCanonicalId() {
431
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
432
- return crypto.randomUUID();
433
- }
434
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
435
- const r = Math.random() * 16 | 0;
436
- return (c === "x" ? r : r & 3 | 8).toString(16);
437
- });
438
- }
439
- function generateInfrastructureFields(activeScope, availableScopes) {
440
- if (!activeScope || !availableScopes?.length) {
441
- throw ErrorFactory.unauthorized("[generateInfrastructureFields] Missing scope context.");
442
- }
443
- let companyId = null;
444
- let legalEntityId = null;
445
- let facilityId = null;
446
- let pointer = activeScope;
447
- while (pointer) {
448
- if (pointer.type === "company") companyId = pointer.base44Id;
449
- if (pointer.type === "legalEntity") legalEntityId = pointer.base44Id;
450
- if (pointer.type === "facility") facilityId = pointer.base44Id;
451
- const parentId = pointer.parentId ?? null;
452
- pointer = parentId ? availableScopes.find((s) => s.base44Id === parentId) || null : null;
453
- }
454
- if (!companyId) {
455
- throw ErrorFactory.unauthorized("[generateInfrastructureFields] Could not resolve companyId from scope tree.");
456
- }
457
- return {
458
- canonicalId: crypto.randomUUID(),
459
- companyId,
460
- legalEntityId,
461
- facilityId,
462
- authScopeId: activeScope.authScopeId
463
- };
464
- }
465
- function buildRlsFilter(session, extra = {}) {
466
- return { ...extra, authScopeId: { $in: session.readScopes || [] } };
467
- }
468
- function canRead(session, authScopeId) {
469
- return session.readScopes?.includes(authScopeId) ?? false;
470
- }
471
- function canWrite(session, authScopeId, resourcePath) {
472
- const override = session.resourceOverrides?.[authScopeId]?.[resourcePath];
473
- if (override === "WRITE") return true;
474
- if (override === "NONE" || override === "READ") return false;
475
- return session.writeScopes?.includes(authScopeId) ?? false;
476
- }
477
- function assertCanWrite(session, authScopeId, resourcePath) {
478
- const override = session.resourceOverrides?.[authScopeId]?.[resourcePath];
479
- if (override === "WRITE") return;
480
- if (override === "NONE" || override === "READ") {
481
- throw new AppError(
482
- 403,
483
- MOD.SESSION,
484
- CAT.PERMISSION,
485
- ACT.GENERIC,
486
- `You do not have write access to "${resourcePath}" in this scope.`
487
- );
488
- }
489
- if (session.writeScopes?.includes(authScopeId)) return;
490
- throw new AppError(
491
- 403,
492
- MOD.SESSION,
493
- CAT.PERMISSION,
494
- ACT.GENERIC,
495
- "You do not have permission to modify records in this scope."
496
- );
497
- }
498
- function resolveAccess(session, activeScopeId, tabConfig) {
499
- const resourcePath = tabConfig?.resourceId;
500
- const overrides = session.resourceOverrides?.[activeScopeId] ?? {};
501
- if (resourcePath) {
502
- const segments = resourcePath.split(".");
503
- for (let len = segments.length; len >= 1; len--) {
504
- const path = segments.slice(0, len).join(".");
505
- const override = overrides[path];
506
- if (override === "NONE" || override === "READ" || override === "WRITE") return override;
507
- }
508
- }
509
- const allowedRoles = tabConfig?.allowedRoles ?? [];
510
- const requiredPrivileges = tabConfig?.requiredPrivileges ?? [];
511
- const hasRestrictions = allowedRoles.length > 0 || requiredPrivileges.length > 0;
512
- if (hasRestrictions) {
513
- const role = session?.role ?? "";
514
- const privileges = session?.privileges ?? [];
515
- const passesRole = allowedRoles.length > 0 && allowedRoles.includes(role);
516
- const passesPrivilege = requiredPrivileges.length > 0 && requiredPrivileges.some((p) => privileges.includes(p));
517
- return passesRole || passesPrivilege ? "WRITE" : "NONE";
518
- }
519
- return "READ";
520
- }
521
- function resolveMenuVisibility(session, authScopeId, resourcePath) {
522
- const override = session.resourceOverrides?.[authScopeId]?.[resourcePath];
523
- if (override === "NONE") return "hidden";
524
- if (override === "READ") return "read_only";
525
- if (override === "WRITE") return "active";
526
- if (session.writeScopes?.includes(authScopeId)) return "active";
527
- if (session.readScopes?.includes(authScopeId)) return "read_only";
528
- return "hidden";
529
- }
530
- function isTabVisible(session, activeScopeId, tabConfig) {
531
- return resolveAccess(session, activeScopeId, tabConfig) !== "NONE";
532
- }
533
- function isTabWritable(session, activeScopeId, tabConfig) {
534
- return resolveAccess(session, activeScopeId, tabConfig) === "WRITE";
535
- }
536
361
  var UserRole = {
537
362
  OWNER: "owner",
538
363
  MANAGER: "manager",
@@ -752,17 +577,6 @@ var FORM_REGISTRY = {
752
577
  // ── Audit & Compliance ───────────────────────────────────────────────────
753
578
  auditProjectForm: { label: "Audit Project", menuUrl: "/admin", module: "Audit & Compliance" }
754
579
  };
755
- function getFormMeta(componentId) {
756
- return FORM_REGISTRY[componentId] ?? null;
757
- }
758
- function getFormsGroupedByModule() {
759
- const groups = {};
760
- for (const [id, meta] of Object.entries(FORM_REGISTRY)) {
761
- if (!groups[meta.module]) groups[meta.module] = [];
762
- groups[meta.module].push({ id, ...meta });
763
- }
764
- return groups;
765
- }
766
580
  var TASK_TYPE_REGISTRY = {
767
581
  INVOICE_OCR: {
768
582
  label: "Invoice / Receipt OCR",
@@ -797,20 +611,6 @@ var TASK_TYPE_REGISTRY = {
797
611
  approveAction: "ATTACH_REPORT_FILE"
798
612
  }
799
613
  };
800
- var getTaskTypeOptions = () => Object.entries(TASK_TYPE_REGISTRY).map(([value, config]) => ({
801
- value,
802
- label: config.label,
803
- description: config.description,
804
- mimeTypes: config.mimeTypes,
805
- icon: config.icon
806
- }));
807
- var getAcceptedMimeTypes = (taskType) => {
808
- const config = TASK_TYPE_REGISTRY[taskType];
809
- return config ? config.mimeTypes.join(",") : "*/*";
810
- };
811
- var getApproveAction = (taskType) => {
812
- return TASK_TYPE_REGISTRY[taskType]?.approveAction ?? null;
813
- };
814
614
  var RESOURCE_PATHS = {
815
615
  // ── Top-level menu sections ────────────────────────────────────────────────
816
616
  dashboard: "dashboard",
@@ -862,7 +662,6 @@ var AGRI_ONLY = [
862
662
  ];
863
663
  var RESOURCE_MODULE_MAP = {
864
664
  // ── Top-level menu sections ────────────────────────────────────────────────
865
- // CORE features (accessible to everyone with an account)
866
665
  [RESOURCE_PATHS.dashboard]: [],
867
666
  [RESOURCE_PATHS.operations]: ALL_OPERATIONS,
868
667
  [RESOURCE_PATHS.equipment]: ALL_OPERATIONS,
@@ -917,17 +716,8 @@ var ROLE_SECTIONS_BY_KEY = {
917
716
  };
918
717
  var EVERYONE = Object.values(UserRole);
919
718
  var RESOURCE_REQUIREMENTS = {
920
- [RESOURCE_PATHS.dashboard]: {
921
- allowedRoles: EVERYONE
922
- },
923
- [RESOURCE_PATHS.operations]: {
924
- allowedRoles: EVERYONE
925
- },
926
- // [RESOURCE_PATHS.equipment]: EVERYONE,
927
- // [RESOURCE_PATHS.safety]: ALL_OPERATIONS,
928
- // [RESOURCE_PATHS.team]: ALL_OPERATIONS,
929
- // [RESOURCE_PATHS.records]: ALL_OPERATIONS,
930
- // [RESOURCE_PATHS.adminSettings]: ALL_OPERATIONS,
719
+ [RESOURCE_PATHS.dashboard]: { allowedRoles: EVERYONE },
720
+ [RESOURCE_PATHS.operations]: { allowedRoles: EVERYONE },
931
721
  // ── Records & Reports ──────────────────────────────────────────────────────
932
722
  [RESOURCE_PATHS.documentHub]: {
933
723
  allowedRoles: [UserRole.OWNER, UserRole.MANAGER, UserRole.SUPERVISOR],
@@ -949,7 +739,6 @@ var RESOURCE_REQUIREMENTS = {
949
739
  allowedRoles: [UserRole.OWNER, UserRole.MANAGER, UserRole.SUPERVISOR],
950
740
  requiredPrivileges: [UserPrivilege.ADMIN, UserPrivilege.AUDIT_COMPLIANCE, UserPrivilege.FINANCE, UserPrivilege.HR]
951
741
  },
952
- // [RESOURCE_PATHS.analytics]: ALL_OPERATIONS,
953
742
  // ── Admin Settings ─────────────────────────────────────────────────────────
954
743
  [RESOURCE_PATHS.adminUserRoster]: {
955
744
  allowedRoles: [UserRole.OWNER],
@@ -966,101 +755,7 @@ var RESOURCE_REQUIREMENTS = {
966
755
  [RESOURCE_PATHS.adminCompanySettings]: {
967
756
  allowedRoles: [UserRole.OWNER]
968
757
  }
969
- // // ── Operations ────────────────────────────────────────────────────────────
970
- // [RESOURCE_PATHS.farmManagement]: [EnabledModule.FARM_MANAGEMENT],
971
- // [RESOURCE_PATHS.packhouse]: [EnabledModule.PACKHOUSE],
972
- // [RESOURCE_PATHS.accommodation]: [EnabledModule.ACCOMMODATION],
973
- // // ── Equipment & Fleet ──────────────────────────────────────────────────────
974
- // [RESOURCE_PATHS.equipPreStart]: ALL_OPERATIONS,
975
- // [RESOURCE_PATHS.equipMaintenance]: ALL_OPERATIONS,
976
- // [RESOURCE_PATHS.equipFuelRegister]: ALL_OPERATIONS,
977
- // [RESOURCE_PATHS.equipCalibration]: AGRI_ONLY,
978
- // [RESOURCE_PATHS.equipFleet]: ALL_OPERATIONS,
979
- // // ── Safety, Quality & Compliance ──────────────────────────────────────────
980
- // [RESOURCE_PATHS.safetyAuditing]: ALL_OPERATIONS,
981
- // [RESOURCE_PATHS.safetyFood]: AGRI_ONLY,
982
- // [RESOURCE_PATHS.safetyWhs]: ALL_OPERATIONS,
983
- // [RESOURCE_PATHS.safetyCleaning]: ALL_OPERATIONS,
984
- // // ── Team & HR ──────────────────────────────────────────────────────────────
985
- // [RESOURCE_PATHS.teamStaff]: ALL_OPERATIONS,
986
- // [RESOURCE_PATHS.teamTraining]: ALL_OPERATIONS,
987
758
  };
988
- function evaluateBaseAccess(resourcePath, session, requirements = {}) {
989
- if (!session?.role) return "NONE";
990
- if (session.role === UserRole.OWNER) return "WRITE";
991
- const requiredModules = RESOURCE_MODULE_MAP[resourcePath] || [];
992
- if (requiredModules.length > 0) {
993
- const hasModule = requiredModules.some((m) => session.enabledModules?.includes(m));
994
- if (!hasModule) return "NONE";
995
- }
996
- const topLevel = resourcePath.split(".")[0];
997
- const defaultRoles = ROLE_SECTIONS_BY_KEY[topLevel] || [];
998
- const allowedRoles = requirements.allowedRoles?.length ? requirements.allowedRoles : defaultRoles;
999
- if (!allowedRoles.includes(session.role)) return "NONE";
1000
- if (requirements.requiredPrivileges?.length) {
1001
- const hasPrivilege = requirements.requiredPrivileges.some((p) => session.privileges?.includes(p));
1002
- if (!hasPrivilege) return "NONE";
1003
- }
1004
- return session.role === UserRole.MANAGER ? "WRITE" : "READ";
1005
- }
1006
- function resolveEffectiveAccess(base, override) {
1007
- return override === void 0 || override === null ? base : override;
1008
- }
1009
- function findSpecificOverride(session, activeScopeId, resourcePath) {
1010
- const scopeOverrides = session.resourceOverrides?.[activeScopeId];
1011
- if (!scopeOverrides) return null;
1012
- const parts = resourcePath.split(".");
1013
- let currentPath = "";
1014
- let bestOverride = null;
1015
- for (const part of parts) {
1016
- currentPath = currentPath ? `${currentPath}.${part}` : part;
1017
- if (scopeOverrides[currentPath] !== void 0) {
1018
- bestOverride = scopeOverrides[currentPath];
1019
- }
1020
- }
1021
- return bestOverride;
1022
- }
1023
- async function assertTenantBoundary(db, session, targets) {
1024
- if (!session.companyId) {
1025
- throw ErrorFactory.internal(MOD.ADMIN, "Missing requester company context.");
1026
- }
1027
- if (targets.targetUserId) {
1028
- const targetUserAssignments = await db.UserRoleAssignment.filter({
1029
- userId: targets.targetUserId,
1030
- companyId: session.companyId
1031
- });
1032
- if (targetUserAssignments.length === 0) {
1033
- console.error(`[SECURITY BREACH] User tried to modify targetUserId ${targets.targetUserId}`);
1034
- throw ErrorFactory.forbidden(MOD.ADMIN, ACT.EDIT, "Invalid target user.");
1035
- }
1036
- }
1037
- if (targets.authScopeId) {
1038
- const matchedScope = session.availableScopes?.find(
1039
- (scope) => scope.authScopeId === targets.authScopeId
1040
- );
1041
- if (!matchedScope) {
1042
- console.error(`[SECURITY BREACH] Scope ${targets.authScopeId} not found in user's permitted list.`);
1043
- throw ErrorFactory.forbidden(MOD.ADMIN, ACT.EDIT, "Tenant boundary violation.");
1044
- }
1045
- if (targets.expectedScopeType && matchedScope.type !== targets.expectedScopeType) {
1046
- console.error(`[VALIDATION ERROR] Expected type ${targets.expectedScopeType} but got ${matchedScope.type}`);
1047
- throw ErrorFactory.forbidden(MOD.ADMIN, ACT.EDIT, "Invalid authorization scope level.");
1048
- }
1049
- }
1050
- return true;
1051
- }
1052
- async function verifyAndExtractSession(token, secret) {
1053
- if (!token) {
1054
- throw ErrorFactory.unauthorized(MOD.SESSION, "UNAUTHORIZED: No secure session token provided.");
1055
- }
1056
- try {
1057
- const secretKey = new TextEncoder().encode(secret);
1058
- const { payload } = await (0, import_jose.jwtVerify)(token, secretKey);
1059
- return payload;
1060
- } catch (error) {
1061
- throw ErrorFactory.unauthorized(MOD.SESSION, "UNAUTHORIZED: No secure session token provided.");
1062
- }
1063
- }
1064
759
  var DocumentType = /* @__PURE__ */ ((DocumentType2) => {
1065
760
  DocumentType2["SPRAY_RECORD"] = "SPRAY_RECORD";
1066
761
  DocumentType2["FERTIGATION_RECORD"] = "FERTIGATION_RECORD";
@@ -1097,6 +792,510 @@ var DocumentType = /* @__PURE__ */ ((DocumentType2) => {
1097
792
  DocumentType2["SENSITIVE_IDENTITY"] = "SENSITIVE_IDENTITY";
1098
793
  return DocumentType2;
1099
794
  })(DocumentType || {});
795
+ var DocumentCategory = /* @__PURE__ */ ((DocumentCategory2) => {
796
+ DocumentCategory2["AGRONOMY_TESTING"] = "Agronomy & Testing";
797
+ DocumentCategory2["FARM_OPERATIONS"] = "Farm Operations";
798
+ DocumentCategory2["COMPLIANCE_QA"] = "Compliance & Quality";
799
+ DocumentCategory2["INVENTORY_LOG"] = "Inventory & Logistics";
800
+ DocumentCategory2["ASSETS_MAINT"] = "Assets & Maintenance";
801
+ DocumentCategory2["HR_LEGAL_SAFETY"] = "HR, Legal & Safety";
802
+ DocumentCategory2["FINANCE_ADMIN"] = "Finance & Admin";
803
+ return DocumentCategory2;
804
+ })(DocumentCategory || {});
805
+ var DOCUMENT_DISPLAY_INFO = {
806
+ // --- AGRONOMY & TESTING ---
807
+ ["SOIL_TEST" /* SOIL_TEST */]: {
808
+ label: "Soil Analysis",
809
+ description: "Detailed lab results for soil nutrients, pH, and health.",
810
+ category: "Agronomy & Testing" /* AGRONOMY_TESTING */
811
+ },
812
+ ["LEAF_TEST" /* LEAF_TEST */]: {
813
+ label: "Leaf & Tissue Test",
814
+ description: "Nutrient analysis of plant tissue samples.",
815
+ category: "Agronomy & Testing" /* AGRONOMY_TESTING */
816
+ },
817
+ ["WATER_TEST" /* WATER_TEST */]: {
818
+ label: "Water Quality Test",
819
+ description: "Testing for irrigation suitability and microbial levels.",
820
+ category: "Agronomy & Testing" /* AGRONOMY_TESTING */
821
+ },
822
+ ["MRL_TESTING" /* MRL_TESTING */]: {
823
+ label: "MRL Residue Analysis",
824
+ description: "Maximum Residue Limit reports for chemical compliance.",
825
+ category: "Agronomy & Testing" /* AGRONOMY_TESTING */
826
+ },
827
+ ["HEAVY_METAL" /* HEAVY_METAL */]: {
828
+ label: "Heavy Metal Analysis",
829
+ description: "Testing for lead, cadmium, and other metal contaminants.",
830
+ category: "Agronomy & Testing" /* AGRONOMY_TESTING */
831
+ },
832
+ ["MICROBIAL" /* MICROBIAL */]: {
833
+ label: "Microbial Testing",
834
+ description: "Pathogen detection reports (e.g., E. coli, Salmonella).",
835
+ category: "Agronomy & Testing" /* AGRONOMY_TESTING */
836
+ },
837
+ // --- FARM OPERATIONS ---
838
+ ["SPRAY_RECORD" /* SPRAY_RECORD */]: {
839
+ label: "Spray Operations",
840
+ description: "Chemical application logs and weather conditions.",
841
+ category: "Farm Operations" /* FARM_OPERATIONS */
842
+ },
843
+ ["FERTIGATION_RECORD" /* FERTIGATION_RECORD */]: {
844
+ label: "Fertigation Logs",
845
+ description: "Records of liquid fertilizer applied via irrigation.",
846
+ category: "Farm Operations" /* FARM_OPERATIONS */
847
+ },
848
+ ["FERTILIZER_RECORD" /* FERTILIZER_RECORD */]: {
849
+ label: "Fertilizer Records",
850
+ description: "Manual granular or bulk fertilizer application logs.",
851
+ category: "Farm Operations" /* FARM_OPERATIONS */
852
+ },
853
+ ["HARVEST_LOG" /* HARVEST_LOG */]: {
854
+ label: "Harvest Manifests",
855
+ description: "Daily picking volumes and block yield data.",
856
+ category: "Farm Operations" /* FARM_OPERATIONS */
857
+ },
858
+ ["PACKHOUSE_INSPECTION" /* PACKHOUSE_INSPECTION */]: {
859
+ label: "Packhouse Inspections",
860
+ description: "Quality and hygiene checks conducted in the packhouse.",
861
+ category: "Farm Operations" /* FARM_OPERATIONS */
862
+ },
863
+ ["MAPPING_TRAFIC_MANAGEMENT" /* MAPPING_TRAFIC_MANAGEMENT */]: {
864
+ label: "Traffic Management",
865
+ description: "Maps and rules for vehicle and heavy machinery movement.",
866
+ category: "Farm Operations" /* FARM_OPERATIONS */
867
+ },
868
+ // --- COMPLIANCE & QUALITY ---
869
+ ["QA" /* QA */]: {
870
+ label: "Quality Assurance",
871
+ description: "General product quality checks and grading standards.",
872
+ category: "Compliance & Quality" /* COMPLIANCE_QA */
873
+ },
874
+ ["PEST" /* PEST */]: {
875
+ label: "Pest & Disease Monitoring",
876
+ description: "Scouting reports and pest pressure assessments.",
877
+ category: "Compliance & Quality" /* COMPLIANCE_QA */
878
+ },
879
+ ["AUDIT_REPORT" /* AUDIT_REPORT */]: {
880
+ label: "External Audit Reports",
881
+ description: "Final results from Freshcare, GlobalGAP, or Organic audits.",
882
+ category: "Compliance & Quality" /* COMPLIANCE_QA */
883
+ },
884
+ ["RISK_ASSESSMENTS" /* RISK_ASSESSMENTS */]: {
885
+ label: "Risk Assessments",
886
+ description: "Operational hazard identification and safety mitigations.",
887
+ category: "Compliance & Quality" /* COMPLIANCE_QA */
888
+ },
889
+ // --- ASSETS & MAINTENANCE ---
890
+ ["SERVICING_MAINTENANCE" /* SERVICING_MAINTENANCE */]: {
891
+ label: "Equipment Maintenance",
892
+ description: "Service history and repair logs for farm machinery.",
893
+ category: "Assets & Maintenance" /* ASSETS_MAINT */
894
+ },
895
+ ["EQUIPMENT_CALIBRATION_RECORD" /* EQUIPMENT_CALIBRATION_RECORD */]: {
896
+ label: "Calibration Records",
897
+ description: "Accuracy checks for sprayers, scales, and moisture probes.",
898
+ category: "Assets & Maintenance" /* ASSETS_MAINT */
899
+ },
900
+ ["CLEANING" /* CLEANING */]: {
901
+ label: "Sanitation Logs",
902
+ description: "Daily/weekly cleaning schedules for tools and facilities.",
903
+ category: "Assets & Maintenance" /* ASSETS_MAINT */
904
+ },
905
+ ["MAPPING_FARM_MAPS" /* MAPPING_FARM_MAPS */]: {
906
+ label: "Farm Infrastructure Maps",
907
+ description: "Layouts of blocks, irrigation, and fixed assets.",
908
+ category: "Assets & Maintenance" /* ASSETS_MAINT */
909
+ },
910
+ // --- INVENTORY & LOGISTICS ---
911
+ ["INVENTORY_CHEMICALS" /* INVENTORY_CHEMICALS */]: {
912
+ label: "Chemical Inventory",
913
+ description: "Manifests for stored pesticides and fertilizers.",
914
+ category: "Inventory & Logistics" /* INVENTORY_LOG */
915
+ },
916
+ ["INVENTORY_BOX_CARTON" /* INVENTORY_BOX_CARTON */]: {
917
+ label: "Packaging Inventory",
918
+ description: "Stock levels for cartons, bins, and packaging materials.",
919
+ category: "Inventory & Logistics" /* INVENTORY_LOG */
920
+ },
921
+ ["INVENTORY_CONSUMABLES" /* INVENTORY_CONSUMABLES */]: {
922
+ label: "General Consumables",
923
+ description: "Stock tracking for fuel, PPE, and workshop supplies.",
924
+ category: "Inventory & Logistics" /* INVENTORY_LOG */
925
+ },
926
+ ["STOCKTAKE" /* STOCKTAKE */]: {
927
+ label: "Physical Stocktake",
928
+ description: "Periodic audits of physical vs. recorded stock levels.",
929
+ category: "Inventory & Logistics" /* INVENTORY_LOG */
930
+ },
931
+ ["STOCKTAKE_MSDS" /* STOCKTAKE_MSDS */]: {
932
+ label: "MSDS / Safety Data",
933
+ description: "Material Safety Data Sheets for stored chemicals.",
934
+ category: "Inventory & Logistics" /* INVENTORY_LOG */
935
+ },
936
+ // --- HR, LEGAL & SAFETY ---
937
+ ["TRAINING_RECORDS" /* TRAINING_RECORDS */]: {
938
+ label: "Staff Inductions",
939
+ description: "General staff onboarding and safety training logs.",
940
+ category: "HR, Legal & Safety" /* HR_LEGAL_SAFETY */
941
+ },
942
+ ["TRAINING_CERTIFICATE" /* TRAINING_CERTIFICATE */]: {
943
+ label: "Training Certificates",
944
+ description: "External licenses, ChemCert, and first aid tickets.",
945
+ category: "HR, Legal & Safety" /* HR_LEGAL_SAFETY */
946
+ },
947
+ ["SOPS" /* SOPS */]: {
948
+ label: "Standard Procedures (SOPs)",
949
+ description: "Formalized instructions for farm and packhouse tasks.",
950
+ category: "HR, Legal & Safety" /* HR_LEGAL_SAFETY */
951
+ },
952
+ ["LEGAL_CONTRACT" /* LEGAL_CONTRACT */]: {
953
+ label: "Legal Contracts",
954
+ description: "Lease agreements, supply contracts, and employment terms.",
955
+ category: "HR, Legal & Safety" /* HR_LEGAL_SAFETY */
956
+ },
957
+ ["INCIDENT_REPORT" /* INCIDENT_REPORT */]: {
958
+ label: "Incident Reports",
959
+ description: "Logs of injuries, near-misses, or property damage.",
960
+ category: "HR, Legal & Safety" /* HR_LEGAL_SAFETY */
961
+ },
962
+ ["SENSITIVE_IDENTITY" /* SENSITIVE_IDENTITY */]: {
963
+ label: "Identity & Visas",
964
+ description: "Sensitive data: Passports, ID cards, and work permits.",
965
+ category: "HR, Legal & Safety" /* HR_LEGAL_SAFETY */
966
+ },
967
+ ["MAPPING_EMERGENCY" /* MAPPING_EMERGENCY */]: {
968
+ label: "Emergency Response Maps",
969
+ description: "Evacuation routes and emergency assembly points.",
970
+ category: "HR, Legal & Safety" /* HR_LEGAL_SAFETY */
971
+ },
972
+ // --- FINANCE & ADMIN ---
973
+ ["INVOICE" /* INVOICE */]: {
974
+ label: "Supplier Invoices",
975
+ description: "Billing records for inputs, utilities, and services.",
976
+ category: "Finance & Admin" /* FINANCE_ADMIN */
977
+ }
978
+ };
979
+ var CATEGORY_TABS = [
980
+ "All",
981
+ ...Object.values(DocumentCategory)
982
+ ];
983
+ var DOCUMENT_MENU_MAP = {
984
+ ["SPRAY_RECORD" /* SPRAY_RECORD */]: [RESOURCE_PATHS.farmManagement],
985
+ ["FERTIGATION_RECORD" /* FERTIGATION_RECORD */]: [RESOURCE_PATHS.farmManagement],
986
+ ["FERTILIZER_RECORD" /* FERTILIZER_RECORD */]: [RESOURCE_PATHS.farmManagement],
987
+ ["QA" /* QA */]: [RESOURCE_PATHS.safetyAuditing],
988
+ ["CLEANING" /* CLEANING */]: [RESOURCE_PATHS.safetyCleaning],
989
+ ["PEST" /* PEST */]: [RESOURCE_PATHS.farmManagement],
990
+ ["EQUIPMENT_CALIBRATION_RECORD" /* EQUIPMENT_CALIBRATION_RECORD */]: [RESOURCE_PATHS.equipCalibration],
991
+ ["SERVICING_MAINTENANCE" /* SERVICING_MAINTENANCE */]: [RESOURCE_PATHS.equipMaintenance],
992
+ ["INVENTORY_CONSUMABLES" /* INVENTORY_CONSUMABLES */]: [RESOURCE_PATHS.packhouse],
993
+ ["INVENTORY_BOX_CARTON" /* INVENTORY_BOX_CARTON */]: [RESOURCE_PATHS.packhouse],
994
+ ["INVENTORY_CHEMICALS" /* INVENTORY_CHEMICALS */]: [RESOURCE_PATHS.packhouse, RESOURCE_PATHS.farmManagement],
995
+ ["STOCKTAKE" /* STOCKTAKE */]: [RESOURCE_PATHS.packhouse],
996
+ ["STOCKTAKE_MSDS" /* STOCKTAKE_MSDS */]: [RESOURCE_PATHS.safetyWhs],
997
+ ["MAPPING_FARM_MAPS" /* MAPPING_FARM_MAPS */]: [RESOURCE_PATHS.adminBlueprintsSites],
998
+ ["MAPPING_TRAFIC_MANAGEMENT" /* MAPPING_TRAFIC_MANAGEMENT */]: [RESOURCE_PATHS.adminBlueprintsSites],
999
+ ["MAPPING_EMERGENCY" /* MAPPING_EMERGENCY */]: [RESOURCE_PATHS.adminBlueprintsSites],
1000
+ ["INCIDENT_REPORT" /* INCIDENT_REPORT */]: [RESOURCE_PATHS.safetyWhs],
1001
+ ["RISK_ASSESSMENTS" /* RISK_ASSESSMENTS */]: [RESOURCE_PATHS.safetyWhs],
1002
+ ["TRAINING_RECORDS" /* TRAINING_RECORDS */]: [RESOURCE_PATHS.teamTraining],
1003
+ ["TRAINING_CERTIFICATE" /* TRAINING_CERTIFICATE */]: [RESOURCE_PATHS.teamTraining],
1004
+ ["SOPS" /* SOPS */]: [RESOURCE_PATHS.documentHubTemplates],
1005
+ ["SOIL_TEST" /* SOIL_TEST */]: [RESOURCE_PATHS.farmManagement],
1006
+ ["LEAF_TEST" /* LEAF_TEST */]: [RESOURCE_PATHS.farmManagement],
1007
+ ["WATER_TEST" /* WATER_TEST */]: [RESOURCE_PATHS.farmManagement, RESOURCE_PATHS.safetyFood],
1008
+ ["MRL_TESTING" /* MRL_TESTING */]: [RESOURCE_PATHS.safetyFood],
1009
+ ["HEAVY_METAL" /* HEAVY_METAL */]: [RESOURCE_PATHS.safetyFood],
1010
+ ["MICROBIAL" /* MICROBIAL */]: [RESOURCE_PATHS.safetyFood],
1011
+ ["HARVEST_LOG" /* HARVEST_LOG */]: [RESOURCE_PATHS.farmManagement],
1012
+ ["PACKHOUSE_INSPECTION" /* PACKHOUSE_INSPECTION */]: [RESOURCE_PATHS.packhouse],
1013
+ ["INVOICE" /* INVOICE */]: [RESOURCE_PATHS.documentHub],
1014
+ ["LEGAL_CONTRACT" /* LEGAL_CONTRACT */]: [RESOURCE_PATHS.documentHub],
1015
+ ["AUDIT_REPORT" /* AUDIT_REPORT */]: [RESOURCE_PATHS.safetyAuditing, RESOURCE_PATHS.dashboard],
1016
+ ["SENSITIVE_IDENTITY" /* SENSITIVE_IDENTITY */]: [RESOURCE_PATHS.adminUserRoster]
1017
+ };
1018
+
1019
+ // src/index.ts
1020
+ var AppError = class extends Error {
1021
+ status;
1022
+ appCode;
1023
+ isOperational;
1024
+ constructor(status, mod, cat, act, message) {
1025
+ super(message);
1026
+ this.status = status;
1027
+ this.appCode = `${mod}-${status}-${cat}${act}`;
1028
+ this.isOperational = true;
1029
+ Object.setPrototypeOf(this, new.target.prototype);
1030
+ }
1031
+ };
1032
+ var ErrorFactory = {
1033
+ unauthorized: (mod, msg = "Authentication required") => new AppError(401, mod, CAT.PERMISSION, ACT.GENERIC, msg),
1034
+ forbidden: (mod, act, msg = "Access denied") => new AppError(403, mod, CAT.PERMISSION, act, msg),
1035
+ badRequest: (mod, act, msg = "Bad request") => new AppError(400, mod, CAT.VALIDATION, act, msg),
1036
+ notFound: (mod, act = ACT.GENERIC, msg = "Record not found") => new AppError(404, mod, CAT.VALIDATION, act, msg),
1037
+ conflict: (mod, act, msg = "Record already exists") => new AppError(409, mod, CAT.INTEGRITY, act, msg),
1038
+ integrity: (mod, act = ACT.GENERIC, msg = "Data integrity violation") => new AppError(409, mod, CAT.INTEGRITY, act, msg),
1039
+ subscription: (mod, msg = "Module locked or subscription required") => new AppError(403, mod, CAT.SUBSCRIPTION, ACT.GENERIC, msg),
1040
+ internal: (mod, msg = "Internal server error") => new AppError(500, mod, CAT.INTEGRITY, ACT.GENERIC, msg)
1041
+ };
1042
+ var handleAppErrorResponse = (error, mod = MOD.ADMIN) => {
1043
+ if (error instanceof AppError && error.isOperational) {
1044
+ return Response.json(
1045
+ { error: { appCode: error.appCode, message: error.message } },
1046
+ { status: error.status }
1047
+ );
1048
+ }
1049
+ const e = error;
1050
+ console.error(`[${mod}] UNEXPECTED ERROR:`, e?.message);
1051
+ console.error(`[${mod}] STACK:`, e?.stack);
1052
+ return Response.json(
1053
+ { error: { appCode: `${mod}-500-000`, message: "An unexpected server error occurred. Please try again." } },
1054
+ { status: 500 }
1055
+ );
1056
+ };
1057
+ var FALLBACK = {
1058
+ title: "Something Went Wrong",
1059
+ text: "An unexpected error occurred. Please try again or contact your administrator."
1060
+ };
1061
+ var resolveAppError = (appCode) => {
1062
+ if (!appCode || typeof appCode !== "string") {
1063
+ return { ...FALLBACK, module: "UNK", moduleLabel: "Unknown", status: 500, catAct: "000", isSubscriptionIssue: false, isPermissionIssue: false };
1064
+ }
1065
+ const parts = appCode.split("-");
1066
+ if (parts.length !== 3) {
1067
+ return { ...FALLBACK, module: "UNK", moduleLabel: "Unknown", status: 500, catAct: "000", isSubscriptionIssue: false, isPermissionIssue: false };
1068
+ }
1069
+ const [mod, status, catAct] = parts;
1070
+ const details = ERROR_DICTIONARY[catAct] || FALLBACK;
1071
+ return {
1072
+ title: details.title,
1073
+ text: details.text,
1074
+ module: mod,
1075
+ moduleLabel: MODULE_LABELS[mod] || mod,
1076
+ status: parseInt(status, 10),
1077
+ catAct,
1078
+ isSubscriptionIssue: catAct.startsWith("1"),
1079
+ isPermissionIssue: catAct.startsWith("2")
1080
+ };
1081
+ };
1082
+ var extractAppCode = (error) => {
1083
+ const e = error;
1084
+ return e?.response?.data?.error?.appCode ?? e?.data?.error?.appCode ?? null;
1085
+ };
1086
+ var resolveError = (error) => {
1087
+ const appCode = extractAppCode(error);
1088
+ if (appCode) return resolveAppError(appCode);
1089
+ const e = error;
1090
+ return { ...FALLBACK, module: "UNK", moduleLabel: "Unknown", status: e?.status || 500, catAct: "000", isSubscriptionIssue: false, isPermissionIssue: false };
1091
+ };
1092
+ function generateCanonicalId() {
1093
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
1094
+ return crypto.randomUUID();
1095
+ }
1096
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
1097
+ const r = Math.random() * 16 | 0;
1098
+ return (c === "x" ? r : r & 3 | 8).toString(16);
1099
+ });
1100
+ }
1101
+ function generateInfrastructureFields(activeScope, availableScopes) {
1102
+ if (!activeScope || !availableScopes?.length) {
1103
+ throw ErrorFactory.unauthorized("[generateInfrastructureFields] Missing scope context.");
1104
+ }
1105
+ let companyId = null;
1106
+ let legalEntityId = null;
1107
+ let facilityId = null;
1108
+ let pointer = activeScope;
1109
+ while (pointer) {
1110
+ if (pointer.type === "company") companyId = pointer.base44Id;
1111
+ if (pointer.type === "legalEntity") legalEntityId = pointer.base44Id;
1112
+ if (pointer.type === "facility") facilityId = pointer.base44Id;
1113
+ const parentId = pointer.parentId ?? null;
1114
+ pointer = parentId ? availableScopes.find((s) => s.base44Id === parentId) || null : null;
1115
+ }
1116
+ if (!companyId) {
1117
+ throw ErrorFactory.unauthorized("[generateInfrastructureFields] Could not resolve companyId from scope tree.");
1118
+ }
1119
+ return {
1120
+ canonicalId: crypto.randomUUID(),
1121
+ companyId,
1122
+ legalEntityId,
1123
+ facilityId,
1124
+ authScopeId: activeScope.authScopeId
1125
+ };
1126
+ }
1127
+ function buildRlsFilter(session, extra = {}) {
1128
+ return { ...extra, authScopeId: { $in: session.readScopes || [] } };
1129
+ }
1130
+ function canRead(session, authScopeId) {
1131
+ return session.readScopes?.includes(authScopeId) ?? false;
1132
+ }
1133
+ function canWrite(session, authScopeId, resourcePath) {
1134
+ const override = session.resourceOverrides?.[authScopeId]?.[resourcePath];
1135
+ if (override === "WRITE") return true;
1136
+ if (override === "NONE" || override === "READ") return false;
1137
+ return session.writeScopes?.includes(authScopeId) ?? false;
1138
+ }
1139
+ function assertCanWrite(session, authScopeId, resourcePath) {
1140
+ const override = session.resourceOverrides?.[authScopeId]?.[resourcePath];
1141
+ if (override === "WRITE") return;
1142
+ if (override === "NONE" || override === "READ") {
1143
+ throw new AppError(
1144
+ 403,
1145
+ MOD.SESSION,
1146
+ CAT.PERMISSION,
1147
+ ACT.GENERIC,
1148
+ `You do not have write access to "${resourcePath}" in this scope.`
1149
+ );
1150
+ }
1151
+ if (session.writeScopes?.includes(authScopeId)) return;
1152
+ throw new AppError(
1153
+ 403,
1154
+ MOD.SESSION,
1155
+ CAT.PERMISSION,
1156
+ ACT.GENERIC,
1157
+ "You do not have permission to modify records in this scope."
1158
+ );
1159
+ }
1160
+ function resolveAccess(session, activeScopeId, tabConfig) {
1161
+ const resourcePath = tabConfig?.resourceId;
1162
+ const overrides = session.resourceOverrides?.[activeScopeId] ?? {};
1163
+ if (resourcePath) {
1164
+ const segments = resourcePath.split(".");
1165
+ for (let len = segments.length; len >= 1; len--) {
1166
+ const path = segments.slice(0, len).join(".");
1167
+ const override = overrides[path];
1168
+ if (override === "NONE" || override === "READ" || override === "WRITE") return override;
1169
+ }
1170
+ }
1171
+ const allowedRoles = tabConfig?.allowedRoles ?? [];
1172
+ const requiredPrivileges = tabConfig?.requiredPrivileges ?? [];
1173
+ const hasRestrictions = allowedRoles.length > 0 || requiredPrivileges.length > 0;
1174
+ if (hasRestrictions) {
1175
+ const role = session?.role ?? "";
1176
+ const privileges = session?.privileges ?? [];
1177
+ const passesRole = allowedRoles.length > 0 && allowedRoles.includes(role);
1178
+ const passesPrivilege = requiredPrivileges.length > 0 && requiredPrivileges.some((p) => privileges.includes(p));
1179
+ return passesRole || passesPrivilege ? "WRITE" : "NONE";
1180
+ }
1181
+ return "READ";
1182
+ }
1183
+ function resolveMenuVisibility(session, authScopeId, resourcePath) {
1184
+ const override = session.resourceOverrides?.[authScopeId]?.[resourcePath];
1185
+ if (override === "NONE") return "hidden";
1186
+ if (override === "READ") return "read_only";
1187
+ if (override === "WRITE") return "active";
1188
+ if (session.writeScopes?.includes(authScopeId)) return "active";
1189
+ if (session.readScopes?.includes(authScopeId)) return "read_only";
1190
+ return "hidden";
1191
+ }
1192
+ function isTabVisible(session, activeScopeId, tabConfig) {
1193
+ return resolveAccess(session, activeScopeId, tabConfig) !== "NONE";
1194
+ }
1195
+ function isTabWritable(session, activeScopeId, tabConfig) {
1196
+ return resolveAccess(session, activeScopeId, tabConfig) === "WRITE";
1197
+ }
1198
+ function evaluateBaseAccess(resourcePath, session, requirements = {}) {
1199
+ if (!session?.role) return "NONE";
1200
+ if (session.role === UserRole.OWNER) return "WRITE";
1201
+ const requiredModules = RESOURCE_MODULE_MAP[resourcePath] || [];
1202
+ if (requiredModules.length > 0) {
1203
+ const hasModule = requiredModules.some((m) => session.enabledModules?.includes(m));
1204
+ if (!hasModule) return "NONE";
1205
+ }
1206
+ const topLevel = resourcePath.split(".")[0];
1207
+ const defaultRoles = ROLE_SECTIONS_BY_KEY[topLevel] || [];
1208
+ const allowedRoles = requirements.allowedRoles?.length ? requirements.allowedRoles : defaultRoles;
1209
+ if (!allowedRoles.includes(session.role)) return "NONE";
1210
+ if (requirements.requiredPrivileges?.length) {
1211
+ const hasPrivilege = requirements.requiredPrivileges.some((p) => session.privileges?.includes(p));
1212
+ if (!hasPrivilege) return "NONE";
1213
+ }
1214
+ return session.role === UserRole.MANAGER ? "WRITE" : "READ";
1215
+ }
1216
+ function resolveEffectiveAccess(base, override) {
1217
+ return override === void 0 || override === null ? base : override;
1218
+ }
1219
+ function findSpecificOverride(session, activeScopeId, resourcePath) {
1220
+ const scopeOverrides = session.resourceOverrides?.[activeScopeId];
1221
+ if (!scopeOverrides) return null;
1222
+ const parts = resourcePath.split(".");
1223
+ let currentPath = "";
1224
+ let bestOverride = null;
1225
+ for (const part of parts) {
1226
+ currentPath = currentPath ? `${currentPath}.${part}` : part;
1227
+ if (scopeOverrides[currentPath] !== void 0) {
1228
+ bestOverride = scopeOverrides[currentPath];
1229
+ }
1230
+ }
1231
+ return bestOverride;
1232
+ }
1233
+ async function assertTenantBoundary(db, session, targets) {
1234
+ if (!session.companyId) {
1235
+ throw ErrorFactory.internal(MOD.ADMIN, "Missing requester company context.");
1236
+ }
1237
+ if (targets.targetUserId) {
1238
+ const targetUserAssignments = await db.UserRoleAssignment.filter({
1239
+ userId: targets.targetUserId,
1240
+ companyId: session.companyId
1241
+ });
1242
+ if (targetUserAssignments.length === 0) {
1243
+ console.error(`[SECURITY BREACH] User tried to modify targetUserId ${targets.targetUserId}`);
1244
+ throw ErrorFactory.forbidden(MOD.ADMIN, ACT.EDIT, "Invalid target user.");
1245
+ }
1246
+ }
1247
+ if (targets.authScopeId) {
1248
+ const matchedScope = session.availableScopes?.find(
1249
+ (scope) => scope.authScopeId === targets.authScopeId
1250
+ );
1251
+ if (!matchedScope) {
1252
+ console.error(`[SECURITY BREACH] Scope ${targets.authScopeId} not found in user's permitted list.`);
1253
+ throw ErrorFactory.forbidden(MOD.ADMIN, ACT.EDIT, "Tenant boundary violation.");
1254
+ }
1255
+ if (targets.expectedScopeType && matchedScope.type !== targets.expectedScopeType) {
1256
+ console.error(`[VALIDATION ERROR] Expected type ${targets.expectedScopeType} but got ${matchedScope.type}`);
1257
+ throw ErrorFactory.forbidden(MOD.ADMIN, ACT.EDIT, "Invalid authorization scope level.");
1258
+ }
1259
+ }
1260
+ return true;
1261
+ }
1262
+ async function verifyAndExtractSession(token, secret) {
1263
+ if (!token) {
1264
+ throw ErrorFactory.unauthorized(MOD.SESSION, "UNAUTHORIZED: No secure session token provided.");
1265
+ }
1266
+ try {
1267
+ const secretKey = new TextEncoder().encode(secret);
1268
+ const { payload } = await (0, import_jose.jwtVerify)(token, secretKey);
1269
+ return payload;
1270
+ } catch (error) {
1271
+ throw ErrorFactory.unauthorized(MOD.SESSION, "UNAUTHORIZED: No secure session token provided.");
1272
+ }
1273
+ }
1274
+ function getFormMeta(componentId) {
1275
+ return FORM_REGISTRY[componentId] ?? null;
1276
+ }
1277
+ function getFormsGroupedByModule() {
1278
+ const groups = {};
1279
+ for (const [id, meta] of Object.entries(FORM_REGISTRY)) {
1280
+ if (!groups[meta.module]) groups[meta.module] = [];
1281
+ groups[meta.module].push({ id, ...meta });
1282
+ }
1283
+ return groups;
1284
+ }
1285
+ var getTaskTypeOptions = () => Object.entries(TASK_TYPE_REGISTRY).map(([value, config]) => ({
1286
+ value,
1287
+ label: config.label,
1288
+ description: config.description,
1289
+ mimeTypes: config.mimeTypes,
1290
+ icon: config.icon
1291
+ }));
1292
+ var getAcceptedMimeTypes = (taskType) => {
1293
+ const config = TASK_TYPE_REGISTRY[taskType];
1294
+ return config ? config.mimeTypes.join(",") : "*/*";
1295
+ };
1296
+ var getApproveAction = (taskType) => {
1297
+ return TASK_TYPE_REGISTRY[taskType]?.approveAction ?? null;
1298
+ };
1100
1299
  function generateDocumentPath(params) {
1101
1300
  const sanitizedName = params.siteName.replace(/[^a-z0-9]/gi, "_");
1102
1301
  if (params.isStatic) {
@@ -1146,8 +1345,12 @@ function calculateFileMetadataMatch(criteria, fileMetadata, auditContext) {
1146
1345
  AuditStatus,
1147
1346
  AuditType,
1148
1347
  CAT,
1348
+ CATEGORY_TABS,
1149
1349
  Converter,
1150
1350
  CropCycleStatus,
1351
+ DOCUMENT_DISPLAY_INFO,
1352
+ DOCUMENT_MENU_MAP,
1353
+ DocumentCategory,
1151
1354
  DocumentType,
1152
1355
  ERROR_DICTIONARY,
1153
1356
  EVERYONE,