@litusarchieve18/agricore-utils 1.0.5 → 1.0.7
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/README.md +5 -1
- package/dist/index.d.mts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +76 -16
- package/dist/index.mjs +75 -16
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -117,7 +117,11 @@ Run the publish command:
|
|
|
117
117
|
Bash
|
|
118
118
|
npm publish --access public
|
|
119
119
|
📝 Version History
|
|
120
|
-
v1.0.
|
|
120
|
+
v1.0.5 — add RESOURCE_MODULE_MAP
|
|
121
|
+
|
|
122
|
+
v1.0.6 — adding more logic
|
|
123
|
+
|
|
124
|
+
v1.0.5 — refactor the code and edit readme
|
|
121
125
|
|
|
122
126
|
v1.0.4 — add generateInfrastructureFields, security access control and multi tenant boundary
|
|
123
127
|
|
package/dist/index.d.mts
CHANGED
|
@@ -487,6 +487,7 @@ declare const RESOURCE_PATHS: {
|
|
|
487
487
|
teamStaff: string;
|
|
488
488
|
teamTraining: string;
|
|
489
489
|
};
|
|
490
|
+
declare const RESOURCE_MODULE_MAP: Record<string, string[]>;
|
|
490
491
|
declare const ACCESS_RANK: Record<AccessLevelType, number>;
|
|
491
492
|
declare const ROLE_SECTIONS_BY_KEY: Record<string, UserRoleType[]>;
|
|
492
493
|
declare function evaluateBaseAccess(resourcePath: string, session: {
|
|
@@ -494,7 +495,6 @@ declare function evaluateBaseAccess(resourcePath: string, session: {
|
|
|
494
495
|
privileges?: string[];
|
|
495
496
|
enabledModules?: string[];
|
|
496
497
|
}, requirements?: {
|
|
497
|
-
module?: string;
|
|
498
498
|
allowedRoles?: UserRoleType[];
|
|
499
499
|
requiredPrivileges?: string[];
|
|
500
500
|
}): AccessLevelType;
|
|
@@ -506,7 +506,8 @@ declare function evaluateBaseAccess(resourcePath: string, session: {
|
|
|
506
506
|
declare function assertTenantBoundary(db: any, requesterCompanyId: string, targets: {
|
|
507
507
|
targetUserId?: string;
|
|
508
508
|
authScopeId?: string;
|
|
509
|
+
expectedScopeType?: 'company' | 'legalEntity' | 'facility';
|
|
509
510
|
}): Promise<boolean>;
|
|
510
|
-
declare function resolveEffectiveAccess(base: AccessLevelType, override?: AccessLevelType): AccessLevelType;
|
|
511
|
+
declare function resolveEffectiveAccess(base: AccessLevelType, override?: AccessLevelType | null): AccessLevelType;
|
|
511
512
|
|
|
512
|
-
export { ACCESS_RANK, ACT, AccessLevel, type AccessLevelType, type AgriCoreSession, AgriLogger, AppError, ApprovalStatus, ApprovalType, AuditStatus, AuditType, type AuthScopeFields, type AvailableScope, CAT, type CompanyConfig, Converter, CropCycleStatus, ERROR_DICTIONARY, EmitterType, EnabledModule, ErrorFactory, FORM_REGISTRY, FacilityType, type FormMeta, HarvestMethod, type InfrastructureFields, LinkedStatus, MOD, MODULE_LABELS, MicroclimateZone, MimeType, type ModCode, NettingType, NotificationMode, OrderStatus, type PermissionLevel, PhysicalState, PlantingMethod, RESOURCE_PATHS, ROLE_SECTIONS_BY_KEY, RelationshipType, type ResolvedError, type ResourceOverrides, RowOrientation, SENTINEL_UUID, type ScopeType, SoilTexture, TASK_TYPE_REGISTRY, type TabConfig, TargetEntityType, TaskStatus, TaskType, type TaskTypeConfig, TransactionType, TrellisType, UserPrivilege, UserRole, type UserRoleType, Validator, VigorRating, WaterSource, assertCanWrite, assertTenantBoundary, buildRlsFilter, canRead, canWrite, evaluateBaseAccess, extractAppCode, generateCanonicalId, generateInfrastructureFields, getAcceptedMimeTypes, getApproveAction, getFormMeta, getFormsGroupedByModule, getTaskTypeOptions, handleAppErrorResponse, isTabVisible, isTabWritable, resolveAccess, resolveAppError, resolveEffectiveAccess, resolveError, resolveMenuVisibility, withAgriLogging };
|
|
513
|
+
export { ACCESS_RANK, ACT, AccessLevel, type AccessLevelType, type AgriCoreSession, AgriLogger, AppError, ApprovalStatus, ApprovalType, AuditStatus, AuditType, type AuthScopeFields, type AvailableScope, CAT, type CompanyConfig, Converter, CropCycleStatus, ERROR_DICTIONARY, EmitterType, EnabledModule, ErrorFactory, FORM_REGISTRY, FacilityType, type FormMeta, HarvestMethod, type InfrastructureFields, LinkedStatus, MOD, MODULE_LABELS, MicroclimateZone, MimeType, type ModCode, NettingType, NotificationMode, OrderStatus, type PermissionLevel, PhysicalState, PlantingMethod, RESOURCE_MODULE_MAP, RESOURCE_PATHS, ROLE_SECTIONS_BY_KEY, RelationshipType, type ResolvedError, type ResourceOverrides, RowOrientation, SENTINEL_UUID, type ScopeType, SoilTexture, TASK_TYPE_REGISTRY, type TabConfig, TargetEntityType, TaskStatus, TaskType, type TaskTypeConfig, TransactionType, TrellisType, UserPrivilege, UserRole, type UserRoleType, Validator, VigorRating, WaterSource, assertCanWrite, assertTenantBoundary, buildRlsFilter, canRead, canWrite, evaluateBaseAccess, extractAppCode, generateCanonicalId, generateInfrastructureFields, getAcceptedMimeTypes, getApproveAction, getFormMeta, getFormsGroupedByModule, getTaskTypeOptions, handleAppErrorResponse, isTabVisible, isTabWritable, resolveAccess, resolveAppError, resolveEffectiveAccess, resolveError, resolveMenuVisibility, withAgriLogging };
|
package/dist/index.d.ts
CHANGED
|
@@ -487,6 +487,7 @@ declare const RESOURCE_PATHS: {
|
|
|
487
487
|
teamStaff: string;
|
|
488
488
|
teamTraining: string;
|
|
489
489
|
};
|
|
490
|
+
declare const RESOURCE_MODULE_MAP: Record<string, string[]>;
|
|
490
491
|
declare const ACCESS_RANK: Record<AccessLevelType, number>;
|
|
491
492
|
declare const ROLE_SECTIONS_BY_KEY: Record<string, UserRoleType[]>;
|
|
492
493
|
declare function evaluateBaseAccess(resourcePath: string, session: {
|
|
@@ -494,7 +495,6 @@ declare function evaluateBaseAccess(resourcePath: string, session: {
|
|
|
494
495
|
privileges?: string[];
|
|
495
496
|
enabledModules?: string[];
|
|
496
497
|
}, requirements?: {
|
|
497
|
-
module?: string;
|
|
498
498
|
allowedRoles?: UserRoleType[];
|
|
499
499
|
requiredPrivileges?: string[];
|
|
500
500
|
}): AccessLevelType;
|
|
@@ -506,7 +506,8 @@ declare function evaluateBaseAccess(resourcePath: string, session: {
|
|
|
506
506
|
declare function assertTenantBoundary(db: any, requesterCompanyId: string, targets: {
|
|
507
507
|
targetUserId?: string;
|
|
508
508
|
authScopeId?: string;
|
|
509
|
+
expectedScopeType?: 'company' | 'legalEntity' | 'facility';
|
|
509
510
|
}): Promise<boolean>;
|
|
510
|
-
declare function resolveEffectiveAccess(base: AccessLevelType, override?: AccessLevelType): AccessLevelType;
|
|
511
|
+
declare function resolveEffectiveAccess(base: AccessLevelType, override?: AccessLevelType | null): AccessLevelType;
|
|
511
512
|
|
|
512
|
-
export { ACCESS_RANK, ACT, AccessLevel, type AccessLevelType, type AgriCoreSession, AgriLogger, AppError, ApprovalStatus, ApprovalType, AuditStatus, AuditType, type AuthScopeFields, type AvailableScope, CAT, type CompanyConfig, Converter, CropCycleStatus, ERROR_DICTIONARY, EmitterType, EnabledModule, ErrorFactory, FORM_REGISTRY, FacilityType, type FormMeta, HarvestMethod, type InfrastructureFields, LinkedStatus, MOD, MODULE_LABELS, MicroclimateZone, MimeType, type ModCode, NettingType, NotificationMode, OrderStatus, type PermissionLevel, PhysicalState, PlantingMethod, RESOURCE_PATHS, ROLE_SECTIONS_BY_KEY, RelationshipType, type ResolvedError, type ResourceOverrides, RowOrientation, SENTINEL_UUID, type ScopeType, SoilTexture, TASK_TYPE_REGISTRY, type TabConfig, TargetEntityType, TaskStatus, TaskType, type TaskTypeConfig, TransactionType, TrellisType, UserPrivilege, UserRole, type UserRoleType, Validator, VigorRating, WaterSource, assertCanWrite, assertTenantBoundary, buildRlsFilter, canRead, canWrite, evaluateBaseAccess, extractAppCode, generateCanonicalId, generateInfrastructureFields, getAcceptedMimeTypes, getApproveAction, getFormMeta, getFormsGroupedByModule, getTaskTypeOptions, handleAppErrorResponse, isTabVisible, isTabWritable, resolveAccess, resolveAppError, resolveEffectiveAccess, resolveError, resolveMenuVisibility, withAgriLogging };
|
|
513
|
+
export { ACCESS_RANK, ACT, AccessLevel, type AccessLevelType, type AgriCoreSession, AgriLogger, AppError, ApprovalStatus, ApprovalType, AuditStatus, AuditType, type AuthScopeFields, type AvailableScope, CAT, type CompanyConfig, Converter, CropCycleStatus, ERROR_DICTIONARY, EmitterType, EnabledModule, ErrorFactory, FORM_REGISTRY, FacilityType, type FormMeta, HarvestMethod, type InfrastructureFields, LinkedStatus, MOD, MODULE_LABELS, MicroclimateZone, MimeType, type ModCode, NettingType, NotificationMode, OrderStatus, type PermissionLevel, PhysicalState, PlantingMethod, RESOURCE_MODULE_MAP, RESOURCE_PATHS, ROLE_SECTIONS_BY_KEY, RelationshipType, type ResolvedError, type ResourceOverrides, RowOrientation, SENTINEL_UUID, type ScopeType, SoilTexture, TASK_TYPE_REGISTRY, type TabConfig, TargetEntityType, TaskStatus, TaskType, type TaskTypeConfig, TransactionType, TrellisType, UserPrivilege, UserRole, type UserRoleType, Validator, VigorRating, WaterSource, assertCanWrite, assertTenantBoundary, buildRlsFilter, canRead, canWrite, evaluateBaseAccess, extractAppCode, generateCanonicalId, generateInfrastructureFields, getAcceptedMimeTypes, getApproveAction, getFormMeta, getFormsGroupedByModule, getTaskTypeOptions, handleAppErrorResponse, isTabVisible, isTabWritable, resolveAccess, resolveAppError, resolveEffectiveAccess, resolveError, resolveMenuVisibility, withAgriLogging };
|
package/dist/index.js
CHANGED
|
@@ -49,6 +49,7 @@ __export(index_exports, {
|
|
|
49
49
|
OrderStatus: () => OrderStatus,
|
|
50
50
|
PhysicalState: () => PhysicalState,
|
|
51
51
|
PlantingMethod: () => PlantingMethod,
|
|
52
|
+
RESOURCE_MODULE_MAP: () => RESOURCE_MODULE_MAP,
|
|
52
53
|
RESOURCE_PATHS: () => RESOURCE_PATHS,
|
|
53
54
|
ROLE_SECTIONS_BY_KEY: () => ROLE_SECTIONS_BY_KEY,
|
|
54
55
|
RelationshipType: () => RelationshipType,
|
|
@@ -842,6 +843,56 @@ var RESOURCE_PATHS = {
|
|
|
842
843
|
teamStaff: "team.staff",
|
|
843
844
|
teamTraining: "team.training"
|
|
844
845
|
};
|
|
846
|
+
var ALL_OPERATIONS = [
|
|
847
|
+
EnabledModule.FARM_MANAGEMENT,
|
|
848
|
+
EnabledModule.PACKHOUSE,
|
|
849
|
+
EnabledModule.ACCOMMODATION
|
|
850
|
+
];
|
|
851
|
+
var AGRI_ONLY = [
|
|
852
|
+
EnabledModule.FARM_MANAGEMENT,
|
|
853
|
+
EnabledModule.PACKHOUSE
|
|
854
|
+
];
|
|
855
|
+
var RESOURCE_MODULE_MAP = {
|
|
856
|
+
// ── Top-level menu sections ────────────────────────────────────────────────
|
|
857
|
+
// CORE features (accessible to everyone with an account)
|
|
858
|
+
[RESOURCE_PATHS.dashboard]: [],
|
|
859
|
+
[RESOURCE_PATHS.operations]: ALL_OPERATIONS,
|
|
860
|
+
[RESOURCE_PATHS.equipment]: ALL_OPERATIONS,
|
|
861
|
+
[RESOURCE_PATHS.safety]: ALL_OPERATIONS,
|
|
862
|
+
[RESOURCE_PATHS.team]: ALL_OPERATIONS,
|
|
863
|
+
[RESOURCE_PATHS.records]: ALL_OPERATIONS,
|
|
864
|
+
[RESOURCE_PATHS.adminSettings]: ALL_OPERATIONS,
|
|
865
|
+
// ── Records & Reports ──────────────────────────────────────────────────────
|
|
866
|
+
[RESOURCE_PATHS.documentHub]: ALL_OPERATIONS,
|
|
867
|
+
[RESOURCE_PATHS.documentHubTemplates]: ALL_OPERATIONS,
|
|
868
|
+
[RESOURCE_PATHS.documentHubFolder]: ALL_OPERATIONS,
|
|
869
|
+
[RESOURCE_PATHS.documentHubExtraction]: ALL_OPERATIONS,
|
|
870
|
+
[RESOURCE_PATHS.documentHubQueue]: ALL_OPERATIONS,
|
|
871
|
+
[RESOURCE_PATHS.analytics]: ALL_OPERATIONS,
|
|
872
|
+
// ── Admin Settings ─────────────────────────────────────────────────────────
|
|
873
|
+
[RESOURCE_PATHS.adminUserRoster]: ALL_OPERATIONS,
|
|
874
|
+
[RESOURCE_PATHS.adminBlueprintsSites]: ALL_OPERATIONS,
|
|
875
|
+
[RESOURCE_PATHS.adminRolesPermissions]: ALL_OPERATIONS,
|
|
876
|
+
[RESOURCE_PATHS.adminCompanySettings]: ALL_OPERATIONS,
|
|
877
|
+
// ── Operations ────────────────────────────────────────────────────────────
|
|
878
|
+
[RESOURCE_PATHS.farmManagement]: [EnabledModule.FARM_MANAGEMENT],
|
|
879
|
+
[RESOURCE_PATHS.packhouse]: [EnabledModule.PACKHOUSE],
|
|
880
|
+
[RESOURCE_PATHS.accommodation]: [EnabledModule.ACCOMMODATION],
|
|
881
|
+
// ── Equipment & Fleet ──────────────────────────────────────────────────────
|
|
882
|
+
[RESOURCE_PATHS.equipPreStart]: ALL_OPERATIONS,
|
|
883
|
+
[RESOURCE_PATHS.equipMaintenance]: ALL_OPERATIONS,
|
|
884
|
+
[RESOURCE_PATHS.equipFuelRegister]: ALL_OPERATIONS,
|
|
885
|
+
[RESOURCE_PATHS.equipCalibration]: AGRI_ONLY,
|
|
886
|
+
[RESOURCE_PATHS.equipFleet]: ALL_OPERATIONS,
|
|
887
|
+
// ── Safety, Quality & Compliance ──────────────────────────────────────────
|
|
888
|
+
[RESOURCE_PATHS.safetyAuditing]: ALL_OPERATIONS,
|
|
889
|
+
[RESOURCE_PATHS.safetyFood]: AGRI_ONLY,
|
|
890
|
+
[RESOURCE_PATHS.safetyWhs]: ALL_OPERATIONS,
|
|
891
|
+
[RESOURCE_PATHS.safetyCleaning]: ALL_OPERATIONS,
|
|
892
|
+
// ── Team & HR ──────────────────────────────────────────────────────────────
|
|
893
|
+
[RESOURCE_PATHS.teamStaff]: ALL_OPERATIONS,
|
|
894
|
+
[RESOURCE_PATHS.teamTraining]: ALL_OPERATIONS
|
|
895
|
+
};
|
|
845
896
|
var ACCESS_RANK = {
|
|
846
897
|
NONE: 0,
|
|
847
898
|
READ: 1,
|
|
@@ -859,18 +910,20 @@ var ROLE_SECTIONS_BY_KEY = {
|
|
|
859
910
|
function evaluateBaseAccess(resourcePath, session, requirements = {}) {
|
|
860
911
|
if (!session?.role) return "NONE";
|
|
861
912
|
if (session.role === UserRole.OWNER) return "WRITE";
|
|
913
|
+
const requiredModules = RESOURCE_MODULE_MAP[resourcePath] || [];
|
|
914
|
+
if (requiredModules.length > 0) {
|
|
915
|
+
const hasModule = requiredModules.some((m) => session.enabledModules?.includes(m));
|
|
916
|
+
if (!hasModule) return "NONE";
|
|
917
|
+
}
|
|
862
918
|
const topLevel = resourcePath.split(".")[0];
|
|
863
919
|
const defaultRoles = ROLE_SECTIONS_BY_KEY[topLevel] || [];
|
|
864
|
-
if (requirements.module && !session.enabledModules?.includes(requirements.module)) return "NONE";
|
|
865
920
|
const allowedRoles = requirements.allowedRoles?.length ? requirements.allowedRoles : defaultRoles;
|
|
866
921
|
if (!allowedRoles.includes(session.role)) return "NONE";
|
|
867
922
|
if (requirements.requiredPrivileges?.length) {
|
|
868
923
|
const hasPrivilege = requirements.requiredPrivileges.some((p) => session.privileges?.includes(p));
|
|
869
924
|
if (!hasPrivilege) return "NONE";
|
|
870
925
|
}
|
|
871
|
-
|
|
872
|
-
const isHighRole = highRoles.includes(session.role);
|
|
873
|
-
return isHighRole ? "WRITE" : "READ";
|
|
926
|
+
return session.role === UserRole.MANAGER ? "WRITE" : "READ";
|
|
874
927
|
}
|
|
875
928
|
async function assertTenantBoundary(db, requesterCompanyId, targets) {
|
|
876
929
|
if (!requesterCompanyId) {
|
|
@@ -887,23 +940,29 @@ async function assertTenantBoundary(db, requesterCompanyId, targets) {
|
|
|
887
940
|
}
|
|
888
941
|
}
|
|
889
942
|
if (targets.authScopeId) {
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
943
|
+
let matchFound = false;
|
|
944
|
+
if (targets.expectedScopeType === "company" || !targets.expectedScopeType) {
|
|
945
|
+
const c = await db.Company.filter({ canonicalId: targets.authScopeId, id: requesterCompanyId });
|
|
946
|
+
if (c.length > 0) matchFound = true;
|
|
947
|
+
}
|
|
948
|
+
if (!matchFound && (targets.expectedScopeType === "legalEntity" || !targets.expectedScopeType)) {
|
|
949
|
+
const le = await db.LegalEntity.filter({ canonicalId: targets.authScopeId, companyId: requesterCompanyId });
|
|
950
|
+
if (le.length > 0) matchFound = true;
|
|
951
|
+
}
|
|
952
|
+
if (!matchFound && (targets.expectedScopeType === "facility" || !targets.expectedScopeType)) {
|
|
953
|
+
const fac = await db.Facility.filter({ canonicalId: targets.authScopeId, companyId: requesterCompanyId });
|
|
954
|
+
if (fac.length > 0) matchFound = true;
|
|
955
|
+
}
|
|
956
|
+
if (!matchFound) {
|
|
957
|
+
console.error(`[SECURITY BREACH/VALIDATION ERROR] Scope ${targets.authScopeId} not found for type ${targets.expectedScopeType} in company ${requesterCompanyId}`);
|
|
958
|
+
throw ErrorFactory.forbidden(MOD.ADMIN, ACT.EDIT, "Invalid authorization scope level or tenant boundary violation.");
|
|
900
959
|
}
|
|
901
960
|
}
|
|
902
961
|
return true;
|
|
903
962
|
}
|
|
904
963
|
function resolveEffectiveAccess(base, override) {
|
|
905
|
-
if (
|
|
906
|
-
return
|
|
964
|
+
if (override === void 0 || override === null) return base;
|
|
965
|
+
return override;
|
|
907
966
|
}
|
|
908
967
|
// Annotate the CommonJS export names for ESM import in node:
|
|
909
968
|
0 && (module.exports = {
|
|
@@ -936,6 +995,7 @@ function resolveEffectiveAccess(base, override) {
|
|
|
936
995
|
OrderStatus,
|
|
937
996
|
PhysicalState,
|
|
938
997
|
PlantingMethod,
|
|
998
|
+
RESOURCE_MODULE_MAP,
|
|
939
999
|
RESOURCE_PATHS,
|
|
940
1000
|
ROLE_SECTIONS_BY_KEY,
|
|
941
1001
|
RelationshipType,
|
package/dist/index.mjs
CHANGED
|
@@ -748,6 +748,56 @@ var RESOURCE_PATHS = {
|
|
|
748
748
|
teamStaff: "team.staff",
|
|
749
749
|
teamTraining: "team.training"
|
|
750
750
|
};
|
|
751
|
+
var ALL_OPERATIONS = [
|
|
752
|
+
EnabledModule.FARM_MANAGEMENT,
|
|
753
|
+
EnabledModule.PACKHOUSE,
|
|
754
|
+
EnabledModule.ACCOMMODATION
|
|
755
|
+
];
|
|
756
|
+
var AGRI_ONLY = [
|
|
757
|
+
EnabledModule.FARM_MANAGEMENT,
|
|
758
|
+
EnabledModule.PACKHOUSE
|
|
759
|
+
];
|
|
760
|
+
var RESOURCE_MODULE_MAP = {
|
|
761
|
+
// ── Top-level menu sections ────────────────────────────────────────────────
|
|
762
|
+
// CORE features (accessible to everyone with an account)
|
|
763
|
+
[RESOURCE_PATHS.dashboard]: [],
|
|
764
|
+
[RESOURCE_PATHS.operations]: ALL_OPERATIONS,
|
|
765
|
+
[RESOURCE_PATHS.equipment]: ALL_OPERATIONS,
|
|
766
|
+
[RESOURCE_PATHS.safety]: ALL_OPERATIONS,
|
|
767
|
+
[RESOURCE_PATHS.team]: ALL_OPERATIONS,
|
|
768
|
+
[RESOURCE_PATHS.records]: ALL_OPERATIONS,
|
|
769
|
+
[RESOURCE_PATHS.adminSettings]: ALL_OPERATIONS,
|
|
770
|
+
// ── Records & Reports ──────────────────────────────────────────────────────
|
|
771
|
+
[RESOURCE_PATHS.documentHub]: ALL_OPERATIONS,
|
|
772
|
+
[RESOURCE_PATHS.documentHubTemplates]: ALL_OPERATIONS,
|
|
773
|
+
[RESOURCE_PATHS.documentHubFolder]: ALL_OPERATIONS,
|
|
774
|
+
[RESOURCE_PATHS.documentHubExtraction]: ALL_OPERATIONS,
|
|
775
|
+
[RESOURCE_PATHS.documentHubQueue]: ALL_OPERATIONS,
|
|
776
|
+
[RESOURCE_PATHS.analytics]: ALL_OPERATIONS,
|
|
777
|
+
// ── Admin Settings ─────────────────────────────────────────────────────────
|
|
778
|
+
[RESOURCE_PATHS.adminUserRoster]: ALL_OPERATIONS,
|
|
779
|
+
[RESOURCE_PATHS.adminBlueprintsSites]: ALL_OPERATIONS,
|
|
780
|
+
[RESOURCE_PATHS.adminRolesPermissions]: ALL_OPERATIONS,
|
|
781
|
+
[RESOURCE_PATHS.adminCompanySettings]: ALL_OPERATIONS,
|
|
782
|
+
// ── Operations ────────────────────────────────────────────────────────────
|
|
783
|
+
[RESOURCE_PATHS.farmManagement]: [EnabledModule.FARM_MANAGEMENT],
|
|
784
|
+
[RESOURCE_PATHS.packhouse]: [EnabledModule.PACKHOUSE],
|
|
785
|
+
[RESOURCE_PATHS.accommodation]: [EnabledModule.ACCOMMODATION],
|
|
786
|
+
// ── Equipment & Fleet ──────────────────────────────────────────────────────
|
|
787
|
+
[RESOURCE_PATHS.equipPreStart]: ALL_OPERATIONS,
|
|
788
|
+
[RESOURCE_PATHS.equipMaintenance]: ALL_OPERATIONS,
|
|
789
|
+
[RESOURCE_PATHS.equipFuelRegister]: ALL_OPERATIONS,
|
|
790
|
+
[RESOURCE_PATHS.equipCalibration]: AGRI_ONLY,
|
|
791
|
+
[RESOURCE_PATHS.equipFleet]: ALL_OPERATIONS,
|
|
792
|
+
// ── Safety, Quality & Compliance ──────────────────────────────────────────
|
|
793
|
+
[RESOURCE_PATHS.safetyAuditing]: ALL_OPERATIONS,
|
|
794
|
+
[RESOURCE_PATHS.safetyFood]: AGRI_ONLY,
|
|
795
|
+
[RESOURCE_PATHS.safetyWhs]: ALL_OPERATIONS,
|
|
796
|
+
[RESOURCE_PATHS.safetyCleaning]: ALL_OPERATIONS,
|
|
797
|
+
// ── Team & HR ──────────────────────────────────────────────────────────────
|
|
798
|
+
[RESOURCE_PATHS.teamStaff]: ALL_OPERATIONS,
|
|
799
|
+
[RESOURCE_PATHS.teamTraining]: ALL_OPERATIONS
|
|
800
|
+
};
|
|
751
801
|
var ACCESS_RANK = {
|
|
752
802
|
NONE: 0,
|
|
753
803
|
READ: 1,
|
|
@@ -765,18 +815,20 @@ var ROLE_SECTIONS_BY_KEY = {
|
|
|
765
815
|
function evaluateBaseAccess(resourcePath, session, requirements = {}) {
|
|
766
816
|
if (!session?.role) return "NONE";
|
|
767
817
|
if (session.role === UserRole.OWNER) return "WRITE";
|
|
818
|
+
const requiredModules = RESOURCE_MODULE_MAP[resourcePath] || [];
|
|
819
|
+
if (requiredModules.length > 0) {
|
|
820
|
+
const hasModule = requiredModules.some((m) => session.enabledModules?.includes(m));
|
|
821
|
+
if (!hasModule) return "NONE";
|
|
822
|
+
}
|
|
768
823
|
const topLevel = resourcePath.split(".")[0];
|
|
769
824
|
const defaultRoles = ROLE_SECTIONS_BY_KEY[topLevel] || [];
|
|
770
|
-
if (requirements.module && !session.enabledModules?.includes(requirements.module)) return "NONE";
|
|
771
825
|
const allowedRoles = requirements.allowedRoles?.length ? requirements.allowedRoles : defaultRoles;
|
|
772
826
|
if (!allowedRoles.includes(session.role)) return "NONE";
|
|
773
827
|
if (requirements.requiredPrivileges?.length) {
|
|
774
828
|
const hasPrivilege = requirements.requiredPrivileges.some((p) => session.privileges?.includes(p));
|
|
775
829
|
if (!hasPrivilege) return "NONE";
|
|
776
830
|
}
|
|
777
|
-
|
|
778
|
-
const isHighRole = highRoles.includes(session.role);
|
|
779
|
-
return isHighRole ? "WRITE" : "READ";
|
|
831
|
+
return session.role === UserRole.MANAGER ? "WRITE" : "READ";
|
|
780
832
|
}
|
|
781
833
|
async function assertTenantBoundary(db, requesterCompanyId, targets) {
|
|
782
834
|
if (!requesterCompanyId) {
|
|
@@ -793,23 +845,29 @@ async function assertTenantBoundary(db, requesterCompanyId, targets) {
|
|
|
793
845
|
}
|
|
794
846
|
}
|
|
795
847
|
if (targets.authScopeId) {
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
848
|
+
let matchFound = false;
|
|
849
|
+
if (targets.expectedScopeType === "company" || !targets.expectedScopeType) {
|
|
850
|
+
const c = await db.Company.filter({ canonicalId: targets.authScopeId, id: requesterCompanyId });
|
|
851
|
+
if (c.length > 0) matchFound = true;
|
|
852
|
+
}
|
|
853
|
+
if (!matchFound && (targets.expectedScopeType === "legalEntity" || !targets.expectedScopeType)) {
|
|
854
|
+
const le = await db.LegalEntity.filter({ canonicalId: targets.authScopeId, companyId: requesterCompanyId });
|
|
855
|
+
if (le.length > 0) matchFound = true;
|
|
856
|
+
}
|
|
857
|
+
if (!matchFound && (targets.expectedScopeType === "facility" || !targets.expectedScopeType)) {
|
|
858
|
+
const fac = await db.Facility.filter({ canonicalId: targets.authScopeId, companyId: requesterCompanyId });
|
|
859
|
+
if (fac.length > 0) matchFound = true;
|
|
860
|
+
}
|
|
861
|
+
if (!matchFound) {
|
|
862
|
+
console.error(`[SECURITY BREACH/VALIDATION ERROR] Scope ${targets.authScopeId} not found for type ${targets.expectedScopeType} in company ${requesterCompanyId}`);
|
|
863
|
+
throw ErrorFactory.forbidden(MOD.ADMIN, ACT.EDIT, "Invalid authorization scope level or tenant boundary violation.");
|
|
806
864
|
}
|
|
807
865
|
}
|
|
808
866
|
return true;
|
|
809
867
|
}
|
|
810
868
|
function resolveEffectiveAccess(base, override) {
|
|
811
|
-
if (
|
|
812
|
-
return
|
|
869
|
+
if (override === void 0 || override === null) return base;
|
|
870
|
+
return override;
|
|
813
871
|
}
|
|
814
872
|
export {
|
|
815
873
|
ACCESS_RANK,
|
|
@@ -841,6 +899,7 @@ export {
|
|
|
841
899
|
OrderStatus,
|
|
842
900
|
PhysicalState,
|
|
843
901
|
PlantingMethod,
|
|
902
|
+
RESOURCE_MODULE_MAP,
|
|
844
903
|
RESOURCE_PATHS,
|
|
845
904
|
ROLE_SECTIONS_BY_KEY,
|
|
846
905
|
RelationshipType,
|