@hotlap.ai/telemetry 1.1.0 → 1.3.0
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/cli.js +1 -1
- package/dist/ibt.d.ts +2 -1
- package/dist/ibt.d.ts.map +1 -1
- package/dist/ibt.js +1 -1
- package/dist/{index-tz5ph8p3.js → index-6wrtvcny.js} +38 -16
- package/dist/lap-points.d.ts +70 -0
- package/dist/lap-points.d.ts.map +1 -0
- package/dist/neutral/ibt-kagktz7r.js +6208 -0
- package/dist/neutral/ibt.js +20 -6103
- package/dist/neutral/lap-points.js +149 -0
- package/dist/neutral/session-yaml.js +20 -0
- package/dist/session-yaml.d.ts +87 -0
- package/dist/session-yaml.d.ts.map +1 -0
- package/package.json +12 -2
package/dist/cli.js
CHANGED
package/dist/ibt.d.ts
CHANGED
|
@@ -10,8 +10,10 @@ export declare class IBT {
|
|
|
10
10
|
private diskHeader;
|
|
11
11
|
private varHeaders;
|
|
12
12
|
private sessionInfoCache;
|
|
13
|
+
private static readonly sessionRegexCache;
|
|
13
14
|
private rawSessionInfo;
|
|
14
15
|
private filePath;
|
|
16
|
+
private static getSectionRegex;
|
|
15
17
|
get fileName(): string | null;
|
|
16
18
|
get varHeaderBufferTick(): number | null;
|
|
17
19
|
get varHeaderNames(): string[] | null;
|
|
@@ -33,7 +35,6 @@ export declare class IBT {
|
|
|
33
35
|
iterate(keys: string[]): Generator<Map<string, TelemetryValue>, void, unknown>;
|
|
34
36
|
getRawSessionInfo(): string | null;
|
|
35
37
|
getSessionInfo<T = unknown>(key?: string): T | null;
|
|
36
|
-
private cleanYaml;
|
|
37
38
|
}
|
|
38
39
|
export declare function parseIbt(filePath: string): Promise<IBT>;
|
|
39
40
|
export declare function parseIbtBuffer(buffer: ArrayBuffer | Uint8Array): Promise<IBT>;
|
package/dist/ibt.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ibt.d.ts","sourceRoot":"","sources":["../src/ibt.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAU,SAAS,EAAiB,cAAc,EAAe,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"ibt.d.ts","sourceRoot":"","sources":["../src/ibt.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAU,SAAS,EAAiB,cAAc,EAAe,MAAM,SAAS,CAAC;AAc7F,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,qBAAa,GAAG;IACd,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,IAAI,CAAyB;IACrC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,UAAU,CAA8B;IAChD,OAAO,CAAC,UAAU,CAAuC;IACzD,OAAO,CAAC,gBAAgB,CAAmC;IAC3D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAA6B;IACtE,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,QAAQ,CAAuB;IAEvC,OAAO,CAAC,MAAM,CAAC,eAAe;IAS9B,IAAI,QAAQ,IAAI,MAAM,GAAG,IAAI,CAE5B;IAED,IAAI,mBAAmB,IAAI,MAAM,GAAG,IAAI,CAEvC;IAED,IAAI,cAAc,IAAI,MAAM,EAAE,GAAG,IAAI,CAGpC;IAED,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,IAAI,eAAe,IAAI,MAAM,CAE5B;IAED,IAAI,gBAAgB,IAAI,MAAM,CAE7B;IAED,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAEK,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAa3C,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;WAgBnB,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC;IAUvE,KAAK,IAAI,IAAI;IAWb,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAIjD,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;IAatD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,EAAE,GAAG,IAAI;IAuB5C,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,YAAY,GAAG,UAAU,GAAG,WAAW,GAAG,IAAI;IAmCvF,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;IAgC5D,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC;IA8B/E,iBAAiB,IAAI,MAAM,GAAG,IAAI;IAYlC,cAAc,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI;CAkCpD;AAED,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAI7D;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,CAEnF"}
|
package/dist/ibt.js
CHANGED
|
@@ -14,6 +14,28 @@ import {
|
|
|
14
14
|
DISK_SUB_HEADER_OFFSET
|
|
15
15
|
} from "./index-wb6ebd0j.js";
|
|
16
16
|
|
|
17
|
+
// src/session-yaml.ts
|
|
18
|
+
var YAML_SPECIAL_FIELDS_REGEX = /((?:DriverSetupName|UserName|TeamName|AbbrevName|Initials): )(.*)/g;
|
|
19
|
+
var YAML_COMMA_VALUE_REGEX = /(\w+: )(,.*)/g;
|
|
20
|
+
function cleanYamlFast(yaml) {
|
|
21
|
+
let cleaned = "";
|
|
22
|
+
for (let i = 0;i < yaml.length; i++) {
|
|
23
|
+
const code = yaml.charCodeAt(i);
|
|
24
|
+
if (code === 129 || code === 141 || code === 143 || code === 144 || code === 157) {
|
|
25
|
+
cleaned += " ";
|
|
26
|
+
} else if (code === 9 || code === 10 || code === 13 || code >= 32 && code <= 126 || code >= 160 && code <= 255) {
|
|
27
|
+
cleaned += yaml[i];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
cleaned = cleaned.replace(YAML_SPECIAL_FIELDS_REGEX, (_, prefix, value) => {
|
|
31
|
+
const escaped = value.replace(/["\\]/g, "\\$&");
|
|
32
|
+
return `${prefix}"${escaped}"`;
|
|
33
|
+
});
|
|
34
|
+
return cleaned.replace(YAML_COMMA_VALUE_REGEX, '$1"$2"');
|
|
35
|
+
}
|
|
36
|
+
var utf8Decoder = new TextDecoder("utf-8", { fatal: false });
|
|
37
|
+
var win1252Decoder = new TextDecoder("windows-1252");
|
|
38
|
+
|
|
17
39
|
// src/ibt.ts
|
|
18
40
|
class IBT {
|
|
19
41
|
buffer = null;
|
|
@@ -22,8 +44,21 @@ class IBT {
|
|
|
22
44
|
diskHeader = null;
|
|
23
45
|
varHeaders = null;
|
|
24
46
|
sessionInfoCache = new Map;
|
|
47
|
+
static sessionRegexCache = new Map;
|
|
25
48
|
rawSessionInfo = null;
|
|
26
49
|
filePath = null;
|
|
50
|
+
static getSectionRegex(key) {
|
|
51
|
+
let regex = IBT.sessionRegexCache.get(key);
|
|
52
|
+
if (!regex) {
|
|
53
|
+
regex = new RegExp(`
|
|
54
|
+
${key}:
|
|
55
|
+
([\\s\\S]*?)(?=
|
|
56
|
+
|
|
57
|
+
|$)`);
|
|
58
|
+
IBT.sessionRegexCache.set(key, regex);
|
|
59
|
+
}
|
|
60
|
+
return regex;
|
|
61
|
+
}
|
|
27
62
|
get fileName() {
|
|
28
63
|
return this.filePath;
|
|
29
64
|
}
|
|
@@ -241,7 +276,7 @@ class IBT {
|
|
|
241
276
|
if (!key) {
|
|
242
277
|
if (!this.sessionInfoCache.has("__full__")) {
|
|
243
278
|
try {
|
|
244
|
-
const cleaned =
|
|
279
|
+
const cleaned = cleanYamlFast(raw);
|
|
245
280
|
this.sessionInfoCache.set("__full__", $parse(cleaned));
|
|
246
281
|
} catch {
|
|
247
282
|
return null;
|
|
@@ -252,17 +287,13 @@ class IBT {
|
|
|
252
287
|
if (this.sessionInfoCache.has(key)) {
|
|
253
288
|
return this.sessionInfoCache.get(key);
|
|
254
289
|
}
|
|
255
|
-
const sectionMatch = raw.match(
|
|
256
|
-
${key}:
|
|
257
|
-
([\\s\\S]*?)(?=
|
|
258
|
-
|
|
259
|
-
|$)`));
|
|
290
|
+
const sectionMatch = raw.match(IBT.getSectionRegex(key));
|
|
260
291
|
if (!sectionMatch)
|
|
261
292
|
return null;
|
|
262
293
|
try {
|
|
263
294
|
const sectionYaml = `${key}:
|
|
264
295
|
${sectionMatch[1]}`;
|
|
265
|
-
const cleaned =
|
|
296
|
+
const cleaned = cleanYamlFast(sectionYaml);
|
|
266
297
|
const parsed = $parse(cleaned);
|
|
267
298
|
const result = parsed?.[key] ?? null;
|
|
268
299
|
this.sessionInfoCache.set(key, result);
|
|
@@ -271,15 +302,6 @@ ${sectionMatch[1]}`;
|
|
|
271
302
|
return null;
|
|
272
303
|
}
|
|
273
304
|
}
|
|
274
|
-
cleanYaml(yaml) {
|
|
275
|
-
let cleaned = yaml.replace(/[\x81\x8D\x8F\x90\x9D]/g, " ").replace(/[^\x09\x0A\x0D\x20-\x7E\xA0-\xFF]/g, "");
|
|
276
|
-
cleaned = cleaned.replace(/((?:DriverSetupName|UserName|TeamName|AbbrevName|Initials): )(.*)/g, (_, prefix, value) => {
|
|
277
|
-
const escaped = value.replace(/["\\]/g, "\\$&");
|
|
278
|
-
return `${prefix}"${escaped}"`;
|
|
279
|
-
});
|
|
280
|
-
cleaned = cleaned.replace(/(\w+: )(,.*)/g, '$1"$2"');
|
|
281
|
-
return cleaned;
|
|
282
|
-
}
|
|
283
305
|
}
|
|
284
306
|
async function parseIbt(filePath) {
|
|
285
307
|
const ibt = new IBT;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical lap point extraction — produces the per-sample telemetry series
|
|
3
|
+
* (byDist / byTime) that the UI charts and the backend lap_bundles store.
|
|
4
|
+
*
|
|
5
|
+
* Output shape matches the deployed IbtLapPoint contract exactly
|
|
6
|
+
* (UI/src/lib/ibt-extract.ts and BACKEND process-job convertToIbtLapData):
|
|
7
|
+
* - Speed m/s → km/h, Throttle/Brake 0–1 → 0–100 %, SteeringWheelAngle rad → deg
|
|
8
|
+
* - distanceKm normalized per lap: (LapDist − min LapDist) / 1000
|
|
9
|
+
* - timeSec normalized per lap: SessionTime − min SessionTime
|
|
10
|
+
* - tire temps LFtempM.. with LFtempCM.. carcass fallback (process-job behavior)
|
|
11
|
+
*
|
|
12
|
+
* CANONICAL DECISION — tire wear is percent 0–100 (×100 from the raw 0–1
|
|
13
|
+
* channel), matching process-job and therefore every stored lap bundle. The
|
|
14
|
+
* UI's ibt-extract.ts left wear at raw 0–1; that was the divergent one.
|
|
15
|
+
*
|
|
16
|
+
* RFC-0001 C8: extraction runs at FULL resolution; downsampling to maxPoints
|
|
17
|
+
* happens last and is presentation-only — never an input to metrics.
|
|
18
|
+
*
|
|
19
|
+
* RUNTIME NEUTRALITY: this module must not import Bun/Deno/Node APIs.
|
|
20
|
+
*/
|
|
21
|
+
import type { IbtSource, NormalizedLap } from './normalize';
|
|
22
|
+
/** Matches the UI/backend IbtLapPoint contract field-for-field. */
|
|
23
|
+
export interface LapPoint {
|
|
24
|
+
distanceKm: number;
|
|
25
|
+
timeSec: number;
|
|
26
|
+
speedKmh: number | null;
|
|
27
|
+
throttlePct: number | null;
|
|
28
|
+
brakePct: number | null;
|
|
29
|
+
brakeABSactive: boolean | null;
|
|
30
|
+
gear: number | null;
|
|
31
|
+
rpm: number | null;
|
|
32
|
+
steeringDeg: number | null;
|
|
33
|
+
lat: number | null;
|
|
34
|
+
lon: number | null;
|
|
35
|
+
altitudeM: number | null;
|
|
36
|
+
tireTempLF: number | null;
|
|
37
|
+
tireTempRF: number | null;
|
|
38
|
+
tireTempLR: number | null;
|
|
39
|
+
tireTempRR: number | null;
|
|
40
|
+
tirePressureLF: number | null;
|
|
41
|
+
tirePressureRF: number | null;
|
|
42
|
+
tirePressureLR: number | null;
|
|
43
|
+
tirePressureRR: number | null;
|
|
44
|
+
tireWearLF: number | null;
|
|
45
|
+
tireWearRF: number | null;
|
|
46
|
+
tireWearLR: number | null;
|
|
47
|
+
tireWearRR: number | null;
|
|
48
|
+
}
|
|
49
|
+
export interface ExtractLapPointsResult {
|
|
50
|
+
/** Points sorted ascending by distanceKm (downsampled). */
|
|
51
|
+
byDist: LapPoint[];
|
|
52
|
+
/** Points sorted ascending by timeSec (downsampled). */
|
|
53
|
+
byTime: LapPoint[];
|
|
54
|
+
/** Number of valid full-resolution points before downsampling. */
|
|
55
|
+
downsampledFrom: number;
|
|
56
|
+
}
|
|
57
|
+
export interface ExtractLapPointsOptions {
|
|
58
|
+
/** Maximum points per series after downsampling. Default 500. */
|
|
59
|
+
maxPoints?: number;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Extract the telemetry point series for one normalized lap.
|
|
63
|
+
*
|
|
64
|
+
* Iterates lap.firstSampleIndex..lastSampleIndex; when the Lap / SessionNum
|
|
65
|
+
* channels are available, only indices whose Lap equals lap.lapNumber (and
|
|
66
|
+
* whose SessionNum matches the lap's own session, read at firstSampleIndex)
|
|
67
|
+
* are honored. Without those channels the whole contiguous range is accepted.
|
|
68
|
+
*/
|
|
69
|
+
export declare function extractLapPoints(source: IbtSource, lap: NormalizedLap, opts?: ExtractLapPointsOptions): ExtractLapPointsResult;
|
|
70
|
+
//# sourceMappingURL=lap-points.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lap-points.d.ts","sourceRoot":"","sources":["../src/lap-points.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAM5D,mEAAmE;AACnE,MAAM,WAAW,QAAQ;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,cAAc,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACrC,2DAA2D;IAC3D,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,wDAAwD;IACxD,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,kEAAkE;IAClE,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,uBAAuB;IACtC,iEAAiE;IACjE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA8CD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,aAAa,EAClB,IAAI,CAAC,EAAE,uBAAuB,GAC7B,sBAAsB,CA8IxB"}
|