@litusarchieve18/agricore-utils 1.0.10 → 1.0.12

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 CHANGED
@@ -65,6 +65,8 @@ The universal vocabulary of the AgriCore platform, ensuring type-safety across a
65
65
  🔐 Security & Access Control
66
66
  The library now includes a centralized logic layer to enforce granular permissions across all AgriCore services.
67
67
 
68
+ ---------------------------------------------------------------------
69
+
68
70
  evaluateBaseAccess: Automatically determines a user's base permission level (NONE, READ, or WRITE) for a specific resource path (e.g., records.financials). It respects the OWNER role "God Mode" bypass and uses ROLE_SECTIONS_BY_KEY to provide sensible defaults for different app sections.
69
71
 
70
72
  Access Ranking (resolveEffectiveAccess): Implements an additive permission model. By ranking levels (NONE < READ < WRITE), it allows the system to compare base permissions against specific user overrides and resolve the highest authorized access level.
@@ -92,6 +94,8 @@ const recordToSave = {
92
94
 
93
95
  To completely eliminate database bottlenecks and solve serverless rate-limiting, AgriCore has migrated to a state-of-the-art, "Zero-DB" authorization architecture. By decoupling our security rules from the database SDK, our backend API endpoints now resolve complex multi-tenant boundaries and granular role-based access controls in roughly 1 millisecond.
94
96
 
97
+ ---------------------------------------------------------------------
98
+
95
99
  Key Features of the New Security Engine:
96
100
 
97
101
  One-Time Session Generation: On login, the backend dynamically aggregates a user's full hierarchical profile—including role assignments, availableScopes (Company > Legal Entity > Facility), and granular resourceOverrides—into a single, cryptographically signed JSON Web Token (JWT).
@@ -102,6 +106,56 @@ Smart Frontend Interceptor: A centralized React hook (useApiClient) acts as an a
102
106
 
103
107
  Instant Context Switching: Because the JWT securely holds the user's entire "VIP List" of permitted scopes, users can instantly switch between farms, legal entities, and facilities in the frontend global dropdown without triggering a new authentication handshake or database query.
104
108
 
109
+ ---------------------------------------------------------------------
110
+
111
+ This Document Management Engine provides a standardized, compliant, and migration-ready architecture for handling agricultural records. It ensures that files are stored predictably and matched against audit requirements with high precision.
112
+
113
+ Document Management & Compliance Engine
114
+ This module handles the lifecycle of file assets, from standardized naming and path generation to intelligent metadata matching for compliance audits.
115
+
116
+ 1. Standardized Taxonomy (DocumentType)
117
+ The DocumentType enum serves as the single source of truth for the AgriCore document ecosystem. It categorizes every record—from SPRAY_RECORD to MAPPING_FARM_MAPS—ensuring that the database remains searchable and consistent across different farms and legal entities.
118
+
119
+ 2. Smart Routing (generateDocumentPath)
120
+ This function enforces the "Core vs. Seasonal" storage architecture. It ensures that permanent files (Fixed Assets) and crop-cycle files (Working Assets) are physically and logically separated:
121
+
122
+ Static Assets (isStatic: true): Routed to {SiteName}/_CORE/{DocumentType}.
123
+
124
+ Seasonal Assets: Routed to a strict temporal hierarchy: {SiteName}/_SEASONAL/{Year}/{DocumentType}/{Crop}.
125
+
126
+ 3. Intelligence Engine (calculateFileMetadataMatch)
127
+ A 3-tier matching algorithm used to automatically suggest evidence for audit questions. It evaluates the relevance of a file based on three layers:
128
+
129
+ Static Hard Fails: Strict equality checks for properties like documentType.
130
+
131
+ Dynamic Hard Fails (mustMatchContext): Ensures files belong to the correct boundaries (e.g., siteId array inclusion) based on the current AuditHeader.
132
+
133
+ Soft Relevance Scoring (contextMatch): Calculates a percentage score based on environmental tags like seasonId or crop, allowing the UI to surface the "best matches" first.
134
+
135
+ Quick Example
136
+ TypeScript
137
+ // 1. Generate a path for a seasonal spray record
138
+ const path = generateDocumentPath({
139
+ siteName: "North Farm",
140
+ docType: DocumentType.SPRAY_RECORD,
141
+ year: 2026,
142
+ crop: "Mango"
143
+ });
144
+ // Output: North_Farm/_SEASONAL/2026/SPRAY_RECORD/MANGO
145
+
146
+ // 2. Score a file against an audit requirement
147
+ const score = calculateFileMetadataMatch(
148
+ {
149
+ mustMatch: { documentType: "SPRAY_RECORD" },
150
+ mustMatchContext: ["siteId"], // Hard fail if wrong farm
151
+ contextMatch: ["seasonId"] // Soft score for season relevance
152
+ },
153
+ file.metadata,
154
+ auditHeader.context
155
+ );
156
+
157
+ ============================================================================
158
+
105
159
  🛠️ Development & Publishing Guide
106
160
  Zero Dependencies
107
161
  To keep the package ultra-lightweight (~30KB), this library has zero runtime dependencies. All build tools (tsup, typescript) are strictly kept in devDependencies, and the package.json uses the "files": ["dist"] array to ensure only compiled code is uploaded.
@@ -129,6 +183,10 @@ Run the publish command:
129
183
  Bash
130
184
  npm publish --access public
131
185
  📝 Version History
186
+ V1.0.12 — add some functionality to add a file tag
187
+
188
+ V1.0.11 — add userName and userEmail to AgriCoreSession
189
+
132
190
  V1.0.10 — add an explicit exports map
133
191
 
134
192
  V1.0.9 — added jwt function
package/dist/index.d.mts CHANGED
@@ -23,6 +23,8 @@ interface ResourceOverrides {
23
23
  */
24
24
  interface AgriCoreSession {
25
25
  userId: string;
26
+ userName: string;
27
+ userEmail: string;
26
28
  companyId: string;
27
29
  activeScopeId: string | null;
28
30
  companyConfig: CompanyConfig;
@@ -518,5 +520,57 @@ targets: {
518
520
  expectedScopeType?: 'company' | 'legalEntity' | 'facility';
519
521
  }): Promise<boolean>;
520
522
  declare function verifyAndExtractSession(token: string, secret: string): Promise<AgriCoreSession>;
523
+ declare enum DocumentType {
524
+ SPRAY_RECORD = "SPRAY_RECORD",
525
+ FERTIGATION_RECORD = "FERTIGATION_RECORD",
526
+ FERTILIZER_RECORD = "FERTILIZER_RECORD",
527
+ QA = "QA",
528
+ CLEANING = "CLEANING",
529
+ PEST = "PEST",
530
+ EQUIPMENT_CALIBRATION_RECORD = "EQUIPMENT_CALIBRATION_RECORD",
531
+ INVENTORY_CONSUMABLES = "INVENTORY_CONSUMABLES",
532
+ INVENTORY_BOX_CARTON = "INVENTORY_BOX_CARTON",
533
+ INVENTORY_CHEMICALS = "INVENTORY_CHEMICALS",
534
+ STOCKTAKE = "STOCKTAKE",
535
+ STOCKTAKE_MSDS = "STOCKTAKE_MSDS",
536
+ MAPPING_FARM_MAPS = "MAPPING_FARM_MAPS",
537
+ MAPPING_TRAFIC_MANAGEMENT = "MAPPING_TRAFIC_MANAGEMENT",
538
+ MAPPING_EMERGENCY = "MAPPING_EMERGENCY",
539
+ INCIDENT_REPORT = "INCIDENT_REPORT",
540
+ TRAINING_RECORDS = "TRAINING_RECORDS",
541
+ SOPS = "SOPS",
542
+ RISK_ASSESSMENTS = "RISK_ASSESSMENTS",
543
+ SERVICING_MAINTENANCE = "SERVICING_MAINTENANCE",
544
+ SOIL_TEST = "SOIL_TEST",
545
+ LEAF_TEST = "LEAF_TEST",
546
+ WATER_TEST = "WATER_TEST",
547
+ MRL_TESTING = "MRL_TESTING",
548
+ HEAVY_METAL = "HEAVY_METAL",
549
+ MICROBIAL = "MICROBIAL",
550
+ HARVEST_LOG = "HARVEST_LOG",
551
+ PACKHOUSE_INSPECTION = "PACKHOUSE_INSPECTION",
552
+ TRAINING_CERTIFICATE = "TRAINING_CERTIFICATE",
553
+ INVOICE = "INVOICE",
554
+ LEGAL_CONTRACT = "LEGAL_CONTRACT",
555
+ AUDIT_REPORT = "AUDIT_REPORT",
556
+ SENSITIVE_IDENTITY = "SENSITIVE_IDENTITY"
557
+ }
558
+ /**
559
+ * Generates a full folder path matching strict business requirements.
560
+ * Static: {SiteName}/_CORE/{DocumentType}
561
+ * Dynamic: {SiteName}/_SEASONAL/{Year}/{DocumentType}/{Crop}
562
+ */
563
+ declare function generateDocumentPath(params: {
564
+ siteName: string;
565
+ docType: DocumentType;
566
+ isStatic?: boolean;
567
+ year?: number | string;
568
+ crop?: string;
569
+ }): string;
570
+ declare function calculateFileMetadataMatch(criteria: {
571
+ mustMatch: Record<string, any>;
572
+ mustMatchContext?: string[];
573
+ contextMatch?: string[];
574
+ }, fileMetadata: Record<string, any>, auditContext: Record<string, any>): number;
521
575
 
522
- 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, EVERYONE, 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, RESOURCE_REQUIREMENTS, ROLE_SECTIONS_BY_KEY, RelationshipType, type ResolvedError, type ResourceOverrides, type ResourceRequirement, 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, findSpecificOverride, generateCanonicalId, generateInfrastructureFields, getAcceptedMimeTypes, getApproveAction, getFormMeta, getFormsGroupedByModule, getTaskTypeOptions, handleAppErrorResponse, isTabVisible, isTabWritable, resolveAccess, resolveAppError, resolveEffectiveAccess, resolveError, resolveMenuVisibility, verifyAndExtractSession, withAgriLogging };
576
+ export { ACCESS_RANK, ACT, AccessLevel, type AccessLevelType, type AgriCoreSession, AgriLogger, AppError, ApprovalStatus, ApprovalType, AuditStatus, AuditType, type AuthScopeFields, type AvailableScope, CAT, type CompanyConfig, Converter, CropCycleStatus, DocumentType, ERROR_DICTIONARY, EVERYONE, 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, RESOURCE_REQUIREMENTS, ROLE_SECTIONS_BY_KEY, RelationshipType, type ResolvedError, type ResourceOverrides, type ResourceRequirement, 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, calculateFileMetadataMatch, canRead, canWrite, evaluateBaseAccess, extractAppCode, findSpecificOverride, generateCanonicalId, generateDocumentPath, generateInfrastructureFields, getAcceptedMimeTypes, getApproveAction, getFormMeta, getFormsGroupedByModule, getTaskTypeOptions, handleAppErrorResponse, isTabVisible, isTabWritable, resolveAccess, resolveAppError, resolveEffectiveAccess, resolveError, resolveMenuVisibility, verifyAndExtractSession, withAgriLogging };
package/dist/index.d.ts CHANGED
@@ -23,6 +23,8 @@ interface ResourceOverrides {
23
23
  */
24
24
  interface AgriCoreSession {
25
25
  userId: string;
26
+ userName: string;
27
+ userEmail: string;
26
28
  companyId: string;
27
29
  activeScopeId: string | null;
28
30
  companyConfig: CompanyConfig;
@@ -518,5 +520,57 @@ targets: {
518
520
  expectedScopeType?: 'company' | 'legalEntity' | 'facility';
519
521
  }): Promise<boolean>;
520
522
  declare function verifyAndExtractSession(token: string, secret: string): Promise<AgriCoreSession>;
523
+ declare enum DocumentType {
524
+ SPRAY_RECORD = "SPRAY_RECORD",
525
+ FERTIGATION_RECORD = "FERTIGATION_RECORD",
526
+ FERTILIZER_RECORD = "FERTILIZER_RECORD",
527
+ QA = "QA",
528
+ CLEANING = "CLEANING",
529
+ PEST = "PEST",
530
+ EQUIPMENT_CALIBRATION_RECORD = "EQUIPMENT_CALIBRATION_RECORD",
531
+ INVENTORY_CONSUMABLES = "INVENTORY_CONSUMABLES",
532
+ INVENTORY_BOX_CARTON = "INVENTORY_BOX_CARTON",
533
+ INVENTORY_CHEMICALS = "INVENTORY_CHEMICALS",
534
+ STOCKTAKE = "STOCKTAKE",
535
+ STOCKTAKE_MSDS = "STOCKTAKE_MSDS",
536
+ MAPPING_FARM_MAPS = "MAPPING_FARM_MAPS",
537
+ MAPPING_TRAFIC_MANAGEMENT = "MAPPING_TRAFIC_MANAGEMENT",
538
+ MAPPING_EMERGENCY = "MAPPING_EMERGENCY",
539
+ INCIDENT_REPORT = "INCIDENT_REPORT",
540
+ TRAINING_RECORDS = "TRAINING_RECORDS",
541
+ SOPS = "SOPS",
542
+ RISK_ASSESSMENTS = "RISK_ASSESSMENTS",
543
+ SERVICING_MAINTENANCE = "SERVICING_MAINTENANCE",
544
+ SOIL_TEST = "SOIL_TEST",
545
+ LEAF_TEST = "LEAF_TEST",
546
+ WATER_TEST = "WATER_TEST",
547
+ MRL_TESTING = "MRL_TESTING",
548
+ HEAVY_METAL = "HEAVY_METAL",
549
+ MICROBIAL = "MICROBIAL",
550
+ HARVEST_LOG = "HARVEST_LOG",
551
+ PACKHOUSE_INSPECTION = "PACKHOUSE_INSPECTION",
552
+ TRAINING_CERTIFICATE = "TRAINING_CERTIFICATE",
553
+ INVOICE = "INVOICE",
554
+ LEGAL_CONTRACT = "LEGAL_CONTRACT",
555
+ AUDIT_REPORT = "AUDIT_REPORT",
556
+ SENSITIVE_IDENTITY = "SENSITIVE_IDENTITY"
557
+ }
558
+ /**
559
+ * Generates a full folder path matching strict business requirements.
560
+ * Static: {SiteName}/_CORE/{DocumentType}
561
+ * Dynamic: {SiteName}/_SEASONAL/{Year}/{DocumentType}/{Crop}
562
+ */
563
+ declare function generateDocumentPath(params: {
564
+ siteName: string;
565
+ docType: DocumentType;
566
+ isStatic?: boolean;
567
+ year?: number | string;
568
+ crop?: string;
569
+ }): string;
570
+ declare function calculateFileMetadataMatch(criteria: {
571
+ mustMatch: Record<string, any>;
572
+ mustMatchContext?: string[];
573
+ contextMatch?: string[];
574
+ }, fileMetadata: Record<string, any>, auditContext: Record<string, any>): number;
521
575
 
522
- 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, EVERYONE, 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, RESOURCE_REQUIREMENTS, ROLE_SECTIONS_BY_KEY, RelationshipType, type ResolvedError, type ResourceOverrides, type ResourceRequirement, 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, findSpecificOverride, generateCanonicalId, generateInfrastructureFields, getAcceptedMimeTypes, getApproveAction, getFormMeta, getFormsGroupedByModule, getTaskTypeOptions, handleAppErrorResponse, isTabVisible, isTabWritable, resolveAccess, resolveAppError, resolveEffectiveAccess, resolveError, resolveMenuVisibility, verifyAndExtractSession, withAgriLogging };
576
+ export { ACCESS_RANK, ACT, AccessLevel, type AccessLevelType, type AgriCoreSession, AgriLogger, AppError, ApprovalStatus, ApprovalType, AuditStatus, AuditType, type AuthScopeFields, type AvailableScope, CAT, type CompanyConfig, Converter, CropCycleStatus, DocumentType, ERROR_DICTIONARY, EVERYONE, 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, RESOURCE_REQUIREMENTS, ROLE_SECTIONS_BY_KEY, RelationshipType, type ResolvedError, type ResourceOverrides, type ResourceRequirement, 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, calculateFileMetadataMatch, canRead, canWrite, evaluateBaseAccess, extractAppCode, findSpecificOverride, generateCanonicalId, generateDocumentPath, generateInfrastructureFields, getAcceptedMimeTypes, getApproveAction, getFormMeta, getFormsGroupedByModule, getTaskTypeOptions, handleAppErrorResponse, isTabVisible, isTabWritable, resolveAccess, resolveAppError, resolveEffectiveAccess, resolveError, resolveMenuVisibility, verifyAndExtractSession, withAgriLogging };
package/dist/index.js CHANGED
@@ -32,6 +32,7 @@ __export(index_exports, {
32
32
  CAT: () => CAT,
33
33
  Converter: () => Converter,
34
34
  CropCycleStatus: () => CropCycleStatus,
35
+ DocumentType: () => DocumentType,
35
36
  ERROR_DICTIONARY: () => ERROR_DICTIONARY,
36
37
  EVERYONE: () => EVERYONE,
37
38
  EmitterType: () => EmitterType,
@@ -72,12 +73,14 @@ __export(index_exports, {
72
73
  assertCanWrite: () => assertCanWrite,
73
74
  assertTenantBoundary: () => assertTenantBoundary,
74
75
  buildRlsFilter: () => buildRlsFilter,
76
+ calculateFileMetadataMatch: () => calculateFileMetadataMatch,
75
77
  canRead: () => canRead,
76
78
  canWrite: () => canWrite,
77
79
  evaluateBaseAccess: () => evaluateBaseAccess,
78
80
  extractAppCode: () => extractAppCode,
79
81
  findSpecificOverride: () => findSpecificOverride,
80
82
  generateCanonicalId: () => generateCanonicalId,
83
+ generateDocumentPath: () => generateDocumentPath,
81
84
  generateInfrastructureFields: () => generateInfrastructureFields,
82
85
  getAcceptedMimeTypes: () => getAcceptedMimeTypes,
83
86
  getApproveAction: () => getApproveAction,
@@ -1058,6 +1061,79 @@ async function verifyAndExtractSession(token, secret) {
1058
1061
  throw ErrorFactory.unauthorized(MOD.SESSION, "UNAUTHORIZED: No secure session token provided.");
1059
1062
  }
1060
1063
  }
1064
+ var DocumentType = /* @__PURE__ */ ((DocumentType2) => {
1065
+ DocumentType2["SPRAY_RECORD"] = "SPRAY_RECORD";
1066
+ DocumentType2["FERTIGATION_RECORD"] = "FERTIGATION_RECORD";
1067
+ DocumentType2["FERTILIZER_RECORD"] = "FERTILIZER_RECORD";
1068
+ DocumentType2["QA"] = "QA";
1069
+ DocumentType2["CLEANING"] = "CLEANING";
1070
+ DocumentType2["PEST"] = "PEST";
1071
+ DocumentType2["EQUIPMENT_CALIBRATION_RECORD"] = "EQUIPMENT_CALIBRATION_RECORD";
1072
+ DocumentType2["INVENTORY_CONSUMABLES"] = "INVENTORY_CONSUMABLES";
1073
+ DocumentType2["INVENTORY_BOX_CARTON"] = "INVENTORY_BOX_CARTON";
1074
+ DocumentType2["INVENTORY_CHEMICALS"] = "INVENTORY_CHEMICALS";
1075
+ DocumentType2["STOCKTAKE"] = "STOCKTAKE";
1076
+ DocumentType2["STOCKTAKE_MSDS"] = "STOCKTAKE_MSDS";
1077
+ DocumentType2["MAPPING_FARM_MAPS"] = "MAPPING_FARM_MAPS";
1078
+ DocumentType2["MAPPING_TRAFIC_MANAGEMENT"] = "MAPPING_TRAFIC_MANAGEMENT";
1079
+ DocumentType2["MAPPING_EMERGENCY"] = "MAPPING_EMERGENCY";
1080
+ DocumentType2["INCIDENT_REPORT"] = "INCIDENT_REPORT";
1081
+ DocumentType2["TRAINING_RECORDS"] = "TRAINING_RECORDS";
1082
+ DocumentType2["SOPS"] = "SOPS";
1083
+ DocumentType2["RISK_ASSESSMENTS"] = "RISK_ASSESSMENTS";
1084
+ DocumentType2["SERVICING_MAINTENANCE"] = "SERVICING_MAINTENANCE";
1085
+ DocumentType2["SOIL_TEST"] = "SOIL_TEST";
1086
+ DocumentType2["LEAF_TEST"] = "LEAF_TEST";
1087
+ DocumentType2["WATER_TEST"] = "WATER_TEST";
1088
+ DocumentType2["MRL_TESTING"] = "MRL_TESTING";
1089
+ DocumentType2["HEAVY_METAL"] = "HEAVY_METAL";
1090
+ DocumentType2["MICROBIAL"] = "MICROBIAL";
1091
+ DocumentType2["HARVEST_LOG"] = "HARVEST_LOG";
1092
+ DocumentType2["PACKHOUSE_INSPECTION"] = "PACKHOUSE_INSPECTION";
1093
+ DocumentType2["TRAINING_CERTIFICATE"] = "TRAINING_CERTIFICATE";
1094
+ DocumentType2["INVOICE"] = "INVOICE";
1095
+ DocumentType2["LEGAL_CONTRACT"] = "LEGAL_CONTRACT";
1096
+ DocumentType2["AUDIT_REPORT"] = "AUDIT_REPORT";
1097
+ DocumentType2["SENSITIVE_IDENTITY"] = "SENSITIVE_IDENTITY";
1098
+ return DocumentType2;
1099
+ })(DocumentType || {});
1100
+ function generateDocumentPath(params) {
1101
+ const sanitizedName = params.siteName.replace(/[^a-z0-9]/gi, "_");
1102
+ if (params.isStatic) {
1103
+ return `${sanitizedName}/_CORE/${params.docType}`;
1104
+ } else {
1105
+ const folderYear = params.year || (/* @__PURE__ */ new Date()).getUTCFullYear();
1106
+ const folderCrop = params.crop ? `/${params.crop.toUpperCase()}` : "";
1107
+ return `${sanitizedName}/_SEASONAL/${folderYear}/${params.docType}${folderCrop}`;
1108
+ }
1109
+ }
1110
+ function isValueMatch(fileValue, expectedValue) {
1111
+ if (Array.isArray(expectedValue)) return expectedValue.includes(fileValue);
1112
+ return fileValue === expectedValue;
1113
+ }
1114
+ function calculateFileMetadataMatch(criteria, fileMetadata, auditContext) {
1115
+ for (const [key, expectedValue] of Object.entries(criteria.mustMatch)) {
1116
+ if (!isValueMatch(fileMetadata[key], expectedValue)) return 0;
1117
+ }
1118
+ if (criteria.mustMatchContext) {
1119
+ for (const field of criteria.mustMatchContext) {
1120
+ const contextValue = auditContext[field];
1121
+ if (contextValue === void 0) continue;
1122
+ if (!isValueMatch(fileMetadata[field], contextValue)) return 0;
1123
+ }
1124
+ }
1125
+ if (fileMetadata.isStatic === true) return 100;
1126
+ if (!criteria.contextMatch || criteria.contextMatch.length === 0) return 100;
1127
+ let matches = 0;
1128
+ let validChecks = 0;
1129
+ criteria.contextMatch.forEach((field) => {
1130
+ const contextValue = auditContext[field];
1131
+ if (contextValue === void 0) return;
1132
+ validChecks++;
1133
+ if (isValueMatch(fileMetadata[field], contextValue)) matches++;
1134
+ });
1135
+ return validChecks > 0 ? Math.round(matches / validChecks * 100) : 100;
1136
+ }
1061
1137
  // Annotate the CommonJS export names for ESM import in node:
1062
1138
  0 && (module.exports = {
1063
1139
  ACCESS_RANK,
@@ -1072,6 +1148,7 @@ async function verifyAndExtractSession(token, secret) {
1072
1148
  CAT,
1073
1149
  Converter,
1074
1150
  CropCycleStatus,
1151
+ DocumentType,
1075
1152
  ERROR_DICTIONARY,
1076
1153
  EVERYONE,
1077
1154
  EmitterType,
@@ -1112,12 +1189,14 @@ async function verifyAndExtractSession(token, secret) {
1112
1189
  assertCanWrite,
1113
1190
  assertTenantBoundary,
1114
1191
  buildRlsFilter,
1192
+ calculateFileMetadataMatch,
1115
1193
  canRead,
1116
1194
  canWrite,
1117
1195
  evaluateBaseAccess,
1118
1196
  extractAppCode,
1119
1197
  findSpecificOverride,
1120
1198
  generateCanonicalId,
1199
+ generateDocumentPath,
1121
1200
  generateInfrastructureFields,
1122
1201
  getAcceptedMimeTypes,
1123
1202
  getApproveAction,
package/dist/index.mjs CHANGED
@@ -961,6 +961,79 @@ async function verifyAndExtractSession(token, secret) {
961
961
  throw ErrorFactory.unauthorized(MOD.SESSION, "UNAUTHORIZED: No secure session token provided.");
962
962
  }
963
963
  }
964
+ var DocumentType = /* @__PURE__ */ ((DocumentType2) => {
965
+ DocumentType2["SPRAY_RECORD"] = "SPRAY_RECORD";
966
+ DocumentType2["FERTIGATION_RECORD"] = "FERTIGATION_RECORD";
967
+ DocumentType2["FERTILIZER_RECORD"] = "FERTILIZER_RECORD";
968
+ DocumentType2["QA"] = "QA";
969
+ DocumentType2["CLEANING"] = "CLEANING";
970
+ DocumentType2["PEST"] = "PEST";
971
+ DocumentType2["EQUIPMENT_CALIBRATION_RECORD"] = "EQUIPMENT_CALIBRATION_RECORD";
972
+ DocumentType2["INVENTORY_CONSUMABLES"] = "INVENTORY_CONSUMABLES";
973
+ DocumentType2["INVENTORY_BOX_CARTON"] = "INVENTORY_BOX_CARTON";
974
+ DocumentType2["INVENTORY_CHEMICALS"] = "INVENTORY_CHEMICALS";
975
+ DocumentType2["STOCKTAKE"] = "STOCKTAKE";
976
+ DocumentType2["STOCKTAKE_MSDS"] = "STOCKTAKE_MSDS";
977
+ DocumentType2["MAPPING_FARM_MAPS"] = "MAPPING_FARM_MAPS";
978
+ DocumentType2["MAPPING_TRAFIC_MANAGEMENT"] = "MAPPING_TRAFIC_MANAGEMENT";
979
+ DocumentType2["MAPPING_EMERGENCY"] = "MAPPING_EMERGENCY";
980
+ DocumentType2["INCIDENT_REPORT"] = "INCIDENT_REPORT";
981
+ DocumentType2["TRAINING_RECORDS"] = "TRAINING_RECORDS";
982
+ DocumentType2["SOPS"] = "SOPS";
983
+ DocumentType2["RISK_ASSESSMENTS"] = "RISK_ASSESSMENTS";
984
+ DocumentType2["SERVICING_MAINTENANCE"] = "SERVICING_MAINTENANCE";
985
+ DocumentType2["SOIL_TEST"] = "SOIL_TEST";
986
+ DocumentType2["LEAF_TEST"] = "LEAF_TEST";
987
+ DocumentType2["WATER_TEST"] = "WATER_TEST";
988
+ DocumentType2["MRL_TESTING"] = "MRL_TESTING";
989
+ DocumentType2["HEAVY_METAL"] = "HEAVY_METAL";
990
+ DocumentType2["MICROBIAL"] = "MICROBIAL";
991
+ DocumentType2["HARVEST_LOG"] = "HARVEST_LOG";
992
+ DocumentType2["PACKHOUSE_INSPECTION"] = "PACKHOUSE_INSPECTION";
993
+ DocumentType2["TRAINING_CERTIFICATE"] = "TRAINING_CERTIFICATE";
994
+ DocumentType2["INVOICE"] = "INVOICE";
995
+ DocumentType2["LEGAL_CONTRACT"] = "LEGAL_CONTRACT";
996
+ DocumentType2["AUDIT_REPORT"] = "AUDIT_REPORT";
997
+ DocumentType2["SENSITIVE_IDENTITY"] = "SENSITIVE_IDENTITY";
998
+ return DocumentType2;
999
+ })(DocumentType || {});
1000
+ function generateDocumentPath(params) {
1001
+ const sanitizedName = params.siteName.replace(/[^a-z0-9]/gi, "_");
1002
+ if (params.isStatic) {
1003
+ return `${sanitizedName}/_CORE/${params.docType}`;
1004
+ } else {
1005
+ const folderYear = params.year || (/* @__PURE__ */ new Date()).getUTCFullYear();
1006
+ const folderCrop = params.crop ? `/${params.crop.toUpperCase()}` : "";
1007
+ return `${sanitizedName}/_SEASONAL/${folderYear}/${params.docType}${folderCrop}`;
1008
+ }
1009
+ }
1010
+ function isValueMatch(fileValue, expectedValue) {
1011
+ if (Array.isArray(expectedValue)) return expectedValue.includes(fileValue);
1012
+ return fileValue === expectedValue;
1013
+ }
1014
+ function calculateFileMetadataMatch(criteria, fileMetadata, auditContext) {
1015
+ for (const [key, expectedValue] of Object.entries(criteria.mustMatch)) {
1016
+ if (!isValueMatch(fileMetadata[key], expectedValue)) return 0;
1017
+ }
1018
+ if (criteria.mustMatchContext) {
1019
+ for (const field of criteria.mustMatchContext) {
1020
+ const contextValue = auditContext[field];
1021
+ if (contextValue === void 0) continue;
1022
+ if (!isValueMatch(fileMetadata[field], contextValue)) return 0;
1023
+ }
1024
+ }
1025
+ if (fileMetadata.isStatic === true) return 100;
1026
+ if (!criteria.contextMatch || criteria.contextMatch.length === 0) return 100;
1027
+ let matches = 0;
1028
+ let validChecks = 0;
1029
+ criteria.contextMatch.forEach((field) => {
1030
+ const contextValue = auditContext[field];
1031
+ if (contextValue === void 0) return;
1032
+ validChecks++;
1033
+ if (isValueMatch(fileMetadata[field], contextValue)) matches++;
1034
+ });
1035
+ return validChecks > 0 ? Math.round(matches / validChecks * 100) : 100;
1036
+ }
964
1037
  export {
965
1038
  ACCESS_RANK,
966
1039
  ACT,
@@ -974,6 +1047,7 @@ export {
974
1047
  CAT,
975
1048
  Converter,
976
1049
  CropCycleStatus,
1050
+ DocumentType,
977
1051
  ERROR_DICTIONARY,
978
1052
  EVERYONE,
979
1053
  EmitterType,
@@ -1014,12 +1088,14 @@ export {
1014
1088
  assertCanWrite,
1015
1089
  assertTenantBoundary,
1016
1090
  buildRlsFilter,
1091
+ calculateFileMetadataMatch,
1017
1092
  canRead,
1018
1093
  canWrite,
1019
1094
  evaluateBaseAccess,
1020
1095
  extractAppCode,
1021
1096
  findSpecificOverride,
1022
1097
  generateCanonicalId,
1098
+ generateDocumentPath,
1023
1099
  generateInfrastructureFields,
1024
1100
  getAcceptedMimeTypes,
1025
1101
  getApproveAction,
package/package.json CHANGED
@@ -1,37 +1,37 @@
1
- {
2
- "name": "@litusarchieve18/agricore-utils",
3
- "version": "1.0.10",
4
- "description": "Canonical Backend Utility Library for AgriCore",
5
- "main": "./dist/index.js",
6
- "module": "./dist/index.mjs",
7
- "types": "./dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/index.mjs",
12
- "require": "./dist/index.js",
13
- "default": "./dist/index.mjs"
14
- }
15
- },
16
- "files": [
17
- "dist"
18
- ],
19
- "scripts": {
20
- "build": "tsup src/index.ts --format cjs,esm --dts --clean",
21
- "prepublishOnly": "npm run build"
22
- },
23
- "keywords": [
24
- "agricore",
25
- "utils",
26
- "backend"
27
- ],
28
- "author": "Vincent",
29
- "license": "ISC",
30
- "devDependencies": {
31
- "tsup": "^8.0.0",
32
- "typescript": "^5.0.0"
33
- },
34
- "dependencies": {
35
- "jose": "^6.2.2"
36
- }
37
- }
1
+ {
2
+ "name": "@litusarchieve18/agricore-utils",
3
+ "version": "1.0.12",
4
+ "description": "Canonical Backend Utility Library for AgriCore",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js",
13
+ "default": "./dist/index.mjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean",
21
+ "prepublishOnly": "npm run build"
22
+ },
23
+ "keywords": [
24
+ "agricore",
25
+ "utils",
26
+ "backend"
27
+ ],
28
+ "author": "Vincent",
29
+ "license": "ISC",
30
+ "devDependencies": {
31
+ "tsup": "^8.0.0",
32
+ "typescript": "^5.0.0"
33
+ },
34
+ "dependencies": {
35
+ "jose": "^6.2.2"
36
+ }
37
+ }