onroute-policy-engine 2.3.1 → 2.4.1

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
@@ -1,51 +1,323 @@
1
- A JSON-based rules engine to validate onRouteBC permit applications against commercial vehicle policy.
1
+ # onRouteBC Policy Engine
2
2
 
3
+ A comprehensive JSON-based rules engine for validating commercial vehicle permit applications against British Columbia's transportation policy regulations.
3
4
 
4
- ## Synopsis
5
- ```orbc-policy-engine``` is a library designed to compare a commercial vehicle permit application against policy expressed in JSON format, and return a list of policy violations as well as other informational policy messages related to the permit.
5
+ [![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.7.2-blue.svg)](https://www.typescriptlang.org/)
7
+ [![Node.js](https://img.shields.io/badge/Node.js-18+-green.svg)](https://nodejs.org/)
6
8
 
7
- ```orbc-policy-engine``` makes use of https://github.com/CacheControl/json-rules-engine for rules engine functionality. Complex rules are modeled by extending the core ```json-rules-engine``` operators and other capabilities.
9
+ ## Overview
8
10
 
9
- ## Usage
10
- ```js
11
- import Policy from 'orbc-policy-engine';
11
+ The onRouteBC Policy Engine is a sophisticated validation library designed to ensure commercial vehicle permit applications comply with British Columbia's transportation regulations. It provides a flexible, rule-based system that can validate complex vehicle configurations, weight distributions, axle arrangements, and permit requirements.
12
12
 
13
- // Instantiate a new Policy object
14
- // policyDefinition is a JSON object of type PolicyDefinition
15
- const policy: Policy = new Policy(policyDefinition);
13
+ ### Key Features
16
14
 
17
- // Get list of all available permit types (ID and name)
18
- const permitTypes: Map<string, string> = policy.getPermitTypes();
15
+ - **Comprehensive Vehicle Validation**: Validates vehicle configurations, weights, dimensions, and axle arrangements
16
+ - **Policy-Driven Rules**: Uses JSON-based policy definitions for flexible rule configuration
17
+ - **Bridge Formula Calculations**: Implements provincial bridge formula requirements for axle group weight limits
18
+ - **Tire Load Validation**: Ensures tire configurations meet safety and regulatory requirements
19
+ - **Weight Distribution Checks**: Validates proper weight distribution across vehicle axles
20
+ - **Permit Type Support**: Handles multiple permit types including Term Oversize, Single Trip Oversize, and Motive Fuel
21
+ - **Commodity-Based Validation**: Supports commodity-specific permit requirements
22
+ - **Extensible Architecture**: Built on json-rules-engine with custom operators for complex validations
19
23
 
20
- // Get list of all available commodities (ID and name)
21
- const commodities: Map<string, string> = policy.getCommodities();
24
+ ## Installation
22
25
 
23
- // Get list of all available power unit types
24
- const powerUnits: Map<string, string> = policy.getPowerUnitTypes();
26
+ ```bash
27
+ npm install onroute-policy-engine
28
+ ```
29
+
30
+ ## Quick Start
31
+
32
+ ```typescript
33
+ import Policy from 'onroute-policy-engine';
34
+
35
+ // Load your policy definition
36
+ const policyDefinition = require('./policy-definition.json');
37
+
38
+ // Create policy instance
39
+ const policy = new Policy(policyDefinition);
40
+
41
+ // Validate a permit application
42
+ const permitApplication = {
43
+ permitType: 'TROS',
44
+ permitData: {
45
+ // Your permit data here
46
+ }
47
+ };
48
+
49
+ const results = await policy.validate(permitApplication);
50
+ console.log(results);
51
+ ```
52
+
53
+ ## Core Concepts
54
+
55
+ ### Policy Definition
56
+
57
+ The policy engine uses a JSON-based policy definition that describes:
58
+ - **Permit Types**: Different types of permits (TROS, STOS, MFP, etc.)
59
+ - **Vehicle Types**: Power units and trailers with their characteristics
60
+ - **Validation Rules**: Complex rules for weight, dimension, and configuration validation
61
+ - **Commodities**: Cargo types that affect permit requirements
62
+
63
+ ### Vehicle Configuration
64
+
65
+ A vehicle configuration consists of:
66
+ - **Power Units**: The primary vehicle (truck, tractor, etc.)
67
+ - **Trailers**: Additional units being towed
68
+ - **Axle Configurations**: Detailed axle arrangements with weights and dimensions
69
+
70
+ ### Validation Results
71
+
72
+ The engine returns comprehensive validation results including:
73
+ - **Policy Violations**: Specific rule violations with detailed messages
74
+ - **Informational Messages**: Guidance and recommendations
75
+ - **Axle Calculations**: Bridge formula and weight distribution results
76
+
77
+ ## API Reference
78
+
79
+ ### Main Policy Class
80
+
81
+ ```typescript
82
+ class Policy {
83
+ constructor(policyDefinition: PolicyDefinition)
84
+
85
+ // Core validation
86
+ validate(permitApplication: PermitApplication): Promise<ValidationResults>
87
+
88
+ // Vehicle configuration validation
89
+ runAxleCalculation(
90
+ vehicleConfiguration: string[],
91
+ axleConfiguration: AxleConfiguration[],
92
+ licensedGVW: number
93
+ ): AxleCalcResults
94
+
95
+ // Policy information
96
+ getPermitTypes(): Map<string, string>
97
+ getCommodities(permitTypeId?: string): Map<string, string>
98
+ getPowerUnitTypes(): Map<string, string>
99
+ getTrailerTypes(): Map<string, string>
100
+
101
+ // Vehicle configuration helpers
102
+ getNextPermittableVehicles(
103
+ permitTypeId: string,
104
+ commodityId: string,
105
+ currentConfiguration: string[]
106
+ ): Map<string, string>
107
+
108
+ // Weight and dimension calculations
109
+ getDefaultPowerUnitWeight(vehicleType: string, axleCode: number): WeightDimension[]
110
+ getDefaultTrailerWeight(vehicleType: string, axles: number): TrailerWeightDimension[]
111
+ calculateBridge(axleConfiguration: AxleConfiguration[]): BridgeCalculationResult[]
112
+ }
113
+ ```
114
+
115
+ ### Key Types
116
+
117
+ ```typescript
118
+ interface PermitApplication {
119
+ permitType: string;
120
+ permitData: any;
121
+ }
122
+
123
+ interface ValidationResults {
124
+ results: ValidationResult[];
125
+ summary: {
126
+ totalViolations: number;
127
+ totalWarnings: number;
128
+ totalInfo: number;
129
+ };
130
+ }
131
+
132
+ interface AxleConfiguration {
133
+ numberOfAxles: number;
134
+ numberOfTires?: number;
135
+ tireSize?: number;
136
+ axleUnitWeight: number;
137
+ axleSpread?: number;
138
+ }
139
+ ```
140
+
141
+ ## Usage Examples
142
+
143
+ ### Basic Permit Validation
144
+
145
+ ```typescript
146
+ import Policy from 'onroute-policy-engine';
147
+
148
+ const policy = new Policy(policyDefinition);
149
+
150
+ const permitApp = {
151
+ permitType: 'TROS',
152
+ permitData: {
153
+ vehicleConfiguration: ['TRKTRAC', 'SEMITRL'],
154
+ axleConfiguration: [
155
+ { numberOfAxles: 2, axleUnitWeight: 12000, numberOfTires: 4, tireSize: 445 },
156
+ { numberOfAxles: 3, axleUnitWeight: 34000, numberOfTires: 12, tireSize: 445 },
157
+ { numberOfAxles: 3, axleUnitWeight: 34000, numberOfTires: 12, tireSize: 445 }
158
+ ],
159
+ licensedGVW: 63500
160
+ }
161
+ };
162
+
163
+ const results = await policy.validate(permitApp);
164
+ console.log(`Validation completed with ${results.violations.length} violations`);
165
+ ```
166
+
167
+ ### Axle Calculation Validation
168
+
169
+ ```typescript
170
+ // Validate axle configuration against policy rules
171
+ const axleResults = policy.runAxleCalculation(
172
+ ['TRKTRAC', 'SEMITRL'],
173
+ [
174
+ { numberOfAxles: 2, axleUnitWeight: 12000, numberOfTires: 4, tireSize: 445 },
175
+ { numberOfAxles: 3, axleUnitWeight: 34000, numberOfTires: 12, tireSize: 445 },
176
+ { numberOfAxles: 3, axleUnitWeight: 34000, numberOfTires: 12, tireSize: 445 }
177
+ ],
178
+ 63500
179
+ );
180
+
181
+ console.log('Axle validation results:', axleResults.results);
182
+ ```
183
+
184
+ ### Getting Available Options
185
+
186
+ ```typescript
187
+ // Get all available permit types
188
+ const permitTypes = policy.getPermitTypes();
189
+ console.log('Available permit types:', Array.from(permitTypes.entries()));
190
+
191
+ // Get commodities for a specific permit type
192
+ const commodities = policy.getCommodities('TROS');
193
+ console.log('TROS commodities:', Array.from(commodities.entries()));
25
194
 
26
- // Get list of all available trailer types
27
- const trailers: Map<string, string> = policy.getTrailerTypes();
195
+ // Get valid next vehicles for a configuration
196
+ const nextVehicles = policy.getNextPermittableVehicles(
197
+ 'STOS',
198
+ 'IMCONTN',
199
+ ['TRKTRAC']
200
+ );
201
+ console.log('Valid next vehicles:', Array.from(nextVehicles.entries()));
202
+ ```
203
+
204
+ ## Policy Check Rules
205
+
206
+ The engine implements several key validation rules:
207
+
208
+ 1. **Bridge Formula Check**: Validates axle group weights based on axle spacing
209
+ 2. **Number of Wheels Per Axle**: Ensures valid tire counts per axle unit
210
+ 3. **Permittable Weight Check**: Validates axle unit weights against limits
211
+ 4. **Minimum Steer Axle Weight**: Ensures proper front axle weight distribution
212
+ 5. **Minimum Drive Axle Weight**: Validates drive axle weight requirements
213
+ 6. **Maximum Tire Load**: Checks tire load capacity based on size and quantity
214
+
215
+ For detailed information about these rules, see [Policy Check Rules Documentation](./docs/policy-check-rules.md).
216
+
217
+ ## Development
218
+
219
+ ### Prerequisites
220
+
221
+ - Node.js 18+
222
+ - TypeScript 5.7+
223
+ - npm or yarn
224
+
225
+ ### Setup
226
+
227
+ ```bash
228
+ # Clone the repository
229
+ git clone https://github.com/bcgov/onroutebc-policy-engine.git
230
+ cd onroutebc-policy-engine
231
+
232
+ # Install dependencies
233
+ npm install
234
+
235
+ # Build the project
236
+ npm run build
237
+
238
+ # Run tests
239
+ npm test
240
+
241
+ # Run linting
242
+ npm run lint
243
+ ```
244
+
245
+ ### Project Structure
246
+
247
+ ```
248
+ src/
249
+ ├── enum/ # Enumerations and constants
250
+ ├── helper/ # Helper functions and utilities
251
+ ├── types/ # TypeScript type definitions
252
+ ├── _examples/ # Usage examples and demos
253
+ ├── _test/ # Test data and configurations
254
+ ├── policy-engine.ts # Main policy engine implementation
255
+ ├── validation-result.ts # Validation result types
256
+ └── index.ts # Public API exports
257
+ ```
28
258
 
29
- // Get list of all valid commodities for a given permit type
30
- const commodities: Map<string, string> = policy.getCommodities(permitTypeId);
259
+ ### Building
31
260
 
32
- // Get list of all vehicle types valid to be added to a configuration,
33
- // by permit type and commodity. Requires supplying the vehicles already
34
- // added to the configuration, or empty array if starting from scratch
35
- const allowableVehicles: Map<string, string> = policy.getNextPermittableVehicles(
36
- permitTypeId,
37
- commodityId,
38
- currentConfiguration);
261
+ ```bash
262
+ # Clean build
263
+ npm run clean-build
39
264
 
40
- // Validate a permit application against policy
41
- // permitApplication is a JSON object of type PermitApplication
42
- // A PermitApplication is the standard permitData object wrapped
43
- // in an object with a permitType key. For example:
44
- // {
45
- // permitType: 'TROS',
46
- // permitData: { ... }
47
- // }
48
- // Note this is an async call due to the reliance on json-rules-engine
49
- const results: ValidationResults = await policy.validate(permitApplication);
265
+ # Development build
266
+ npm run build
50
267
  ```
51
268
 
269
+ ## Documentation
270
+
271
+ - [Policy Configuration Reference](./docs/policy-configuration-reference.md) - Detailed policy definition format
272
+ - [Validation Result Reference](./docs/validation-result-reference.md) - Understanding validation results
273
+ - [Basic Client-Server Flow](./docs/basic-client-server-flow.md) - Integration patterns
274
+ - [Policy Check Rules](./docs/policy-check-rules.md) - Detailed explanation of validation rules
275
+
276
+ ## Contributing
277
+
278
+ 1. Fork the repository
279
+ 2. Create a feature branch (`git checkout -b feature/new-feature`)
280
+ 3. Commit your changes (`git commit -m 'Add new feature'`)
281
+ 4. Push to the branch (`git push origin feature/new-feature`)
282
+ 5. Open a Pull Request
283
+
284
+ ### Code Style
285
+
286
+ - Follow TypeScript best practices
287
+ - Use ESLint and Prettier for code formatting
288
+ - Write comprehensive tests for new features
289
+ - Update documentation for API changes
290
+
291
+ ## Testing
292
+
293
+ ```bash
294
+ # Run all tests
295
+ npm test
296
+
297
+ # Run tests with coverage
298
+ npm test -- --coverage
299
+
300
+ # Run specific test file
301
+ npm test -- validate-tros.spec.ts
302
+ ```
303
+
304
+ ## License
305
+
306
+ This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.
307
+
308
+ ## Support
309
+
310
+ For questions, issues, or contributions:
311
+
312
+ - **Issues**: [GitHub Issues](https://github.com/bcgov/onroutebc-policy-engine/issues)
313
+ - **Documentation**: Check the [docs](./docs/) directory
314
+ - **Examples**: See [src/_examples](./src/_examples/) for usage examples
315
+
316
+ ## Related Projects
317
+
318
+ - [json-rules-engine](https://github.com/CacheControl/json-rules-engine) - Core rules engine functionality
319
+ - [onRouteBC](https://onroutebc.gov.bc.ca/) - British Columbia's commercial vehicle permitting system
320
+
321
+ ---
322
+
323
+ **Note**: This policy engine is specifically designed for British Columbia's commercial vehicle regulations. Ensure compliance with local regulations when adapting for other jurisdictions.
@@ -341,4 +341,23 @@ export declare class Policy {
341
341
  * // Returns: ['TRKTRAC']
342
342
  */
343
343
  getSimplifiedVehicleConfiguration(vehicleDetails: PermitVehicleDetails, vehicleConfiguration: VehicleConfiguration): string[];
344
+ /**
345
+ * Given a commodity and selected power unit subtype for a permit type,
346
+ * return whether or not axle units can be added to the power unit.
347
+ * @param permitType The permit type
348
+ * @param commodityId The commodity id
349
+ * @param powerUnitSubtype The id representing the power unit subtype
350
+ * @returns true if the axle units can be added to the power unit, false otherwise
351
+ */
352
+ canAddAxleUnitsToPowerUnit(permitTypeId: string, commodityId?: string | null, powerUnitSubtype?: string | null): boolean;
353
+ /**
354
+ * Given a commodity, selected power unit and trailer subtype for a permit type,
355
+ * return whether or not axle units can be added to the trailer.
356
+ * @param permitType The permit type
357
+ * @param commodityId The commodity id
358
+ * @param powerUnitSubtype The id representing the power unit subtype
359
+ * @param trailerSubtype The id representing the trailer subtype
360
+ * @returns true if the axle units can be added to the trailer, false otherwise
361
+ */
362
+ canAddAxleUnitsToTrailer(permitTypeId: string, commodityId?: string | null, powerUnitSubtype?: string | null, trailerSubtype?: string | null): boolean;
344
363
  }
@@ -858,5 +858,72 @@ class Policy {
858
858
  getSimplifiedVehicleConfiguration(vehicleDetails, vehicleConfiguration) {
859
859
  return (0, vehicles_helper_1.getSimplifiedVehicleConfigurationHelper)(vehicleDetails, vehicleConfiguration);
860
860
  }
861
+ /**
862
+ * Given a commodity and selected power unit subtype for a permit type,
863
+ * return whether or not axle units can be added to the power unit.
864
+ * @param permitType The permit type
865
+ * @param commodityId The commodity id
866
+ * @param powerUnitSubtype The id representing the power unit subtype
867
+ * @returns true if the axle units can be added to the power unit, false otherwise
868
+ */
869
+ canAddAxleUnitsToPowerUnit(permitTypeId, commodityId, powerUnitSubtype) {
870
+ if (!permitTypeId || !commodityId || !powerUnitSubtype) {
871
+ throw new Error('Missing permitTypeId and/or commodityId and/or powerUnitSubtype');
872
+ }
873
+ const permitType = this.getPermitTypeDefinition(permitTypeId);
874
+ if (!permitType) {
875
+ throw new Error(`Invalid permit type: '${permitTypeId}'`);
876
+ }
877
+ if (!permitType.commodityRequired) {
878
+ // If commodity is not required, this method cannot check whether or not
879
+ // axle units can be added, since they will not be configured.
880
+ throw new Error(`Permit type '${permitTypeId}' does not require a commodity`);
881
+ }
882
+ const commodity = this.getCommodityDefinition(commodityId);
883
+ if (!commodity) {
884
+ throw new Error(`Invalid commodity type: '${commodityId}'`);
885
+ }
886
+ const powerUnit = commodity.powerUnits.find(pu => pu.type === powerUnitSubtype);
887
+ if (!powerUnit) {
888
+ throw new Error(`Invalid power unit: '${powerUnitSubtype}'`);
889
+ }
890
+ return Boolean(powerUnit.canAddAxleUnits);
891
+ }
892
+ /**
893
+ * Given a commodity, selected power unit and trailer subtype for a permit type,
894
+ * return whether or not axle units can be added to the trailer.
895
+ * @param permitType The permit type
896
+ * @param commodityId The commodity id
897
+ * @param powerUnitSubtype The id representing the power unit subtype
898
+ * @param trailerSubtype The id representing the trailer subtype
899
+ * @returns true if the axle units can be added to the trailer, false otherwise
900
+ */
901
+ canAddAxleUnitsToTrailer(permitTypeId, commodityId, powerUnitSubtype, trailerSubtype) {
902
+ if (!permitTypeId || !commodityId || !powerUnitSubtype || !trailerSubtype) {
903
+ throw new Error('Missing permitTypeId, commodityId, powerUnitSubtype, and/or trailerSubtype');
904
+ }
905
+ const permitType = this.getPermitTypeDefinition(permitTypeId);
906
+ if (!permitType) {
907
+ throw new Error(`Invalid permit type: '${permitTypeId}'`);
908
+ }
909
+ if (!permitType.commodityRequired) {
910
+ // If commodity is not required, this method cannot check whether or not
911
+ // axle units can be added, since they will not be configured.
912
+ throw new Error(`Permit type '${permitTypeId}' does not require a commodity`);
913
+ }
914
+ const commodity = this.getCommodityDefinition(commodityId);
915
+ if (!commodity) {
916
+ throw new Error(`Invalid commodity type: '${commodityId}'`);
917
+ }
918
+ const powerUnit = commodity.powerUnits.find(pu => pu.type === powerUnitSubtype);
919
+ if (!powerUnit) {
920
+ throw new Error(`Invalid power unit: '${powerUnitSubtype}'`);
921
+ }
922
+ const trailer = powerUnit.trailers.find(trailer => trailer.type === trailerSubtype);
923
+ if (!trailer) {
924
+ throw new Error(`Invalid trailer: '${trailerSubtype}'`);
925
+ }
926
+ return Boolean(trailer.canAddAxleUnits);
927
+ }
861
928
  }
862
929
  exports.Policy = Policy;
@@ -22,6 +22,8 @@ export type VehicleDimensions = Vehicle & {
22
22
  trailers: Array<TrailerDimensions>;
23
23
  /** Array of weight dimensions for this power unit (optional) */
24
24
  weightDimensions?: Array<PowerUnitWeightDimension>;
25
+ /** Whether or not axle units can be added for this power unit (optional) */
26
+ canAddAxleUnits?: boolean;
25
27
  };
26
28
  /**
27
29
  * Trailer with booster/jeep configuration and dimension capabilities
@@ -40,4 +42,6 @@ export type TrailerDimensions = Vehicle & {
40
42
  weightDimensions?: Array<TrailerWeightDimension>;
41
43
  /** Whether weight is permittable for this trailer (optional) */
42
44
  weightPermittable?: boolean;
45
+ /** Whether or not axle units can be added for this trailer (optional) */
46
+ canAddAxleUnits?: boolean;
43
47
  };
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "v2.3.1";
1
+ export declare const version = "v2.4.1";
package/dist/version.js CHANGED
@@ -2,4 +2,4 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.version = void 0;
4
4
  // Generated by genversion.
5
- exports.version = 'v2.3.1';
5
+ exports.version = 'v2.4.1';
package/package.json CHANGED
@@ -91,5 +91,5 @@
91
91
  ],
92
92
  "testEnvironment": "node"
93
93
  },
94
- "version": "v2.3.1"
94
+ "version": "v2.4.1"
95
95
  }