@ottolab/bio-age 0.1.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/__tests__/kdm.test.ts +187 -0
- package/__tests__/pheno-age.test.ts +371 -0
- package/__tests__/utils.test.ts +67 -0
- package/package.json +29 -0
- package/src/index.ts +21 -0
- package/src/kdm.ts +129 -0
- package/src/pheno-age.ts +284 -0
- package/src/utils.ts +13 -0
- package/tsconfig.json +10 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { calculateKDM, KDM_REGRESSIONS, AGE_VARIANCE } from '../src/kdm.js';
|
|
3
|
+
import type { KDMInput } from '../src/kdm.js';
|
|
4
|
+
|
|
5
|
+
// Reference healthy 50-year-old with typical biomarkers
|
|
6
|
+
const HEALTHY_50: KDMInput = {
|
|
7
|
+
chronologicalAge: 50,
|
|
8
|
+
albumin: 4.0,
|
|
9
|
+
creatinine: 0.96,
|
|
10
|
+
glucose: 97,
|
|
11
|
+
lnCRP: -0.94,
|
|
12
|
+
lymphocytePercent: 30,
|
|
13
|
+
mcv: 90,
|
|
14
|
+
rdw: 13.3,
|
|
15
|
+
alp: 75,
|
|
16
|
+
wbc: 7.0,
|
|
17
|
+
systolicBP: 120,
|
|
18
|
+
bun: 14,
|
|
19
|
+
hba1c: 5.5,
|
|
20
|
+
totalCholesterol: 200,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Unhealthy profile with accelerated aging markers
|
|
24
|
+
const UNHEALTHY_50: KDMInput = {
|
|
25
|
+
chronologicalAge: 50,
|
|
26
|
+
albumin: 3.2,
|
|
27
|
+
creatinine: 1.4,
|
|
28
|
+
glucose: 145,
|
|
29
|
+
lnCRP: 1.0,
|
|
30
|
+
lymphocytePercent: 18,
|
|
31
|
+
mcv: 98,
|
|
32
|
+
rdw: 15.5,
|
|
33
|
+
alp: 130,
|
|
34
|
+
wbc: 10.5,
|
|
35
|
+
systolicBP: 155,
|
|
36
|
+
bun: 25,
|
|
37
|
+
hba1c: 7.0,
|
|
38
|
+
totalCholesterol: 260,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
describe('KDM_REGRESSIONS', () => {
|
|
42
|
+
it('should have 13 biomarker regressions', () => {
|
|
43
|
+
expect(Object.keys(KDM_REGRESSIONS).length).toBe(13);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should have positive residual SD for all markers', () => {
|
|
47
|
+
for (const [, reg] of Object.entries(KDM_REGRESSIONS)) {
|
|
48
|
+
expect(reg.s).toBeGreaterThan(0);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should have albumin declining with age (negative slope)', () => {
|
|
53
|
+
expect(KDM_REGRESSIONS.albumin.k).toBeLessThan(0);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should have systolic BP increasing with age (positive slope)', () => {
|
|
57
|
+
expect(KDM_REGRESSIONS.systolicBP.k).toBeGreaterThan(0);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should export AGE_VARIANCE as a positive number', () => {
|
|
61
|
+
expect(AGE_VARIANCE).toBeGreaterThan(0);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe('calculateKDM', () => {
|
|
66
|
+
it('should return a reasonable KDM age for a healthy 50-year-old', () => {
|
|
67
|
+
const result = calculateKDM(HEALTHY_50);
|
|
68
|
+
expect(result.kdmAge).toBeGreaterThan(30);
|
|
69
|
+
expect(result.kdmAge).toBeLessThan(70);
|
|
70
|
+
expect(result.markersUsed).toBe(13);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('delta should equal kdmAge - chronologicalAge', () => {
|
|
74
|
+
const result = calculateKDM(HEALTHY_50);
|
|
75
|
+
expect(result.delta).toBeCloseTo(result.kdmAge - 50, 1);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should show older KDM age for unhealthy biomarkers', () => {
|
|
79
|
+
const healthy = calculateKDM(HEALTHY_50);
|
|
80
|
+
const unhealthy = calculateKDM(UNHEALTHY_50);
|
|
81
|
+
expect(unhealthy.kdmAge).toBeGreaterThan(healthy.kdmAge);
|
|
82
|
+
expect(unhealthy.delta).toBeGreaterThan(healthy.delta);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should work with minimum 3 markers', () => {
|
|
86
|
+
const minimal: KDMInput = {
|
|
87
|
+
chronologicalAge: 45,
|
|
88
|
+
albumin: 4.0,
|
|
89
|
+
glucose: 95,
|
|
90
|
+
systolicBP: 118,
|
|
91
|
+
};
|
|
92
|
+
const result = calculateKDM(minimal);
|
|
93
|
+
expect(result.markersUsed).toBe(3);
|
|
94
|
+
expect(Number.isFinite(result.kdmAge)).toBe(true);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('should throw with fewer than 3 markers', () => {
|
|
98
|
+
const tooFew: KDMInput = {
|
|
99
|
+
chronologicalAge: 45,
|
|
100
|
+
albumin: 4.0,
|
|
101
|
+
glucose: 95,
|
|
102
|
+
};
|
|
103
|
+
expect(() => calculateKDM(tooFew)).toThrow('at least 3 biomarkers');
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('should throw with only chronological age', () => {
|
|
107
|
+
expect(() => calculateKDM({ chronologicalAge: 45 })).toThrow('at least 3 biomarkers');
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should return rounded values to 2 decimal places', () => {
|
|
111
|
+
const result = calculateKDM(HEALTHY_50);
|
|
112
|
+
expect(result.kdmAge).toBe(Math.round(result.kdmAge * 100) / 100);
|
|
113
|
+
expect(result.delta).toBe(Math.round(result.delta * 100) / 100);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should work for a young person (age 25)', () => {
|
|
117
|
+
const young: KDMInput = {
|
|
118
|
+
chronologicalAge: 25,
|
|
119
|
+
albumin: 4.5,
|
|
120
|
+
creatinine: 0.85,
|
|
121
|
+
glucose: 85,
|
|
122
|
+
lnCRP: -1.5,
|
|
123
|
+
lymphocytePercent: 33,
|
|
124
|
+
mcv: 88,
|
|
125
|
+
rdw: 12.5,
|
|
126
|
+
alp: 65,
|
|
127
|
+
wbc: 6.5,
|
|
128
|
+
systolicBP: 110,
|
|
129
|
+
bun: 12,
|
|
130
|
+
hba1c: 5.1,
|
|
131
|
+
totalCholesterol: 175,
|
|
132
|
+
};
|
|
133
|
+
const result = calculateKDM(young);
|
|
134
|
+
expect(result.kdmAge).toBeGreaterThan(10);
|
|
135
|
+
expect(result.kdmAge).toBeLessThan(45);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should work for elderly person (age 80)', () => {
|
|
139
|
+
const elderly: KDMInput = {
|
|
140
|
+
chronologicalAge: 80,
|
|
141
|
+
albumin: 3.5,
|
|
142
|
+
creatinine: 1.1,
|
|
143
|
+
glucose: 115,
|
|
144
|
+
lnCRP: 0.5,
|
|
145
|
+
lymphocytePercent: 22,
|
|
146
|
+
mcv: 94,
|
|
147
|
+
rdw: 14.5,
|
|
148
|
+
alp: 95,
|
|
149
|
+
wbc: 6.0,
|
|
150
|
+
systolicBP: 145,
|
|
151
|
+
bun: 20,
|
|
152
|
+
hba1c: 5.9,
|
|
153
|
+
totalCholesterol: 210,
|
|
154
|
+
};
|
|
155
|
+
const result = calculateKDM(elderly);
|
|
156
|
+
expect(result.kdmAge).toBeGreaterThan(60);
|
|
157
|
+
expect(Number.isFinite(result.kdmAge)).toBe(true);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('should handle partial marker sets (5-6 markers)', () => {
|
|
161
|
+
const partial: KDMInput = {
|
|
162
|
+
chronologicalAge: 40,
|
|
163
|
+
glucose: 100,
|
|
164
|
+
hba1c: 5.6,
|
|
165
|
+
systolicBP: 125,
|
|
166
|
+
albumin: 4.1,
|
|
167
|
+
creatinine: 0.9,
|
|
168
|
+
};
|
|
169
|
+
const result = calculateKDM(partial);
|
|
170
|
+
expect(result.markersUsed).toBe(5);
|
|
171
|
+
expect(Number.isFinite(result.kdmAge)).toBe(true);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('should produce consistent results (deterministic)', () => {
|
|
175
|
+
const r1 = calculateKDM(HEALTHY_50);
|
|
176
|
+
const r2 = calculateKDM(HEALTHY_50);
|
|
177
|
+
expect(r1.kdmAge).toBe(r2.kdmAge);
|
|
178
|
+
expect(r1.delta).toBe(r2.delta);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('should be sensitive to individual marker changes', () => {
|
|
182
|
+
const base = calculateKDM(HEALTHY_50);
|
|
183
|
+
const highBP = calculateKDM({ ...HEALTHY_50, systolicBP: 160 });
|
|
184
|
+
// Higher BP should increase KDM age
|
|
185
|
+
expect(highBP.kdmAge).toBeGreaterThan(base.kdmAge);
|
|
186
|
+
});
|
|
187
|
+
});
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
calculatePhenoAge,
|
|
4
|
+
calculateMetabolicProxy,
|
|
5
|
+
computeLinearPredictor,
|
|
6
|
+
computeMortalityScore,
|
|
7
|
+
invertToPhenoAge,
|
|
8
|
+
convertToPhenoAgeUnits,
|
|
9
|
+
PHENO_AGE_COEFFICIENTS,
|
|
10
|
+
GAMMA,
|
|
11
|
+
} from '../src/pheno-age.js';
|
|
12
|
+
import type { PhenoAgeInput, MetabolicProxyInput } from '../src/pheno-age.js';
|
|
13
|
+
|
|
14
|
+
// Reference healthy 40-year-old with population-mean biomarkers
|
|
15
|
+
// Glucose in mmol/L (5.42 ≈ 97.7 mg/dL)
|
|
16
|
+
const HEALTHY_40: PhenoAgeInput = {
|
|
17
|
+
chronologicalAge: 40,
|
|
18
|
+
albumin: 4.0, // g/dL
|
|
19
|
+
creatinine: 0.96, // mg/dL
|
|
20
|
+
glucose: 5.42, // mmol/L (~97.7 mg/dL)
|
|
21
|
+
lnCRP: -0.94, // ln(CRP) ~ 0.39 mg/dL
|
|
22
|
+
lymphocytePercent: 30.3,
|
|
23
|
+
mcv: 89.5, // fL
|
|
24
|
+
rdw: 13.3, // %
|
|
25
|
+
alp: 78.5, // U/L
|
|
26
|
+
wbc: 7.1, // 10^3/uL
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// Unhealthy profile: elevated glucose, CRP, low albumin
|
|
30
|
+
const UNHEALTHY_55: PhenoAgeInput = {
|
|
31
|
+
chronologicalAge: 55,
|
|
32
|
+
albumin: 3.2,
|
|
33
|
+
creatinine: 1.3,
|
|
34
|
+
glucose: 7.77, // mmol/L (~140 mg/dL)
|
|
35
|
+
lnCRP: 1.1, // CRP ~ 3 mg/dL
|
|
36
|
+
lymphocytePercent: 18,
|
|
37
|
+
mcv: 98,
|
|
38
|
+
rdw: 15.5,
|
|
39
|
+
alp: 120,
|
|
40
|
+
wbc: 10.5,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
describe('PHENO_AGE_COEFFICIENTS', () => {
|
|
44
|
+
it('should have correct Levine 2018 values', () => {
|
|
45
|
+
expect(PHENO_AGE_COEFFICIENTS.intercept).toBe(-19.9067);
|
|
46
|
+
expect(PHENO_AGE_COEFFICIENTS.albumin).toBe(-0.0336);
|
|
47
|
+
expect(PHENO_AGE_COEFFICIENTS.creatinine).toBe(0.0095);
|
|
48
|
+
expect(PHENO_AGE_COEFFICIENTS.glucose).toBe(0.1953);
|
|
49
|
+
expect(PHENO_AGE_COEFFICIENTS.lnCRP).toBe(0.0954);
|
|
50
|
+
expect(PHENO_AGE_COEFFICIENTS.lymphocytePercent).toBe(-0.012);
|
|
51
|
+
expect(PHENO_AGE_COEFFICIENTS.mcv).toBe(0.0268);
|
|
52
|
+
expect(PHENO_AGE_COEFFICIENTS.rdw).toBe(0.3306);
|
|
53
|
+
expect(PHENO_AGE_COEFFICIENTS.alp).toBe(0.00188);
|
|
54
|
+
expect(PHENO_AGE_COEFFICIENTS.wbc).toBe(0.0554);
|
|
55
|
+
expect(PHENO_AGE_COEFFICIENTS.age).toBe(0.0804);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should export gamma constant', () => {
|
|
59
|
+
expect(GAMMA).toBe(0.0076927);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('computeLinearPredictor', () => {
|
|
64
|
+
it('should compute xb from coefficients and markers', () => {
|
|
65
|
+
const xb = computeLinearPredictor(HEALTHY_40);
|
|
66
|
+
expect(typeof xb).toBe('number');
|
|
67
|
+
expect(Number.isFinite(xb)).toBe(true);
|
|
68
|
+
// With population-mean markers, xb should be negative (reasonable mortality)
|
|
69
|
+
expect(xb).toBeLessThan(0);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should increase with worse biomarkers', () => {
|
|
73
|
+
const xbHealthy = computeLinearPredictor(HEALTHY_40);
|
|
74
|
+
const xbUnhealthy = computeLinearPredictor(UNHEALTHY_55);
|
|
75
|
+
expect(xbUnhealthy).toBeGreaterThan(xbHealthy);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should be linear: changing one marker shifts xb proportionally', () => {
|
|
79
|
+
const base = computeLinearPredictor(HEALTHY_40);
|
|
80
|
+
const withHighGlucose = computeLinearPredictor({ ...HEALTHY_40, glucose: 7.42 }); // +2 mmol/L
|
|
81
|
+
const diff = withHighGlucose - base;
|
|
82
|
+
expect(diff).toBeCloseTo(2 * PHENO_AGE_COEFFICIENTS.glucose, 4);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe('computeMortalityScore', () => {
|
|
87
|
+
it('should return a value between 0 and 1 for typical xb', () => {
|
|
88
|
+
// Healthy xb is around -8 to -9
|
|
89
|
+
const m = computeMortalityScore(-9);
|
|
90
|
+
expect(m).toBeGreaterThan(0);
|
|
91
|
+
expect(m).toBeLessThan(1);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should increase monotonically with xb', () => {
|
|
95
|
+
const m1 = computeMortalityScore(-12);
|
|
96
|
+
const m2 = computeMortalityScore(-10);
|
|
97
|
+
const m3 = computeMortalityScore(-8);
|
|
98
|
+
expect(m2).toBeGreaterThan(m1);
|
|
99
|
+
expect(m3).toBeGreaterThan(m2);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('should approach 1 for very high xb', () => {
|
|
103
|
+
const m = computeMortalityScore(0);
|
|
104
|
+
expect(m).toBeGreaterThan(0.99);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should be near 0 for very low xb', () => {
|
|
108
|
+
const m = computeMortalityScore(-20);
|
|
109
|
+
expect(m).toBeLessThan(0.01);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe('invertToPhenoAge', () => {
|
|
114
|
+
it('should produce a finite age for typical mortality scores', () => {
|
|
115
|
+
const age = invertToPhenoAge(0.5);
|
|
116
|
+
expect(Number.isFinite(age)).toBe(true);
|
|
117
|
+
expect(age).toBeGreaterThan(0);
|
|
118
|
+
expect(age).toBeLessThan(150);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should increase monotonically with mortality score', () => {
|
|
122
|
+
const a1 = invertToPhenoAge(0.3);
|
|
123
|
+
const a2 = invertToPhenoAge(0.5);
|
|
124
|
+
const a3 = invertToPhenoAge(0.8);
|
|
125
|
+
expect(a2).toBeGreaterThan(a1);
|
|
126
|
+
expect(a3).toBeGreaterThan(a2);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('should handle edge values near 0 and 1', () => {
|
|
130
|
+
const low = invertToPhenoAge(0.001);
|
|
131
|
+
const high = invertToPhenoAge(0.999);
|
|
132
|
+
expect(Number.isFinite(low)).toBe(true);
|
|
133
|
+
expect(Number.isFinite(high)).toBe(true);
|
|
134
|
+
expect(high).toBeGreaterThan(low);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe('calculatePhenoAge', () => {
|
|
139
|
+
it('should return a reasonable PhenoAge for a healthy 40-year-old', () => {
|
|
140
|
+
const result = calculatePhenoAge(HEALTHY_40);
|
|
141
|
+
expect(result.isProxy).toBe(false);
|
|
142
|
+
expect(result.phenoAge).toBeGreaterThan(20);
|
|
143
|
+
expect(result.phenoAge).toBeLessThan(60);
|
|
144
|
+
// Delta should be moderate for population-mean markers
|
|
145
|
+
expect(Math.abs(result.delta)).toBeLessThan(15);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('should show older PhenoAge for unhealthy biomarkers', () => {
|
|
149
|
+
const healthy = calculatePhenoAge(HEALTHY_40);
|
|
150
|
+
const unhealthy = calculatePhenoAge(UNHEALTHY_55);
|
|
151
|
+
// Unhealthy person should have a larger delta (more accelerated aging)
|
|
152
|
+
expect(unhealthy.delta).toBeGreaterThan(healthy.delta);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('should have higher mortality score for unhealthy profile', () => {
|
|
156
|
+
const healthy = calculatePhenoAge(HEALTHY_40);
|
|
157
|
+
const unhealthy = calculatePhenoAge(UNHEALTHY_55);
|
|
158
|
+
expect(unhealthy.mortalityScore).toBeGreaterThan(healthy.mortalityScore);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('should return rounded values to 2 decimal places', () => {
|
|
162
|
+
const result = calculatePhenoAge(HEALTHY_40);
|
|
163
|
+
expect(result.phenoAge).toBe(Math.round(result.phenoAge * 100) / 100);
|
|
164
|
+
expect(result.delta).toBe(Math.round(result.delta * 100) / 100);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('should include driver analysis', () => {
|
|
168
|
+
const result = calculatePhenoAge(HEALTHY_40);
|
|
169
|
+
expect(result.drivers).toBeDefined();
|
|
170
|
+
expect(result.drivers!.length).toBe(9); // 9 biomarkers
|
|
171
|
+
for (const d of result.drivers!) {
|
|
172
|
+
expect(['aging', 'protective']).toContain(d.direction);
|
|
173
|
+
expect(typeof d.contribution).toBe('number');
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('should sort drivers by absolute contribution', () => {
|
|
178
|
+
const result = calculatePhenoAge(UNHEALTHY_55);
|
|
179
|
+
const drivers = result.drivers!;
|
|
180
|
+
for (let i = 1; i < drivers.length; i++) {
|
|
181
|
+
expect(Math.abs(drivers[i - 1].contribution)).toBeGreaterThanOrEqual(
|
|
182
|
+
Math.abs(drivers[i].contribution),
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('delta should equal phenoAge - chronologicalAge', () => {
|
|
188
|
+
const result = calculatePhenoAge(HEALTHY_40);
|
|
189
|
+
expect(result.delta).toBeCloseTo(result.phenoAge - 40, 1);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('should work for a young person (age 20)', () => {
|
|
193
|
+
const young = { ...HEALTHY_40, chronologicalAge: 20 };
|
|
194
|
+
const result = calculatePhenoAge(young);
|
|
195
|
+
expect(result.phenoAge).toBeGreaterThan(0);
|
|
196
|
+
expect(Number.isFinite(result.phenoAge)).toBe(true);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('should work for an elderly person (age 85)', () => {
|
|
200
|
+
const elderly: PhenoAgeInput = {
|
|
201
|
+
chronologicalAge: 85,
|
|
202
|
+
albumin: 3.5,
|
|
203
|
+
creatinine: 1.1,
|
|
204
|
+
glucose: 6.11, // mmol/L (~110 mg/dL)
|
|
205
|
+
lnCRP: 0.5,
|
|
206
|
+
lymphocytePercent: 22,
|
|
207
|
+
mcv: 94,
|
|
208
|
+
rdw: 14.8,
|
|
209
|
+
alp: 95,
|
|
210
|
+
wbc: 6.5,
|
|
211
|
+
};
|
|
212
|
+
const result = calculatePhenoAge(elderly);
|
|
213
|
+
expect(result.phenoAge).toBeGreaterThan(60);
|
|
214
|
+
expect(Number.isFinite(result.phenoAge)).toBe(true);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('should produce a larger delta when glucose is elevated', () => {
|
|
218
|
+
const normal = calculatePhenoAge(HEALTHY_40);
|
|
219
|
+
const highGlucose = calculatePhenoAge({ ...HEALTHY_40, glucose: 8.0 }); // ~144 mg/dL
|
|
220
|
+
expect(highGlucose.delta).toBeGreaterThan(normal.delta);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('should produce a larger delta when CRP is elevated', () => {
|
|
224
|
+
const normal = calculatePhenoAge(HEALTHY_40);
|
|
225
|
+
const highCRP = calculatePhenoAge({ ...HEALTHY_40, lnCRP: 1.5 }); // CRP ~4.5 mg/dL
|
|
226
|
+
expect(highCRP.delta).toBeGreaterThan(normal.delta);
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
describe('calculateMetabolicProxy', () => {
|
|
231
|
+
it('should return isProxy = true', () => {
|
|
232
|
+
const result = calculateMetabolicProxy({ chronologicalAge: 40 });
|
|
233
|
+
expect(result.isProxy).toBe(true);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it('should return chronological age when no markers provided', () => {
|
|
237
|
+
const result = calculateMetabolicProxy({ chronologicalAge: 40 });
|
|
238
|
+
expect(result.phenoAge).toBe(40);
|
|
239
|
+
expect(result.delta).toBe(0);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('should show positive delta for unhealthy metabolic markers', () => {
|
|
243
|
+
const input: MetabolicProxyInput = {
|
|
244
|
+
chronologicalAge: 45,
|
|
245
|
+
glucose: 140, // high
|
|
246
|
+
hba1c: 6.8, // high
|
|
247
|
+
hsCrp: 8.0, // high
|
|
248
|
+
triglycerides: 300, // high
|
|
249
|
+
hdl: 35, // low
|
|
250
|
+
fastingInsulin: 20, // high
|
|
251
|
+
uricAcid: 8.0, // high
|
|
252
|
+
};
|
|
253
|
+
const result = calculateMetabolicProxy(input);
|
|
254
|
+
expect(result.delta).toBeGreaterThan(0);
|
|
255
|
+
expect(result.phenoAge).toBeGreaterThan(45);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('should show negative delta for excellent metabolic markers', () => {
|
|
259
|
+
const input: MetabolicProxyInput = {
|
|
260
|
+
chronologicalAge: 50,
|
|
261
|
+
glucose: 80,
|
|
262
|
+
hba1c: 4.9,
|
|
263
|
+
hsCrp: 0.3,
|
|
264
|
+
triglycerides: 60,
|
|
265
|
+
hdl: 75,
|
|
266
|
+
fastingInsulin: 3,
|
|
267
|
+
uricAcid: 3.5,
|
|
268
|
+
};
|
|
269
|
+
const result = calculateMetabolicProxy(input);
|
|
270
|
+
expect(result.delta).toBeLessThan(0);
|
|
271
|
+
expect(result.phenoAge).toBeLessThan(50);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('should clamp delta to [-10, +15]', () => {
|
|
275
|
+
const extreme: MetabolicProxyInput = {
|
|
276
|
+
chronologicalAge: 40,
|
|
277
|
+
glucose: 300,
|
|
278
|
+
hba1c: 12,
|
|
279
|
+
hsCrp: 50,
|
|
280
|
+
triglycerides: 800,
|
|
281
|
+
fastingInsulin: 60,
|
|
282
|
+
uricAcid: 15,
|
|
283
|
+
};
|
|
284
|
+
const result = calculateMetabolicProxy(extreme);
|
|
285
|
+
expect(result.delta).toBeLessThanOrEqual(15);
|
|
286
|
+
expect(result.delta).toBeGreaterThanOrEqual(-10);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it('should work with a subset of markers', () => {
|
|
290
|
+
const partial: MetabolicProxyInput = {
|
|
291
|
+
chronologicalAge: 35,
|
|
292
|
+
glucose: 95,
|
|
293
|
+
hsCrp: 1.5,
|
|
294
|
+
};
|
|
295
|
+
const result = calculateMetabolicProxy(partial);
|
|
296
|
+
expect(Number.isFinite(result.phenoAge)).toBe(true);
|
|
297
|
+
expect(result.isProxy).toBe(true);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it('should return rounded values', () => {
|
|
301
|
+
const input: MetabolicProxyInput = {
|
|
302
|
+
chronologicalAge: 40,
|
|
303
|
+
glucose: 110,
|
|
304
|
+
hba1c: 5.8,
|
|
305
|
+
};
|
|
306
|
+
const result = calculateMetabolicProxy(input);
|
|
307
|
+
expect(result.phenoAge).toBe(Math.round(result.phenoAge * 100) / 100);
|
|
308
|
+
expect(result.delta).toBe(Math.round(result.delta * 100) / 100);
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
describe('convertToPhenoAgeUnits', () => {
|
|
313
|
+
it('should convert albumin from g/L to g/dL', () => {
|
|
314
|
+
const result = convertToPhenoAgeUnits({ albumin_gL: 40 });
|
|
315
|
+
expect(result.albumin).toBeCloseTo(4.0, 4);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
it('should convert creatinine from umol/L to mg/dL', () => {
|
|
319
|
+
const result = convertToPhenoAgeUnits({ creatinine_umolL: 88.4 });
|
|
320
|
+
expect(result.creatinine).toBeCloseTo(1.0, 2);
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it('should convert glucose from mg/dL to mmol/L', () => {
|
|
324
|
+
const result = convertToPhenoAgeUnits({ glucose_mgDL: 90 });
|
|
325
|
+
expect(result.glucose).toBeCloseTo(90 / 18.0182, 2);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it('should pass through glucose in mmol/L', () => {
|
|
329
|
+
const result = convertToPhenoAgeUnits({ glucose_mmolL: 5.0 });
|
|
330
|
+
expect(result.glucose).toBe(5.0);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it('should convert CRP from mg/L to ln(mg/dL)', () => {
|
|
334
|
+
const result = convertToPhenoAgeUnits({ crp_mgL: 1.0 });
|
|
335
|
+
// 1.0 mg/L → 0.1 mg/dL → ln(0.1) ≈ -2.302
|
|
336
|
+
expect(result.lnCRP).toBeCloseTo(Math.log(0.1), 2);
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it('should handle CRP floor for very low values', () => {
|
|
340
|
+
const result = convertToPhenoAgeUnits({ crp_mgL: 0 });
|
|
341
|
+
expect(result.lnCRP).toBeCloseTo(Math.log(0.001), 2);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
it('should pass through direct units unchanged', () => {
|
|
345
|
+
const result = convertToPhenoAgeUnits({
|
|
346
|
+
lymphocytePercent: 30,
|
|
347
|
+
mcv: 90,
|
|
348
|
+
rdw: 13,
|
|
349
|
+
alp: 75,
|
|
350
|
+
wbc: 7,
|
|
351
|
+
});
|
|
352
|
+
expect(result.lymphocytePercent).toBe(30);
|
|
353
|
+
expect(result.mcv).toBe(90);
|
|
354
|
+
expect(result.rdw).toBe(13);
|
|
355
|
+
expect(result.alp).toBe(75);
|
|
356
|
+
expect(result.wbc).toBe(7);
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
it('should return partial result for partial input', () => {
|
|
360
|
+
const result = convertToPhenoAgeUnits({ albumin_gL: 40 });
|
|
361
|
+
expect(result.albumin).toBeDefined();
|
|
362
|
+
expect(result.creatinine).toBeUndefined();
|
|
363
|
+
expect(result.glucose).toBeUndefined();
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
it('should prefer glucose_mmolL over glucose_mgDL when both provided', () => {
|
|
367
|
+
const result = convertToPhenoAgeUnits({ glucose_mgDL: 90, glucose_mmolL: 5.0 });
|
|
368
|
+
// glucose_mmolL is processed after glucose_mgDL, so it wins
|
|
369
|
+
expect(result.glucose).toBe(5.0);
|
|
370
|
+
});
|
|
371
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { clamp, safeLn } from '../src/utils.js';
|
|
3
|
+
|
|
4
|
+
describe('clamp', () => {
|
|
5
|
+
it('should return value when within range', () => {
|
|
6
|
+
expect(clamp(5, 0, 10)).toBe(5);
|
|
7
|
+
expect(clamp(0, 0, 10)).toBe(0);
|
|
8
|
+
expect(clamp(10, 0, 10)).toBe(10);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should clamp to min when below range', () => {
|
|
12
|
+
expect(clamp(-5, 0, 10)).toBe(0);
|
|
13
|
+
expect(clamp(-100, -10, 10)).toBe(-10);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should clamp to max when above range', () => {
|
|
17
|
+
expect(clamp(15, 0, 10)).toBe(10);
|
|
18
|
+
expect(clamp(100, -10, 10)).toBe(10);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should handle equal min and max', () => {
|
|
22
|
+
expect(clamp(5, 3, 3)).toBe(3);
|
|
23
|
+
expect(clamp(1, 3, 3)).toBe(3);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should handle negative ranges', () => {
|
|
27
|
+
expect(clamp(-5, -10, -1)).toBe(-5);
|
|
28
|
+
expect(clamp(-15, -10, -1)).toBe(-10);
|
|
29
|
+
expect(clamp(0, -10, -1)).toBe(-1);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should handle floating point', () => {
|
|
33
|
+
expect(clamp(0.5, 0.1, 0.9)).toBe(0.5);
|
|
34
|
+
expect(clamp(0.05, 0.1, 0.9)).toBe(0.1);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe('safeLn', () => {
|
|
39
|
+
it('should return ln for positive values', () => {
|
|
40
|
+
expect(safeLn(1)).toBeCloseTo(0, 10);
|
|
41
|
+
expect(safeLn(Math.E)).toBeCloseTo(1, 10);
|
|
42
|
+
expect(safeLn(10)).toBeCloseTo(Math.log(10), 10);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should floor zero to default 0.001', () => {
|
|
46
|
+
expect(safeLn(0)).toBeCloseTo(Math.log(0.001), 10);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should floor negative values to default 0.001', () => {
|
|
50
|
+
expect(safeLn(-5)).toBeCloseTo(Math.log(0.001), 10);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should use custom floor when provided', () => {
|
|
54
|
+
expect(safeLn(0, 0.01)).toBeCloseTo(Math.log(0.01), 10);
|
|
55
|
+
expect(safeLn(-1, 0.1)).toBeCloseTo(Math.log(0.1), 10);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should not change values above the floor', () => {
|
|
59
|
+
expect(safeLn(5, 0.01)).toBeCloseTo(Math.log(5), 10);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should never return -Infinity', () => {
|
|
63
|
+
expect(Number.isFinite(safeLn(0))).toBe(true);
|
|
64
|
+
expect(Number.isFinite(safeLn(-100))).toBe(true);
|
|
65
|
+
expect(Number.isFinite(safeLn(0.0001))).toBe(true);
|
|
66
|
+
});
|
|
67
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ottolab/bio-age",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"repository": "https://github.com/hokev/Otto",
|
|
6
|
+
"publishConfig": { "access": "public" },
|
|
7
|
+
"type": "module",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"source": "./src/index.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc --build",
|
|
19
|
+
"lint": "eslint src/",
|
|
20
|
+
"test": "vitest run"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@ottolab/shared": "*"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
27
|
+
"vitest": "^3.0.0"
|
|
28
|
+
}
|
|
29
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export {
|
|
2
|
+
calculatePhenoAge,
|
|
3
|
+
calculateMetabolicProxy,
|
|
4
|
+
computeLinearPredictor,
|
|
5
|
+
computeMortalityScore,
|
|
6
|
+
invertToPhenoAge,
|
|
7
|
+
convertToPhenoAgeUnits,
|
|
8
|
+
PHENO_AGE_COEFFICIENTS,
|
|
9
|
+
GAMMA,
|
|
10
|
+
} from './pheno-age.js';
|
|
11
|
+
export type {
|
|
12
|
+
PhenoAgeInput,
|
|
13
|
+
PhenoAgeResult,
|
|
14
|
+
PhenoAgeDriver,
|
|
15
|
+
MetabolicProxyInput,
|
|
16
|
+
} from './pheno-age.js';
|
|
17
|
+
|
|
18
|
+
export { calculateKDM, KDM_REGRESSIONS, AGE_VARIANCE } from './kdm.js';
|
|
19
|
+
export type { KDMInput, KDMResult } from './kdm.js';
|
|
20
|
+
|
|
21
|
+
export { clamp, safeLn } from './utils.js';
|
package/src/kdm.ts
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Klemera-Doubal Method (KDM) Biological Age.
|
|
3
|
+
*
|
|
4
|
+
* Based on: Klemera & Doubal (2006) "A new approach to the concept and
|
|
5
|
+
* computation of biological age". Implemented with biomarker regressions
|
|
6
|
+
* from NHANES III data following the approach in Levine (2013).
|
|
7
|
+
*
|
|
8
|
+
* KDM fits each biomarker as a linear function of chronological age,
|
|
9
|
+
* then combines all biomarkers into a single BA estimate that minimizes
|
|
10
|
+
* the sum of squared deviations weighted by residual variance.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export interface KDMInput {
|
|
14
|
+
chronologicalAge: number;
|
|
15
|
+
albumin?: number; // g/dL
|
|
16
|
+
creatinine?: number; // mg/dL
|
|
17
|
+
glucose?: number; // mg/dL
|
|
18
|
+
lnCRP?: number; // ln(CRP mg/dL)
|
|
19
|
+
lymphocytePercent?: number;
|
|
20
|
+
mcv?: number; // fL
|
|
21
|
+
rdw?: number; // %
|
|
22
|
+
alp?: number; // U/L
|
|
23
|
+
wbc?: number; // 10^3/uL
|
|
24
|
+
systolicBP?: number; // mmHg
|
|
25
|
+
bun?: number; // mg/dL
|
|
26
|
+
hba1c?: number; // %
|
|
27
|
+
totalCholesterol?: number; // mg/dL
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface KDMResult {
|
|
31
|
+
kdmAge: number;
|
|
32
|
+
delta: number;
|
|
33
|
+
markersUsed: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Biomarker regression parameters: each marker regressed on chronological age.
|
|
38
|
+
* slope (k), intercept (q), residual SD (s) from NHANES III reference.
|
|
39
|
+
*
|
|
40
|
+
* Model: biomarker_i = q_i + k_i * age + error_i, Var(error_i) = s_i^2
|
|
41
|
+
*/
|
|
42
|
+
interface BiomarkerRegression {
|
|
43
|
+
k: number; // slope (change per year of age)
|
|
44
|
+
q: number; // intercept
|
|
45
|
+
s: number; // residual standard deviation
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const KDM_REGRESSIONS: Record<string, BiomarkerRegression> = {
|
|
49
|
+
albumin: { k: -0.0172, q: 4.703, s: 0.3262 },
|
|
50
|
+
creatinine: { k: 0.0033, q: 0.842, s: 0.2136 },
|
|
51
|
+
glucose: { k: 0.27, q: 83.56, s: 22.24 },
|
|
52
|
+
lnCRP: { k: 0.0205, q: -1.794, s: 1.126 },
|
|
53
|
+
lymphocytePercent: { k: -0.0522, q: 33.55, s: 8.47 },
|
|
54
|
+
mcv: { k: 0.052, q: 87.08, s: 5.51 },
|
|
55
|
+
rdw: { k: 0.0211, q: 12.36, s: 1.18 },
|
|
56
|
+
alp: { k: 0.347, q: 58.83, s: 24.1 },
|
|
57
|
+
wbc: { k: -0.0072, q: 7.4, s: 2.12 },
|
|
58
|
+
systolicBP: { k: 0.527, q: 101.8, s: 17.64 },
|
|
59
|
+
bun: { k: 0.101, q: 10.89, s: 4.63 },
|
|
60
|
+
hba1c: { k: 0.0131, q: 4.926, s: 0.607 },
|
|
61
|
+
totalCholesterol: { k: 0.252, q: 190.2, s: 40.41 },
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// Variance of chronological age in reference population (NHANES III, adults 20-85)
|
|
65
|
+
const AGE_VARIANCE = 250.0; // ~SD of 15.8 years
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Calculate KDM biological age.
|
|
69
|
+
*
|
|
70
|
+
* The KDM formula:
|
|
71
|
+
* BA = [ sum_i( (x_i - q_i) * k_i / s_i^2 ) + CA / s_BA^2 ]
|
|
72
|
+
* / [ sum_i( k_i^2 / s_i^2 ) + 1 / s_BA^2 ]
|
|
73
|
+
*
|
|
74
|
+
* where s_BA^2 is estimated from the age variance in the reference population.
|
|
75
|
+
*
|
|
76
|
+
* Requires at least 3 markers for a meaningful estimate.
|
|
77
|
+
*/
|
|
78
|
+
export function calculateKDM(input: KDMInput): KDMResult {
|
|
79
|
+
const markers = getAvailableMarkers(input);
|
|
80
|
+
|
|
81
|
+
if (markers.length < 3) {
|
|
82
|
+
throw new Error(`KDM requires at least 3 biomarkers, got ${markers.length}`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let numerator = 0;
|
|
86
|
+
let denominator = 0;
|
|
87
|
+
|
|
88
|
+
for (const { value, regression } of markers) {
|
|
89
|
+
const { k, q, s } = regression;
|
|
90
|
+
const s2 = s * s;
|
|
91
|
+
numerator += ((value - q) * k) / s2;
|
|
92
|
+
denominator += (k * k) / s2;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Add chronological age term (acts as a prior)
|
|
96
|
+
const sBA2 = AGE_VARIANCE;
|
|
97
|
+
numerator += input.chronologicalAge / sBA2;
|
|
98
|
+
denominator += 1 / sBA2;
|
|
99
|
+
|
|
100
|
+
const kdmAge = numerator / denominator;
|
|
101
|
+
const delta = kdmAge - input.chronologicalAge;
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
kdmAge: Math.round(kdmAge * 100) / 100,
|
|
105
|
+
delta: Math.round(delta * 100) / 100,
|
|
106
|
+
markersUsed: markers.length,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Extract available markers from input, matching to their regression parameters.
|
|
112
|
+
*/
|
|
113
|
+
function getAvailableMarkers(
|
|
114
|
+
input: KDMInput,
|
|
115
|
+
): { name: string; value: number; regression: BiomarkerRegression }[] {
|
|
116
|
+
const result: { name: string; value: number; regression: BiomarkerRegression }[] = [];
|
|
117
|
+
|
|
118
|
+
for (const [name, regression] of Object.entries(KDM_REGRESSIONS)) {
|
|
119
|
+
const value = input[name as keyof KDMInput];
|
|
120
|
+
if (typeof value === 'number') {
|
|
121
|
+
result.push({ name, value, regression });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return result;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Export regressions for testing
|
|
129
|
+
export { KDM_REGRESSIONS, AGE_VARIANCE };
|
package/src/pheno-age.ts
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { clamp } from './utils.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Input for PhenoAge calculation.
|
|
5
|
+
* Units follow the Levine 2018 model convention:
|
|
6
|
+
* albumin g/dL, creatinine mg/dL, glucose mmol/L, CRP mg/dL (log-transformed),
|
|
7
|
+
* lymphocyte %, MCV fL, RDW %, ALP U/L, WBC 10^3/uL.
|
|
8
|
+
*/
|
|
9
|
+
export interface PhenoAgeInput {
|
|
10
|
+
chronologicalAge: number;
|
|
11
|
+
albumin: number; // g/dL
|
|
12
|
+
creatinine: number; // mg/dL
|
|
13
|
+
glucose: number; // mmol/L
|
|
14
|
+
lnCRP: number; // ln(CRP in mg/dL)
|
|
15
|
+
lymphocytePercent: number;
|
|
16
|
+
mcv: number; // fL
|
|
17
|
+
rdw: number; // %
|
|
18
|
+
alp: number; // U/L
|
|
19
|
+
wbc: number; // 10^3 cells/uL
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface PhenoAgeResult {
|
|
23
|
+
phenoAge: number;
|
|
24
|
+
delta: number; // phenoAge - chronologicalAge
|
|
25
|
+
mortalityScore: number;
|
|
26
|
+
isProxy: boolean;
|
|
27
|
+
drivers?: PhenoAgeDriver[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface PhenoAgeDriver {
|
|
31
|
+
marker: string;
|
|
32
|
+
contribution: number;
|
|
33
|
+
direction: 'aging' | 'protective';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Input for the metabolic proxy fallback when full CBC is unavailable.
|
|
38
|
+
* All values in conventional US units.
|
|
39
|
+
*/
|
|
40
|
+
export interface MetabolicProxyInput {
|
|
41
|
+
chronologicalAge: number;
|
|
42
|
+
glucose?: number; // mg/dL
|
|
43
|
+
hba1c?: number; // %
|
|
44
|
+
hsCrp?: number; // mg/L
|
|
45
|
+
triglycerides?: number; // mg/dL
|
|
46
|
+
hdl?: number; // mg/dL
|
|
47
|
+
ldlC?: number; // mg/dL
|
|
48
|
+
fastingInsulin?: number; // uIU/mL
|
|
49
|
+
uricAcid?: number; // mg/dL
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Published coefficients (Levine 2018, Table S6)
|
|
53
|
+
export const PHENO_AGE_COEFFICIENTS = {
|
|
54
|
+
intercept: -19.9067,
|
|
55
|
+
albumin: -0.0336,
|
|
56
|
+
creatinine: 0.0095,
|
|
57
|
+
glucose: 0.1953,
|
|
58
|
+
lnCRP: 0.0954,
|
|
59
|
+
lymphocytePercent: -0.012,
|
|
60
|
+
mcv: 0.0268,
|
|
61
|
+
rdw: 0.3306,
|
|
62
|
+
alp: 0.00188,
|
|
63
|
+
wbc: 0.0554,
|
|
64
|
+
age: 0.0804,
|
|
65
|
+
} as const;
|
|
66
|
+
|
|
67
|
+
// Gompertz proportional hazard gamma
|
|
68
|
+
export const GAMMA = 0.0076927;
|
|
69
|
+
|
|
70
|
+
// Max age horizon for Gompertz integration
|
|
71
|
+
const MAX_AGE = 120;
|
|
72
|
+
|
|
73
|
+
// PhenoAge inversion constants (derived from Gompertz model)
|
|
74
|
+
const PHENO_INVERSE = {
|
|
75
|
+
intercept: 141.50225,
|
|
76
|
+
lambda: -0.00553,
|
|
77
|
+
slope: 0.090165,
|
|
78
|
+
} as const;
|
|
79
|
+
|
|
80
|
+
// Population means for driver analysis (NHANES III reference)
|
|
81
|
+
const POPULATION_MEANS: Record<string, number> = {
|
|
82
|
+
albumin: 4.0,
|
|
83
|
+
creatinine: 0.96,
|
|
84
|
+
glucose: 5.42, // 97.7 mg/dL → mmol/L
|
|
85
|
+
lnCRP: -0.94,
|
|
86
|
+
lymphocytePercent: 30.3,
|
|
87
|
+
mcv: 89.5,
|
|
88
|
+
rdw: 13.3,
|
|
89
|
+
alp: 78.5,
|
|
90
|
+
wbc: 7.1,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// Population means and SDs for metabolic proxy (NHANES reference)
|
|
94
|
+
const METABOLIC_PROXY_MARKERS: Record<string, { mean: number; sd: number; weight: number }> = {
|
|
95
|
+
glucose: { mean: 97.7, sd: 22, weight: 1.0 },
|
|
96
|
+
hba1c: { mean: 5.5, sd: 0.5, weight: 1.2 },
|
|
97
|
+
hsCrp: { mean: 2.0, sd: 3.0, weight: 0.8 },
|
|
98
|
+
triglycerides: { mean: 130, sd: 75, weight: 0.6 },
|
|
99
|
+
hdl: { mean: 53, sd: 15, weight: -0.7 }, // negative: higher is better
|
|
100
|
+
ldlC: { mean: 120, sd: 35, weight: 0.5 },
|
|
101
|
+
fastingInsulin: { mean: 9.0, sd: 6.0, weight: 0.9 },
|
|
102
|
+
uricAcid: { mean: 5.4, sd: 1.4, weight: 0.6 },
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// Years of biological age per 1 SD deviation
|
|
106
|
+
const YEARS_PER_SD = 2.5;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Compute the linear predictor (xb) from PhenoAge model.
|
|
110
|
+
*/
|
|
111
|
+
export function computeLinearPredictor(input: PhenoAgeInput): number {
|
|
112
|
+
const c = PHENO_AGE_COEFFICIENTS;
|
|
113
|
+
return (
|
|
114
|
+
c.intercept +
|
|
115
|
+
c.albumin * input.albumin +
|
|
116
|
+
c.creatinine * input.creatinine +
|
|
117
|
+
c.glucose * input.glucose +
|
|
118
|
+
c.lnCRP * input.lnCRP +
|
|
119
|
+
c.lymphocytePercent * input.lymphocytePercent +
|
|
120
|
+
c.mcv * input.mcv +
|
|
121
|
+
c.rdw * input.rdw +
|
|
122
|
+
c.alp * input.alp +
|
|
123
|
+
c.wbc * input.wbc +
|
|
124
|
+
c.age * input.chronologicalAge
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Compute cumulative mortality probability from linear predictor via Gompertz model.
|
|
130
|
+
*
|
|
131
|
+
* M(xb) = 1 - exp(-exp(xb) * (exp(gamma * T) - 1) / gamma)
|
|
132
|
+
* where T = MAX_AGE (120 years)
|
|
133
|
+
*/
|
|
134
|
+
export function computeMortalityScore(xb: number): number {
|
|
135
|
+
const hazard = Math.exp(xb);
|
|
136
|
+
const cumHazard = (hazard * (Math.exp(GAMMA * MAX_AGE) - 1)) / GAMMA;
|
|
137
|
+
return 1 - Math.exp(-cumHazard);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Invert mortality score back to PhenoAge.
|
|
142
|
+
*
|
|
143
|
+
* PhenoAge = intercept + ln(lambda * ln(1 - M)) / slope
|
|
144
|
+
*/
|
|
145
|
+
export function invertToPhenoAge(mortalityScore: number): number {
|
|
146
|
+
const clamped = clamp(mortalityScore, 1e-10, 1 - 1e-10);
|
|
147
|
+
const inner = PHENO_INVERSE.lambda * Math.log(1 - clamped);
|
|
148
|
+
return PHENO_INVERSE.intercept + Math.log(inner) / PHENO_INVERSE.slope;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Calculate PhenoAge biological age using the Levine 2018 algorithm.
|
|
153
|
+
*
|
|
154
|
+
* Algorithm:
|
|
155
|
+
* 1. Linear predictor: xb = intercept + sum(coeff_i * marker_i)
|
|
156
|
+
* 2. Gompertz mortality: M = 1 - exp(-exp(xb) * (exp(gamma*120) - 1) / gamma)
|
|
157
|
+
* 3. Invert: PhenoAge = 141.50225 + ln(-0.00553 * ln(1-M)) / 0.090165
|
|
158
|
+
*
|
|
159
|
+
* All inputs must be in model-native units (g/dL, mg/dL, etc.).
|
|
160
|
+
* Use `convertToPhenoAgeUnits()` if you have SI units.
|
|
161
|
+
*/
|
|
162
|
+
export function calculatePhenoAge(input: PhenoAgeInput): PhenoAgeResult {
|
|
163
|
+
const xb = computeLinearPredictor(input);
|
|
164
|
+
const mortalityScore = computeMortalityScore(xb);
|
|
165
|
+
const phenoAge = invertToPhenoAge(mortalityScore);
|
|
166
|
+
const delta = phenoAge - input.chronologicalAge;
|
|
167
|
+
const drivers = computeDrivers(input);
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
phenoAge: Math.round(phenoAge * 100) / 100,
|
|
171
|
+
delta: Math.round(delta * 100) / 100,
|
|
172
|
+
mortalityScore: Math.round(mortalityScore * 10000) / 10000,
|
|
173
|
+
isProxy: false,
|
|
174
|
+
drivers,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Metabolic proxy for biological age when full CBC panel is unavailable.
|
|
180
|
+
*
|
|
181
|
+
* Uses z-score deviation from population means across available metabolic
|
|
182
|
+
* markers. Each weighted SD of deviation approximates YEARS_PER_SD years
|
|
183
|
+
* of biological age shift. Delta is capped at [-10, +15] years.
|
|
184
|
+
*/
|
|
185
|
+
export function calculateMetabolicProxy(input: MetabolicProxyInput): PhenoAgeResult {
|
|
186
|
+
let weightedZSum = 0;
|
|
187
|
+
let totalWeight = 0;
|
|
188
|
+
|
|
189
|
+
for (const [key, config] of Object.entries(METABOLIC_PROXY_MARKERS)) {
|
|
190
|
+
const value = input[key as keyof MetabolicProxyInput] as number | undefined;
|
|
191
|
+
if (value === undefined) continue;
|
|
192
|
+
|
|
193
|
+
const z = (value - config.mean) / config.sd;
|
|
194
|
+
weightedZSum += z * config.weight;
|
|
195
|
+
totalWeight += Math.abs(config.weight);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (totalWeight === 0) {
|
|
199
|
+
return {
|
|
200
|
+
phenoAge: input.chronologicalAge,
|
|
201
|
+
delta: 0,
|
|
202
|
+
mortalityScore: 0,
|
|
203
|
+
isProxy: true,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const normalizedZ = weightedZSum / totalWeight;
|
|
208
|
+
const rawDelta = normalizedZ * YEARS_PER_SD;
|
|
209
|
+
const delta = clamp(rawDelta, -10, 15);
|
|
210
|
+
const phenoAge = input.chronologicalAge + delta;
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
phenoAge: Math.round(phenoAge * 100) / 100,
|
|
214
|
+
delta: Math.round(delta * 100) / 100,
|
|
215
|
+
mortalityScore: 0,
|
|
216
|
+
isProxy: true,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Identify which biomarkers drive the PhenoAge deviation most.
|
|
222
|
+
* Computes contribution = coefficient * (actual - population_mean) for each marker.
|
|
223
|
+
*/
|
|
224
|
+
function computeDrivers(input: PhenoAgeInput): PhenoAgeDriver[] {
|
|
225
|
+
const c = PHENO_AGE_COEFFICIENTS;
|
|
226
|
+
const markerCoeffs: [string, number, number][] = [
|
|
227
|
+
['albumin', c.albumin, input.albumin],
|
|
228
|
+
['creatinine', c.creatinine, input.creatinine],
|
|
229
|
+
['glucose', c.glucose, input.glucose],
|
|
230
|
+
['lnCRP', c.lnCRP, input.lnCRP],
|
|
231
|
+
['lymphocytePercent', c.lymphocytePercent, input.lymphocytePercent],
|
|
232
|
+
['mcv', c.mcv, input.mcv],
|
|
233
|
+
['rdw', c.rdw, input.rdw],
|
|
234
|
+
['alp', c.alp, input.alp],
|
|
235
|
+
['wbc', c.wbc, input.wbc],
|
|
236
|
+
];
|
|
237
|
+
|
|
238
|
+
const drivers: PhenoAgeDriver[] = markerCoeffs.map(([marker, coeff, actual]) => {
|
|
239
|
+
const mean = POPULATION_MEANS[marker] ?? 0;
|
|
240
|
+
const contribution = coeff * (actual - mean);
|
|
241
|
+
return {
|
|
242
|
+
marker,
|
|
243
|
+
contribution: Math.round(contribution * 10000) / 10000,
|
|
244
|
+
direction: contribution > 0 ? 'aging' : 'protective',
|
|
245
|
+
};
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
return drivers.sort((a, b) => Math.abs(b.contribution) - Math.abs(a.contribution));
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Convert common lab units to PhenoAge model units.
|
|
253
|
+
*
|
|
254
|
+
* Accepts either SI or US units and converts to model-native:
|
|
255
|
+
* albumin g/L → g/dL, creatinine umol/L → mg/dL, glucose mg/dL → mmol/L,
|
|
256
|
+
* CRP mg/L → ln(mg/dL).
|
|
257
|
+
*/
|
|
258
|
+
export function convertToPhenoAgeUnits(raw: {
|
|
259
|
+
albumin_gL?: number;
|
|
260
|
+
creatinine_umolL?: number;
|
|
261
|
+
glucose_mgDL?: number;
|
|
262
|
+
glucose_mmolL?: number;
|
|
263
|
+
crp_mgL?: number;
|
|
264
|
+
lymphocytePercent?: number;
|
|
265
|
+
mcv?: number;
|
|
266
|
+
rdw?: number;
|
|
267
|
+
alp?: number;
|
|
268
|
+
wbc?: number;
|
|
269
|
+
}): Partial<Omit<PhenoAgeInput, 'chronologicalAge'>> {
|
|
270
|
+
const result: Partial<Omit<PhenoAgeInput, 'chronologicalAge'>> = {};
|
|
271
|
+
|
|
272
|
+
if (raw.albumin_gL !== undefined) result.albumin = raw.albumin_gL * 0.1; // g/L → g/dL
|
|
273
|
+
if (raw.creatinine_umolL !== undefined) result.creatinine = raw.creatinine_umolL / 88.4; // umol/L → mg/dL
|
|
274
|
+
if (raw.glucose_mgDL !== undefined) result.glucose = raw.glucose_mgDL / 18.0182; // mg/dL → mmol/L
|
|
275
|
+
if (raw.glucose_mmolL !== undefined) result.glucose = raw.glucose_mmolL; // already mmol/L
|
|
276
|
+
if (raw.crp_mgL !== undefined) result.lnCRP = Math.log(Math.max(raw.crp_mgL * 0.1, 0.001)); // mg/L → mg/dL → ln
|
|
277
|
+
if (raw.lymphocytePercent !== undefined) result.lymphocytePercent = raw.lymphocytePercent;
|
|
278
|
+
if (raw.mcv !== undefined) result.mcv = raw.mcv;
|
|
279
|
+
if (raw.rdw !== undefined) result.rdw = raw.rdw;
|
|
280
|
+
if (raw.alp !== undefined) result.alp = raw.alp;
|
|
281
|
+
if (raw.wbc !== undefined) result.wbc = raw.wbc;
|
|
282
|
+
|
|
283
|
+
return result;
|
|
284
|
+
}
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clamp a value to a [min, max] range.
|
|
3
|
+
*/
|
|
4
|
+
export function clamp(value: number, min: number, max: number): number {
|
|
5
|
+
return Math.min(Math.max(value, min), max);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Natural log with safety floor to avoid -Infinity.
|
|
10
|
+
*/
|
|
11
|
+
export function safeLn(value: number, floor = 0.001): number {
|
|
12
|
+
return Math.log(Math.max(value, floor));
|
|
13
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"fileNames":["../../node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/typescript/lib/lib.es2021.d.ts","../../node_modules/typescript/lib/lib.es2022.d.ts","../../node_modules/typescript/lib/lib.dom.d.ts","../../node_modules/typescript/lib/lib.dom.iterable.d.ts","../../node_modules/typescript/lib/lib.dom.asynciterable.d.ts","../../node_modules/typescript/lib/lib.webworker.importscripts.d.ts","../../node_modules/typescript/lib/lib.scripthost.d.ts","../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/typescript/lib/lib.es2021.promise.d.ts","../../node_modules/typescript/lib/lib.es2021.string.d.ts","../../node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../node_modules/typescript/lib/lib.es2021.intl.d.ts","../../node_modules/typescript/lib/lib.es2022.array.d.ts","../../node_modules/typescript/lib/lib.es2022.error.d.ts","../../node_modules/typescript/lib/lib.es2022.intl.d.ts","../../node_modules/typescript/lib/lib.es2022.object.d.ts","../../node_modules/typescript/lib/lib.es2022.string.d.ts","../../node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../node_modules/typescript/lib/lib.esnext.disposable.d.ts","../../node_modules/typescript/lib/lib.esnext.float16.d.ts","../../node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../node_modules/typescript/lib/lib.es2022.full.d.ts","./src/utils.ts","./src/pheno-age.ts","./src/kdm.ts","./src/index.ts","../../node_modules/@types/deep-eql/index.d.ts","../../node_modules/assertion-error/index.d.ts","../../node_modules/@types/chai/index.d.ts","../../node_modules/@types/d3-array/index.d.ts","../../node_modules/@types/d3-color/index.d.ts","../../node_modules/@types/d3-ease/index.d.ts","../../node_modules/@types/d3-interpolate/index.d.ts","../../node_modules/@types/d3-path/index.d.ts","../../node_modules/@types/d3-time/index.d.ts","../../node_modules/@types/d3-scale/index.d.ts","../../node_modules/@types/d3-shape/index.d.ts","../../node_modules/@types/d3-timer/index.d.ts","../../node_modules/@types/estree/index.d.ts","../../node_modules/@types/json-schema/index.d.ts","../../node_modules/@types/node/compatibility/iterators.d.ts","../../node_modules/@types/node/globals.typedarray.d.ts","../../node_modules/@types/node/buffer.buffer.d.ts","../../node_modules/@types/node/globals.d.ts","../../node_modules/@types/node/web-globals/abortcontroller.d.ts","../../node_modules/@types/node/web-globals/blob.d.ts","../../node_modules/@types/node/web-globals/console.d.ts","../../node_modules/@types/node/web-globals/crypto.d.ts","../../node_modules/@types/node/web-globals/domexception.d.ts","../../node_modules/@types/node/web-globals/encoding.d.ts","../../node_modules/@types/node/web-globals/events.d.ts","../../node_modules/undici-types/utility.d.ts","../../node_modules/undici-types/header.d.ts","../../node_modules/undici-types/readable.d.ts","../../node_modules/undici-types/fetch.d.ts","../../node_modules/undici-types/formdata.d.ts","../../node_modules/undici-types/connector.d.ts","../../node_modules/undici-types/client-stats.d.ts","../../node_modules/undici-types/client.d.ts","../../node_modules/undici-types/errors.d.ts","../../node_modules/undici-types/dispatcher.d.ts","../../node_modules/undici-types/global-dispatcher.d.ts","../../node_modules/undici-types/global-origin.d.ts","../../node_modules/undici-types/pool-stats.d.ts","../../node_modules/undici-types/pool.d.ts","../../node_modules/undici-types/handlers.d.ts","../../node_modules/undici-types/balanced-pool.d.ts","../../node_modules/undici-types/round-robin-pool.d.ts","../../node_modules/undici-types/h2c-client.d.ts","../../node_modules/undici-types/agent.d.ts","../../node_modules/undici-types/mock-interceptor.d.ts","../../node_modules/undici-types/mock-call-history.d.ts","../../node_modules/undici-types/mock-agent.d.ts","../../node_modules/undici-types/mock-client.d.ts","../../node_modules/undici-types/mock-pool.d.ts","../../node_modules/undici-types/snapshot-agent.d.ts","../../node_modules/undici-types/mock-errors.d.ts","../../node_modules/undici-types/proxy-agent.d.ts","../../node_modules/undici-types/env-http-proxy-agent.d.ts","../../node_modules/undici-types/retry-handler.d.ts","../../node_modules/undici-types/retry-agent.d.ts","../../node_modules/undici-types/api.d.ts","../../node_modules/undici-types/cache-interceptor.d.ts","../../node_modules/undici-types/interceptors.d.ts","../../node_modules/undici-types/util.d.ts","../../node_modules/undici-types/cookies.d.ts","../../node_modules/undici-types/patch.d.ts","../../node_modules/undici-types/websocket.d.ts","../../node_modules/undici-types/eventsource.d.ts","../../node_modules/undici-types/diagnostics-channel.d.ts","../../node_modules/undici-types/content-type.d.ts","../../node_modules/undici-types/cache.d.ts","../../node_modules/undici-types/index.d.ts","../../node_modules/@types/node/web-globals/fetch.d.ts","../../node_modules/@types/node/web-globals/importmeta.d.ts","../../node_modules/@types/node/web-globals/messaging.d.ts","../../node_modules/@types/node/web-globals/navigator.d.ts","../../node_modules/@types/node/web-globals/performance.d.ts","../../node_modules/@types/node/web-globals/storage.d.ts","../../node_modules/@types/node/web-globals/streams.d.ts","../../node_modules/@types/node/web-globals/timers.d.ts","../../node_modules/@types/node/web-globals/url.d.ts","../../node_modules/@types/node/assert.d.ts","../../node_modules/@types/node/assert/strict.d.ts","../../node_modules/@types/node/async_hooks.d.ts","../../node_modules/@types/node/buffer.d.ts","../../node_modules/@types/node/child_process.d.ts","../../node_modules/@types/node/cluster.d.ts","../../node_modules/@types/node/console.d.ts","../../node_modules/@types/node/constants.d.ts","../../node_modules/@types/node/crypto.d.ts","../../node_modules/@types/node/dgram.d.ts","../../node_modules/@types/node/diagnostics_channel.d.ts","../../node_modules/@types/node/dns.d.ts","../../node_modules/@types/node/dns/promises.d.ts","../../node_modules/@types/node/domain.d.ts","../../node_modules/@types/node/events.d.ts","../../node_modules/@types/node/fs.d.ts","../../node_modules/@types/node/fs/promises.d.ts","../../node_modules/@types/node/http.d.ts","../../node_modules/@types/node/http2.d.ts","../../node_modules/@types/node/https.d.ts","../../node_modules/@types/node/inspector.d.ts","../../node_modules/@types/node/inspector.generated.d.ts","../../node_modules/@types/node/inspector/promises.d.ts","../../node_modules/@types/node/module.d.ts","../../node_modules/@types/node/net.d.ts","../../node_modules/@types/node/os.d.ts","../../node_modules/@types/node/path.d.ts","../../node_modules/@types/node/path/posix.d.ts","../../node_modules/@types/node/path/win32.d.ts","../../node_modules/@types/node/perf_hooks.d.ts","../../node_modules/@types/node/process.d.ts","../../node_modules/@types/node/punycode.d.ts","../../node_modules/@types/node/querystring.d.ts","../../node_modules/@types/node/quic.d.ts","../../node_modules/@types/node/readline.d.ts","../../node_modules/@types/node/readline/promises.d.ts","../../node_modules/@types/node/repl.d.ts","../../node_modules/@types/node/sea.d.ts","../../node_modules/@types/node/sqlite.d.ts","../../node_modules/@types/node/stream.d.ts","../../node_modules/@types/node/stream/consumers.d.ts","../../node_modules/@types/node/stream/promises.d.ts","../../node_modules/@types/node/stream/web.d.ts","../../node_modules/@types/node/string_decoder.d.ts","../../node_modules/@types/node/test.d.ts","../../node_modules/@types/node/test/reporters.d.ts","../../node_modules/@types/node/timers.d.ts","../../node_modules/@types/node/timers/promises.d.ts","../../node_modules/@types/node/tls.d.ts","../../node_modules/@types/node/trace_events.d.ts","../../node_modules/@types/node/tty.d.ts","../../node_modules/@types/node/url.d.ts","../../node_modules/@types/node/util.d.ts","../../node_modules/@types/node/util/types.d.ts","../../node_modules/@types/node/v8.d.ts","../../node_modules/@types/node/vm.d.ts","../../node_modules/@types/node/wasi.d.ts","../../node_modules/@types/node/worker_threads.d.ts","../../node_modules/@types/node/zlib.d.ts","../../node_modules/@types/node/index.d.ts","../../node_modules/@types/react/global.d.ts","../../node_modules/csstype/index.d.ts","../../node_modules/@types/react/index.d.ts","../../node_modules/@types/react-dom/index.d.ts","../../node_modules/@types/use-sync-external-store/index.d.ts"],"fileIdsList":[[70,71,86,149,157,161,164,166,167,168,180],[86,149,157,161,164,166,167,168,180],[74,86,149,157,161,164,166,167,168,180],[78,86,149,157,161,164,166,167,168,180],[77,86,149,157,161,164,166,167,168,180],[86,146,147,149,157,161,164,166,167,168,180],[86,148,149,157,161,164,166,167,168,180],[149,157,161,164,166,167,168,180],[86,149,157,161,164,166,167,168,180,188],[86,149,150,155,157,160,161,164,166,167,168,170,180,185,197],[86,149,150,151,157,160,161,164,166,167,168,180],[86,149,152,157,161,164,166,167,168,180,198],[86,149,153,154,157,161,164,166,167,168,171,180],[86,149,154,157,161,164,166,167,168,180,185,194],[86,149,155,157,160,161,164,166,167,168,170,180],[86,148,149,156,157,161,164,166,167,168,180],[86,149,157,158,161,164,166,167,168,180],[86,149,157,159,160,161,164,166,167,168,180],[86,148,149,157,160,161,164,166,167,168,180],[86,149,157,160,161,162,164,166,167,168,180,185,197],[86,149,157,160,161,162,164,166,167,168,180,185,188],[86,136,149,157,160,161,163,164,166,167,168,170,180,185,197],[86,149,157,160,161,163,164,166,167,168,170,180,185,194,197],[86,149,157,161,163,164,165,166,167,168,180,185,194,197],[84,85,86,87,88,89,90,91,92,93,94,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204],[86,149,157,160,161,164,166,167,168,180],[86,149,157,161,164,166,168,180],[86,149,157,161,164,166,167,168,169,180,197],[86,149,157,160,161,164,166,167,168,170,180,185],[86,149,157,161,164,166,167,168,171,180],[86,149,157,161,164,166,167,168,172,180],[86,149,157,160,161,164,166,167,168,175,180],[86,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204],[86,149,157,161,164,166,167,168,177,180],[86,149,157,161,164,166,167,168,178,180],[86,149,154,157,161,164,166,167,168,170,180,188],[86,149,157,160,161,164,166,167,168,180,181],[86,149,157,161,164,166,167,168,180,182,198,201],[86,149,157,160,161,164,166,167,168,180,185,187,188],[86,149,157,161,164,166,167,168,180,186,188],[86,149,157,161,164,166,167,168,180,188,198],[86,149,157,161,164,166,167,168,180,189],[86,146,149,157,161,164,166,167,168,180,185,191,197],[86,149,157,161,164,166,167,168,180,185,190],[86,149,157,160,161,164,166,167,168,180,192,193],[86,149,157,161,164,166,167,168,180,192,193],[86,149,154,157,161,164,166,167,168,170,180,185,194],[86,149,157,161,164,166,167,168,180,195],[86,149,157,161,164,166,167,168,170,180,196],[86,149,157,161,163,164,166,167,168,178,180,197],[86,149,157,161,164,166,167,168,180,198,199],[86,149,154,157,161,164,166,167,168,180,199],[86,149,157,161,164,166,167,168,180,185,200],[86,149,157,161,164,166,167,168,169,180,201],[86,149,157,161,164,166,167,168,180,202],[86,149,152,157,161,164,166,167,168,180],[86,149,154,157,161,164,166,167,168,180],[86,149,157,161,164,166,167,168,180,198],[86,136,149,157,161,164,166,167,168,180],[86,149,157,161,164,166,167,168,180,197],[86,149,157,161,164,166,167,168,180,203],[86,149,157,161,164,166,167,168,175,180],[86,149,157,161,164,166,167,168,180,193],[86,136,149,157,160,161,162,164,166,167,168,175,180,185,188,197,200,201,203],[86,149,157,161,164,166,167,168,180,185,204],[86,149,157,161,164,166,167,168,180,208],[86,149,157,161,164,166,167,168,180,206,207],[86,101,104,107,108,149,157,161,164,166,167,168,180,197],[86,104,149,157,161,164,166,167,168,180,185,197],[86,104,108,149,157,161,164,166,167,168,180,197],[86,149,157,161,164,166,167,168,180,185],[86,98,149,157,161,164,166,167,168,180],[86,102,149,157,161,164,166,167,168,180],[86,100,101,104,149,157,161,164,166,167,168,180,197],[86,149,157,161,164,166,167,168,170,180,194],[86,149,157,161,164,166,167,168,180,205],[86,98,149,157,161,164,166,167,168,180,205],[86,100,104,149,157,161,164,166,167,168,170,180,197],[86,95,96,97,99,103,149,157,160,161,164,166,167,168,180,185,197],[86,104,113,121,149,157,161,164,166,167,168,180],[86,96,102,149,157,161,164,166,167,168,180],[86,104,130,131,149,157,161,164,166,167,168,180],[86,96,99,104,149,157,161,164,166,167,168,180,188,197,205],[86,104,149,157,161,164,166,167,168,180],[86,100,104,149,157,161,164,166,167,168,180,197],[86,95,149,157,161,164,166,167,168,180],[86,98,99,100,102,103,104,105,106,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,131,132,133,134,135,149,157,161,164,166,167,168,180],[86,104,123,126,149,157,161,164,166,167,168,180],[86,104,113,114,115,149,157,161,164,166,167,168,180],[86,102,104,114,116,149,157,161,164,166,167,168,180],[86,103,149,157,161,164,166,167,168,180],[86,96,98,104,149,157,161,164,166,167,168,180],[86,104,108,114,116,149,157,161,164,166,167,168,180],[86,108,149,157,161,164,166,167,168,180],[86,102,104,107,149,157,161,164,166,167,168,180,197],[86,96,100,104,113,149,157,161,164,166,167,168,180],[86,104,123,149,157,161,164,166,167,168,180],[86,116,149,157,161,164,166,167,168,180],[86,98,104,130,149,157,161,164,166,167,168,180,188,203,205],[66,67,68,86,149,157,161,164,166,167,168,180],[66,86,149,157,161,164,166,167,168,180]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"080941d9f9ff9307f7e27a83bcd888b7c8270716c39af943532438932ec1d0b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2e80ee7a49e8ac312cc11b77f1475804bee36b3b2bc896bead8b6e1266befb43","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7a3c8b952931daebdfc7a2897c53c0a1c73624593fa070e46bd537e64dcd20a","affectsGlobalScope":true,"impliedFormat":1},{"version":"80e18897e5884b6723488d4f5652167e7bb5024f946743134ecc4aa4ee731f89","affectsGlobalScope":true,"impliedFormat":1},{"version":"cd034f499c6cdca722b60c04b5b1b78e058487a7085a8e0d6fb50809947ee573","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"8cdf8847677ac7d20486e54dd3fcf09eda95812ac8ace44b4418da1bbbab6eb8","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"51ad4c928303041605b4d7ae32e0c1ee387d43a24cd6f1ebf4a2699e1076d4fa","affectsGlobalScope":true,"impliedFormat":1},{"version":"196cb558a13d4533a5163286f30b0509ce0210e4b316c56c38d4c0fd2fb38405","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"3cbad9a1ba4453443026ed38e4b8be018abb26565fa7c944376463ad9df07c41","impliedFormat":1},{"version":"a0b27ca9e4a130ee68703bddfe6793044e3ef95109e23a04a600cb4dbd523ba4","signature":"18a3d8c73f1bed63744efe4e786c47cd439ee655538b44ac6f9b07be31268c0b"},{"version":"20e9df401a040cf74656e02bab3801e4f83b858da036cae6a745d2186e8a98ed","signature":"d4cbca1b6fb27da7c8d80bbc5ac64a90292f3c523c0d423cc13959112672990d"},{"version":"281a5f0f80dae50ac90ebbd5626cdf834d06d53300a16b54ef78e0ecb393ef3c","signature":"f01e6a1f22e607b737092a831e09cdb13ad7bb7e8021ea5291b6c200d53ba94e"},{"version":"4b5e501b268a2958b482f0455b79828729aeb6620acd77ad3557475a672adad4","signature":"fae18ecafb4bb1deffee4047c8a85da2a0ad47a68da8b8e35466fb7a61be2a88"},{"version":"427fe2004642504828c1476d0af4270e6ad4db6de78c0b5da3e4c5ca95052a99","impliedFormat":1},{"version":"2eeffcee5c1661ddca53353929558037b8cf305ffb86a803512982f99bcab50d","impliedFormat":99},{"version":"9afb4cb864d297e4092a79ee2871b5d3143ea14153f62ef0bb04ede25f432030","affectsGlobalScope":true,"impliedFormat":99},{"version":"b1538a92b9bae8d230267210c5db38c2eb6bdb352128a3ce3aa8c6acf9fc9622","impliedFormat":1},{"version":"6fc1a4f64372593767a9b7b774e9b3b92bf04e8785c3f9ea98973aa9f4bbe490","impliedFormat":1},{"version":"ff09b6fbdcf74d8af4e131b8866925c5e18d225540b9b19ce9485ca93e574d84","impliedFormat":1},{"version":"d5895252efa27a50f134a9b580aa61f7def5ab73d0a8071f9b5bf9a317c01c2d","impliedFormat":1},{"version":"2c378d9368abcd2eba8c29b294d40909845f68557bc0b38117e4f04fc56e5f9c","impliedFormat":1},{"version":"56208c500dcb5f42be7e18e8cb578f257a1a89b94b3280c506818fed06391805","impliedFormat":1},{"version":"0c94c2e497e1b9bcfda66aea239d5d36cd980d12a6d9d59e66f4be1fa3da5d5a","impliedFormat":1},{"version":"9b048390bcffe88c023a4cd742a720b41d4cd7df83bc9270e6f2339bf38de278","affectsGlobalScope":true,"impliedFormat":1},{"version":"1f366bde16e0513fa7b64f87f86689c4d36efd85afce7eb24753e9c99b91c319","impliedFormat":1},{"version":"151ff381ef9ff8da2da9b9663ebf657eac35c4c9a19183420c05728f31a6761d","impliedFormat":1},{"version":"f3d8c757e148ad968f0d98697987db363070abada5f503da3c06aefd9d4248c1","impliedFormat":1},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"0ccdaa19852d25ecd84eec365c3bfa16e7859cadecf6e9ca6d0dbbbee439743f","affectsGlobalScope":true,"impliedFormat":1},{"version":"438b41419b1df9f1fbe33b5e1b18f5853432be205991d1b19f5b7f351675541e","affectsGlobalScope":true,"impliedFormat":1},{"version":"096116f8fedc1765d5bd6ef360c257b4a9048e5415054b3bf3c41b07f8951b0b","affectsGlobalScope":true,"impliedFormat":1},{"version":"e5e01375c9e124a83b52ee4b3244ed1a4d214a6cfb54ac73e164a823a4a7860a","affectsGlobalScope":true,"impliedFormat":1},{"version":"f90ae2bbce1505e67f2f6502392e318f5714bae82d2d969185c4a6cecc8af2fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"4b58e207b93a8f1c88bbf2a95ddc686ac83962b13830fe8ad3f404ffc7051fb4","affectsGlobalScope":true,"impliedFormat":1},{"version":"1fefabcb2b06736a66d2904074d56268753654805e829989a46a0161cd8412c5","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"c18a99f01eb788d849ad032b31cafd49de0b19e083fe775370834c5675d7df8e","affectsGlobalScope":true,"impliedFormat":1},{"version":"5247874c2a23b9a62d178ae84f2db6a1d54e6c9a2e7e057e178cc5eea13757fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"cdcf9ea426ad970f96ac930cd176d5c69c6c24eebd9fc580e1572d6c6a88f62c","impliedFormat":1},{"version":"23cd712e2ce083d68afe69224587438e5914b457b8acf87073c22494d706a3d0","impliedFormat":1},{"version":"156a859e21ef3244d13afeeba4e49760a6afa035c149dda52f0c45ea8903b338","impliedFormat":1},{"version":"10ec5e82144dfac6f04fa5d1d6c11763b3e4dbbac6d99101427219ab3e2ae887","impliedFormat":1},{"version":"615754924717c0b1e293e083b83503c0a872717ad5aa60ed7f1a699eb1b4ea5c","impliedFormat":1},{"version":"074de5b2fdead0165a2757e3aaef20f27a6347b1c36adea27d51456795b37682","impliedFormat":1},{"version":"68834d631c8838c715f225509cfc3927913b9cc7a4870460b5b60c8dbdb99baf","impliedFormat":1},{"version":"24371e69a38fc33e268d4a8716dbcda430d6c2c414a99ff9669239c4b8f40dea","impliedFormat":1},{"version":"ccab02f3920fc75c01174c47fcf67882a11daf16baf9e81701d0a94636e94556","impliedFormat":1},{"version":"3e11fce78ad8c0e1d1db4ba5f0652285509be3acdd519529bc8fcef85f7dafd9","impliedFormat":1},{"version":"ea6bc8de8b59f90a7a3960005fd01988f98fd0784e14bc6922dde2e93305ec7d","impliedFormat":1},{"version":"36107995674b29284a115e21a0618c4c2751b32a8766dd4cb3ba740308b16d59","impliedFormat":1},{"version":"914a0ae30d96d71915fc519ccb4efbf2b62c0ddfb3a3fc6129151076bc01dc60","impliedFormat":1},{"version":"9c32412007b5662fd34a8eb04292fb5314ec370d7016d1c2fb8aa193c807fe22","impliedFormat":1},{"version":"7fd1b31fd35876b0aa650811c25ec2c97a3c6387e5473eb18004bed86cdd76b6","impliedFormat":1},{"version":"4d327f7d72ad0918275cea3eee49a6a8dc8114ae1d5b7f3f5d0774de75f7439a","impliedFormat":1},{"version":"6ebe8ebb8659aaa9d1acbf3710d7dae3e923e97610238b9511c25dc39023a166","impliedFormat":1},{"version":"e85d7f8068f6a26710bff0cc8c0fc5e47f71089c3780fbede05857331d2ddec9","impliedFormat":1},{"version":"7befaf0e76b5671be1d47b77fcc65f2b0aad91cc26529df1904f4a7c46d216e9","impliedFormat":1},{"version":"0a60a292b89ca7218b8616f78e5bbd1c96b87e048849469cccb4355e98af959a","impliedFormat":1},{"version":"0b6e25234b4eec6ed96ab138d96eb70b135690d7dd01f3dd8a8ab291c35a683a","impliedFormat":1},{"version":"9666f2f84b985b62400d2e5ab0adae9ff44de9b2a34803c2c5bd3c8325b17dc0","impliedFormat":1},{"version":"40cd35c95e9cf22cfa5bd84e96408b6fcbca55295f4ff822390abb11afbc3dca","impliedFormat":1},{"version":"b1616b8959bf557feb16369c6124a97a0e74ed6f49d1df73bb4b9ddf68acf3f3","impliedFormat":1},{"version":"5b03a034c72146b61573aab280f295b015b9168470f2df05f6080a2122f9b4df","impliedFormat":1},{"version":"40b463c6766ca1b689bfcc46d26b5e295954f32ad43e37ee6953c0a677e4ae2b","impliedFormat":1},{"version":"249b9cab7f5d628b71308c7d9bb0a808b50b091e640ba3ed6e2d0516f4a8d91d","impliedFormat":1},{"version":"80aae6afc67faa5ac0b32b5b8bc8cc9f7fa299cff15cf09cc2e11fd28c6ae29e","impliedFormat":1},{"version":"f473cd2288991ff3221165dcf73cd5d24da30391f87e85b3dd4d0450c787a391","impliedFormat":1},{"version":"499e5b055a5aba1e1998f7311a6c441a369831c70905cc565ceac93c28083d53","impliedFormat":1},{"version":"8aee8b6d4f9f62cf3776cda1305fb18763e2aade7e13cea5bbe699112df85214","impliedFormat":1},{"version":"c63b9ada8c72f95aac5db92aea07e5e87ec810353cdf63b2d78f49a58662cf6c","impliedFormat":1},{"version":"1cc2a09e1a61a5222d4174ab358a9f9de5e906afe79dbf7363d871a7edda3955","impliedFormat":1},{"version":"5d0375ca7310efb77e3ef18d068d53784faf62705e0ad04569597ae0e755c401","impliedFormat":1},{"version":"59af37caec41ecf7b2e76059c9672a49e682c1a2aa6f9d7dc78878f53aa284d6","impliedFormat":1},{"version":"addf417b9eb3f938fddf8d81e96393a165e4be0d4a8b6402292f9c634b1cb00d","impliedFormat":1},{"version":"b64d4d1c5f877f9c666e98e833f0205edb9384acc46e98a1fef344f64d6aba44","impliedFormat":1},{"version":"adf27937dba6af9f08a68c5b1d3fce0ca7d4b960c57e6d6c844e7d1a8e53adae","impliedFormat":1},{"version":"12950411eeab8563b349cb7959543d92d8d02c289ed893d78499a19becb5a8cc","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"c9381908473a1c92cb8c516b184e75f4d226dad95c3a85a5af35f670064d9a2f","impliedFormat":1},{"version":"c3f5289820990ab66b70c7fb5b63cb674001009ff84b13de40619619a9c8175f","affectsGlobalScope":true,"impliedFormat":1},{"version":"b3275d55fac10b799c9546804126239baf020d220136163f763b55a74e50e750","affectsGlobalScope":true,"impliedFormat":1},{"version":"fa68a0a3b7cb32c00e39ee3cd31f8f15b80cac97dce51b6ee7fc14a1e8deb30b","affectsGlobalScope":true,"impliedFormat":1},{"version":"1cf059eaf468efcc649f8cf6075d3cb98e9a35a0fe9c44419ec3d2f5428d7123","affectsGlobalScope":true,"impliedFormat":1},{"version":"6c36e755bced82df7fb6ce8169265d0a7bb046ab4e2cb6d0da0cb72b22033e89","affectsGlobalScope":true,"impliedFormat":1},{"version":"e7721c4f69f93c91360c26a0a84ee885997d748237ef78ef665b153e622b36c1","affectsGlobalScope":true,"impliedFormat":1},{"version":"7a93de4ff8a63bafe62ba86b89af1df0ccb5e40bb85b0c67d6bbcfdcf96bf3d4","affectsGlobalScope":true,"impliedFormat":1},{"version":"90e85f9bc549dfe2b5749b45fe734144e96cd5d04b38eae244028794e142a77e","affectsGlobalScope":true,"impliedFormat":1},{"version":"e0a5deeb610b2a50a6350bd23df6490036a1773a8a71d70f2f9549ab009e67ee","affectsGlobalScope":true,"impliedFormat":1},{"version":"435b3711465425770ed2ee2f1cf00ce071835265e0851a7dc4600ab4b007550e","impliedFormat":1},{"version":"7e49f52a159435fc8df4de9dc377ef5860732ca2dc9efec1640531d3cf5da7a3","impliedFormat":1},{"version":"dd4bde4bdc2e5394aed6855e98cf135dfdf5dd6468cad842e03116d31bbcc9bc","impliedFormat":1},{"version":"4d4e879009a84a47c05350b8dca823036ba3a29a3038efed1be76c9f81e45edf","affectsGlobalScope":true,"impliedFormat":1},{"version":"237ba5ac2a95702a114a309e39c53a5bddff5f6333b325db9764df9b34f3502b","impliedFormat":1},{"version":"9ba13b47cb450a438e3076c4a3f6afb9dc85e17eae50f26d4b2d72c0688c9251","impliedFormat":1},{"version":"b64cd4401633ea4ecadfd700ddc8323a13b63b106ac7127c1d2726f32424622c","impliedFormat":1},{"version":"37c6e5fe5715814412b43cc9b50b24c67a63c4e04e753e0d1305970d65417a60","impliedFormat":1},{"version":"1d024184fb57c58c5c91823f9d10b4915a4867b7934e89115fd0d861a9df27c8","impliedFormat":1},{"version":"ee0e4946247f842c6dd483cbb60a5e6b484fee07996e3a7bc7343dfb68a04c5d","impliedFormat":1},{"version":"ef051f42b7e0ef5ca04552f54c4552eac84099d64b6c5ad0ef4033574b6035b8","impliedFormat":1},{"version":"853a43154f1d01b0173d9cbd74063507ece57170bad7a3b68f3fa1229ad0a92f","impliedFormat":1},{"version":"56231e3c39a031bfb0afb797690b20ed4537670c93c0318b72d5180833d98b72","impliedFormat":1},{"version":"5cc7c39031bfd8b00ad58f32143d59eb6ffc24f5d41a20931269011dccd36c5e","impliedFormat":1},{"version":"b0b69c61b0f0ec8ca15db4c8c41f6e77f4cacb784d42bca948f42dea33e8757e","affectsGlobalScope":true,"impliedFormat":1},{"version":"f96a48183254c00d24575401f1a761b4ce4927d927407e7862a83e06ce5d6964","impliedFormat":1},{"version":"cc25940cfb27aa538e60d465f98bb5068d4d7d33131861ace43f04fe6947d68f","impliedFormat":1},{"version":"f83fb2b1338afbb3f9d733c7d6e8b135826c41b0518867df0c0ace18ae1aa270","impliedFormat":1},{"version":"01ff95aa1443e3f7248974e5a771f513cb2ac158c8898f470a1792f817bee497","impliedFormat":1},{"version":"757227c8b345c57d76f7f0e3bbad7a91ffca23f1b2547cbed9e10025816c9cb7","impliedFormat":1},{"version":"42a05d8f239f74587d4926aba8cc54792eed8e8a442c7adc9b38b516642aadfe","impliedFormat":1},{"version":"5d21b58d60383cc6ab9ad3d3e265d7d25af24a2c9b506247e0e50b0a884920be","impliedFormat":1},{"version":"101f482fd48cb4c7c0468dcc6d62c843d842977aea6235644b1edd05e81fbf22","impliedFormat":1},{"version":"ae6757460f37078884b1571a3de3ebaf724d827d7e1d53626c02b3c2a408ac63","affectsGlobalScope":true,"impliedFormat":1},{"version":"9451a46a89ed209e2e08329e6cac59f89356eae79a7230f916d8cc38725407c7","impliedFormat":1},{"version":"3ef397f12387eff17f550bc484ea7c27d21d43816bbe609d495107f44b97e933","impliedFormat":1},{"version":"1023282e2ba810bc07905d3668349fbd37a26411f0c8f94a70ef3c05fe523fcf","impliedFormat":1},{"version":"b214ebcf76c51b115453f69729ee8aa7b7f8eccdae2a922b568a45c2d7ff52f7","impliedFormat":1},{"version":"429c9cdfa7d126255779efd7e6d9057ced2d69c81859bbab32073bad52e9ba76","impliedFormat":1},{"version":"e236b5eba291f51bdf32c231673e6cab81b5410850e61f51a7a524dddadc0f95","impliedFormat":1},{"version":"cf9717ebf9dd23f5f1e55e00545df1edc40ac8a671a034974fb4ff5dfbfaacc4","affectsGlobalScope":true,"impliedFormat":1},{"version":"7f2c62938251b45715fd2a9887060ec4fbc8724727029d1cbce373747252bdd7","impliedFormat":1},{"version":"e3ace08b6bbd84655d41e244677b474fd995923ffef7149ddb68af8848b60b05","impliedFormat":1},{"version":"132580b0e86c48fab152bab850fc57a4b74fe915c8958d2ccb052b809a44b61c","impliedFormat":1},{"version":"af4ab0aa8908fc9a655bb833d3bc28e117c4f0e1038c5a891546158beb25accb","impliedFormat":1},{"version":"69c9a5a9392e8564bd81116e1ed93b13205201fb44cb35a7fde8c9f9e21c4b23","impliedFormat":1},{"version":"5f8fc37f8434691ffac1bfd8fc2634647da2c0e84253ab5d2dd19a7718915b35","impliedFormat":1},{"version":"5981c2340fd8b076cae8efbae818d42c11ffc615994cb060b1cd390795f1be2b","impliedFormat":1},{"version":"f64deb26664af64dc274637343bde8d82f930c77af05a412c7d310b77207a448","impliedFormat":1},{"version":"ed4f674fc8c0c993cc7e145069ac44129e03519b910c62be206a0cc777bdc60b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0250da3eb85c99624f974e77ef355cdf86f43980251bc371475c2b397ba55bcd","impliedFormat":1},{"version":"f1c93e046fb3d9b7f8249629f4b63dc068dd839b824dd0aa39a5e68476dc9420","impliedFormat":1},{"version":"3d3a5f27ffbc06c885dd4d5f9ee20de61faf877fe2c3a7051c4825903d9a7fdc","impliedFormat":1},{"version":"12806f9f085598ef930edaf2467a5fa1789a878fba077cd27e85dc5851e11834","impliedFormat":1},{"version":"bce309f4d9b67c18d4eeff5bba6cf3e67b2b0aead9f03f75d6060c553974d7ba","impliedFormat":1},{"version":"a43fe41c33d0a192a0ecaf9b92e87bef3709c9972e6d53c42c49251ccb962d69","impliedFormat":1},{"version":"a177959203c017fad3ecc4f3d96c8757a840957a4959a3ae00dab9d35961ca6c","affectsGlobalScope":true,"impliedFormat":1},{"version":"6fc727ccf9b36e257ff982ea0badeffbfc2c151802f741bddff00c6af3b784cf","impliedFormat":1},{"version":"fde38b23ab057617351c1676047d3317f651b1a6d207084e41c056ed158a77f9","impliedFormat":1},{"version":"4844a4c9b4b1e812b257676ed8a80b3f3be0e29bf05e742cc2ea9c3c6865e6c6","impliedFormat":1},{"version":"064878a60367e0407c42fb7ba02a2ea4d83257357dc20088e549bd4d89433e9c","impliedFormat":1},{"version":"14d4bd22d1b05824971b98f7e91b2484c90f1a684805c330476641417c3d9735","impliedFormat":1},{"version":"c3877fef8a43cd434f9728f25a97575b0eb73d92f38b5c87c840daccc3e21d97","impliedFormat":1},{"version":"b484ec11ba00e3a2235562a41898d55372ccabe607986c6fa4f4aba72093749f","impliedFormat":1},{"version":"1dbd83860e7634f9c236647f45dbc5d3c4f9eba8827d87209d6e9826fdf4dbd5","impliedFormat":1},{"version":"41ef7992c555671a8fe54db302788adefa191ded810a50329b79d20a6772d14c","impliedFormat":1},{"version":"041a7781b9127ab568d2cdcce62c58fdea7c7407f40b8c50045d7866a2727130","impliedFormat":1},{"version":"b37f83e7deea729aa9ce5593f78905afb45b7532fdff63041d374f60059e7852","impliedFormat":1},{"version":"e1cb68f3ef3a8dd7b2a9dfb3de482ed6c0f1586ba0db4e7d73c1d2147b6ffc51","impliedFormat":1},{"version":"55cdbeebe76a1fa18bbd7e7bf73350a2173926bd3085bb050cf5a5397025ee4e","impliedFormat":1},{"version":"7e29f41b158de217f94cb9676bf9cbd0cd9b5a46e1985141ed36e075c52bf6ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac51dd7d31333793807a6abaa5ae168512b6131bd41d9c5b98477fc3b7800f9f","impliedFormat":1},{"version":"dc0a7f107690ee5cd8afc8dbf05c4df78085471ce16bdd9881642ec738bc81fe","impliedFormat":1},{"version":"be1cc4d94ea60cbe567bc29ed479d42587bf1e6cba490f123d329976b0fe4ee5","impliedFormat":1},{"version":"7fa8d75d229eeaee235a801758d9c694e94405013fe77d5d1dd8e3201fc414f1","impliedFormat":1}],"root":[[66,69]],"options":{"composite":true,"declaration":true,"declarationMap":true,"esModuleInterop":true,"module":7,"noUnusedLocals":true,"noUnusedParameters":true,"outDir":"./dist","rootDir":"./src","skipLibCheck":true,"sourceMap":true,"strict":true,"target":9},"referencedMap":[[72,1],[73,2],[74,2],[75,2],[76,3],[77,2],[79,4],[80,5],[78,2],[81,2],[70,2],[82,2],[83,2],[146,6],[147,6],[148,7],[86,8],[149,9],[150,10],[151,11],[84,2],[152,12],[153,13],[154,14],[155,15],[156,16],[157,17],[158,17],[159,18],[160,19],[161,20],[162,21],[87,2],[85,2],[163,22],[164,23],[165,24],[205,25],[166,26],[167,27],[168,26],[169,28],[170,29],[171,30],[172,31],[173,31],[174,31],[175,32],[176,33],[177,34],[178,35],[179,36],[180,37],[181,37],[182,38],[183,2],[184,2],[185,39],[186,40],[187,39],[188,41],[189,42],[190,43],[191,44],[192,45],[193,46],[194,47],[195,48],[196,49],[197,50],[198,51],[199,52],[200,53],[201,54],[202,55],[88,26],[89,2],[90,56],[91,57],[92,2],[93,58],[94,2],[137,59],[138,60],[139,61],[140,61],[141,62],[142,2],[143,9],[144,63],[145,60],[203,64],[204,65],[209,66],[206,2],[208,67],[210,2],[71,2],[207,2],[63,2],[64,2],[12,2],[10,2],[11,2],[16,2],[15,2],[2,2],[17,2],[18,2],[19,2],[20,2],[21,2],[22,2],[23,2],[24,2],[3,2],[25,2],[26,2],[4,2],[27,2],[31,2],[28,2],[29,2],[30,2],[32,2],[33,2],[34,2],[5,2],[35,2],[36,2],[37,2],[38,2],[6,2],[42,2],[39,2],[40,2],[41,2],[43,2],[7,2],[44,2],[49,2],[50,2],[45,2],[46,2],[47,2],[48,2],[8,2],[54,2],[51,2],[52,2],[53,2],[55,2],[9,2],[56,2],[65,2],[57,2],[58,2],[60,2],[59,2],[1,2],[61,2],[62,2],[14,2],[13,2],[113,68],[125,69],[110,70],[126,71],[135,72],[101,73],[102,74],[100,75],[134,76],[129,77],[133,78],[104,79],[122,80],[103,81],[132,82],[98,83],[99,77],[105,84],[106,2],[112,85],[109,84],[96,86],[136,87],[127,88],[116,89],[115,84],[117,90],[120,91],[114,92],[118,93],[130,76],[107,94],[108,95],[121,96],[97,71],[124,97],[123,84],[111,95],[119,98],[128,2],[95,2],[131,99],[69,100],[68,2],[67,101],[66,2]],"latestChangedDtsFile":"./dist/index.d.ts","version":"5.9.3"}
|