@7365admin1/core 3.52.6-staging.252 → 3.52.6

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/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @iservice365/core
2
2
 
3
+ ## 3.52.6
4
+
5
+ ### Patch Changes
6
+
7
+ - 3c13b1f: Spreadsheet vehicle import is fail-closed. `bulkUpsertVehicles` wrote every row to the database whatever the ANPR cameras answered, so an imported blocklist plate that no camera accepted was saved as blocked while the car still opened the barrier. Rows are now run through the shared `sweepExpiredVehicles` decision — every camera must confirm — and only confirmed rows are saved; the rest are rolled back off any camera that did take them and returned in `failedRows` with the camera and the reason.
8
+ - 33d649a: Fix the expired-vehicle sweep never matching a genuine expiry
9
+
10
+ `vehicles.end` is written as a BSON Date, but both `getAllExpiredVehicles` and
11
+ `deleteExpiredVehicles` compared it against `new Date().toISOString()` - a
12
+ String. String sorts before Date in BSON canonical type order, so a Date is
13
+ never `$lte` a String: the hourly cron has never selected a genuinely expired
14
+ vehicle, and a season pass that expired kept opening the barrier indefinitely.
15
+ Measured read-only on staging: the old query returned 0 rows while 3 vehicles
16
+ whose `end` had passed were still live.
17
+
18
+ The only rows it ever did match were the ones whose `end` was the string `""` -
19
+ no expiry at all - which is the opposite of the rule. Nine such rows were
20
+ deleted at one site in a single run on 2026-09-01.
21
+
22
+ Both queries now share `expiredVehicleSweepFilter(now)` in `vehicle.model.ts`,
23
+ which compares a Date with a Date and requires `$type: "date"`, so a blank or
24
+ missing expiry is never swept. `MVehicle` also no longer stores a blank expiry
25
+ as `""`: `value.end ?? expiredDate` kept the empty string because `??` only
26
+ falls through on null/undefined, which is where the non-Date values came from.
27
+ A blank expiry now takes the same createdAt + 10 years sentinel as a null one.
28
+
29
+ No backfill: existing rows are unchanged.
30
+
3
31
  ## 3.52.5
4
32
 
5
33
  ### Patch Changes
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@7365admin1/core",
3
3
  "license": "MIT",
4
- "version": "3.52.6-staging.252",
4
+ "version": "3.52.6",
5
5
  "author": "7365admin1",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.mjs",
@@ -1,5 +0,0 @@
1
- ---
2
- "@7365admin1/core": patch
3
- ---
4
-
5
- Spreadsheet vehicle import is fail-closed. `bulkUpsertVehicles` wrote every row to the database whatever the ANPR cameras answered, so an imported blocklist plate that no camera accepted was saved as blocked while the car still opened the barrier. Rows are now run through the shared `sweepExpiredVehicles` decision — every camera must confirm — and only confirmed rows are saved; the rest are rolled back off any camera that did take them and returned in `failedRows` with the camera and the reason.
@@ -1,26 +0,0 @@
1
- ---
2
- "@7365admin1/core": patch
3
- ---
4
-
5
- Fix the expired-vehicle sweep never matching a genuine expiry
6
-
7
- `vehicles.end` is written as a BSON Date, but both `getAllExpiredVehicles` and
8
- `deleteExpiredVehicles` compared it against `new Date().toISOString()` - a
9
- String. String sorts before Date in BSON canonical type order, so a Date is
10
- never `$lte` a String: the hourly cron has never selected a genuinely expired
11
- vehicle, and a season pass that expired kept opening the barrier indefinitely.
12
- Measured read-only on staging: the old query returned 0 rows while 3 vehicles
13
- whose `end` had passed were still live.
14
-
15
- The only rows it ever did match were the ones whose `end` was the string `""` -
16
- no expiry at all - which is the opposite of the rule. Nine such rows were
17
- deleted at one site in a single run on 2026-09-01.
18
-
19
- Both queries now share `expiredVehicleSweepFilter(now)` in `vehicle.model.ts`,
20
- which compares a Date with a Date and requires `$type: "date"`, so a blank or
21
- missing expiry is never swept. `MVehicle` also no longer stores a blank expiry
22
- as `""`: `value.end ?? expiredDate` kept the empty string because `??` only
23
- falls through on null/undefined, which is where the non-Date values came from.
24
- A blank expiry now takes the same createdAt + 10 years sentinel as a null one.
25
-
26
- No backfill: existing rows are unchanged.