@disclosureos/instruments 1.0.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/CHANGELOG.md +37 -0
- package/LICENSE +21 -0
- package/README.md +131 -0
- package/dist/constants/index.d.ts +7 -0
- package/dist/constants/index.js +111 -0
- package/dist/constants/index.js.map +1 -0
- package/dist/factories/index.d.ts +15 -0
- package/dist/factories/index.js +28 -0
- package/dist/factories/index.js.map +1 -0
- package/dist/formatters/index.d.ts +11 -0
- package/dist/formatters/index.js +38 -0
- package/dist/formatters/index.js.map +1 -0
- package/dist/guards/index.d.ts +6 -0
- package/dist/guards/index.js +111 -0
- package/dist/guards/index.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +228 -0
- package/dist/index.js.map +1 -0
- package/dist/labels/index.d.ts +11 -0
- package/dist/labels/index.js +38 -0
- package/dist/labels/index.js.map +1 -0
- package/dist/manifest/index.d.ts +289 -0
- package/dist/manifest/index.js +104 -0
- package/dist/manifest/index.js.map +1 -0
- package/dist/validators/index.d.ts +17 -0
- package/dist/validators/index.js +138 -0
- package/dist/validators/index.js.map +1 -0
- package/package.json +103 -0
- package/schema/sensor-manifest.schema.json +473 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
declare const ModalitySchema: z.ZodEnum<{
|
|
4
|
+
audio: "audio";
|
|
5
|
+
electro_optical: "electro_optical";
|
|
6
|
+
radio_frequency: "radio_frequency";
|
|
7
|
+
quantum: "quantum";
|
|
8
|
+
environmental: "environmental";
|
|
9
|
+
biometric: "biometric";
|
|
10
|
+
}>;
|
|
11
|
+
type Modality = z.infer<typeof ModalitySchema>;
|
|
12
|
+
declare const TimeSourceSchema: z.ZodEnum<{
|
|
13
|
+
atomic_clock: "atomic_clock";
|
|
14
|
+
gps_disciplined: "gps_disciplined";
|
|
15
|
+
ntp: "ntp";
|
|
16
|
+
system: "system";
|
|
17
|
+
unknown: "unknown";
|
|
18
|
+
}>;
|
|
19
|
+
type TimeSource = z.infer<typeof TimeSourceSchema>;
|
|
20
|
+
declare const SensorTimingSchema: z.ZodObject<{
|
|
21
|
+
timeSource: z.ZodEnum<{
|
|
22
|
+
atomic_clock: "atomic_clock";
|
|
23
|
+
gps_disciplined: "gps_disciplined";
|
|
24
|
+
ntp: "ntp";
|
|
25
|
+
system: "system";
|
|
26
|
+
unknown: "unknown";
|
|
27
|
+
}>;
|
|
28
|
+
timeUncertaintyNs: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
29
|
+
}, z.core.$strip>;
|
|
30
|
+
type SensorTiming = z.infer<typeof SensorTimingSchema>;
|
|
31
|
+
declare const RecordsMappingSchema: z.ZodObject<{
|
|
32
|
+
sensorType: z.ZodOptional<z.ZodString>;
|
|
33
|
+
detectionMethod: z.ZodOptional<z.ZodString>;
|
|
34
|
+
proposedSensorType: z.ZodOptional<z.ZodBoolean>;
|
|
35
|
+
proposedDetectionMethod: z.ZodOptional<z.ZodBoolean>;
|
|
36
|
+
}, z.core.$strip>;
|
|
37
|
+
type RecordsMapping = z.infer<typeof RecordsMappingSchema>;
|
|
38
|
+
declare const RawDataSpecSchema: z.ZodObject<{
|
|
39
|
+
format: z.ZodOptional<z.ZodString>;
|
|
40
|
+
locatorPattern: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
41
|
+
sampleRateHz: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
42
|
+
bitDepth: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
43
|
+
}, z.core.$strip>;
|
|
44
|
+
type RawDataSpec = z.infer<typeof RawDataSpecSchema>;
|
|
45
|
+
declare const UncertaintyTypeSchema: z.ZodEnum<{
|
|
46
|
+
A: "A";
|
|
47
|
+
B: "B";
|
|
48
|
+
}>;
|
|
49
|
+
type UncertaintyType = z.infer<typeof UncertaintyTypeSchema>;
|
|
50
|
+
declare const MeasurementUncertaintySchema: z.ZodObject<{
|
|
51
|
+
u_c: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
52
|
+
U: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
53
|
+
k: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
54
|
+
type: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
55
|
+
A: "A";
|
|
56
|
+
B: "B";
|
|
57
|
+
}>>>;
|
|
58
|
+
}, z.core.$strip>;
|
|
59
|
+
type MeasurementUncertainty = z.infer<typeof MeasurementUncertaintySchema>;
|
|
60
|
+
declare const MeasurementSchema: z.ZodObject<{
|
|
61
|
+
name: z.ZodString;
|
|
62
|
+
unit: z.ZodString;
|
|
63
|
+
uncertainty: z.ZodOptional<z.ZodObject<{
|
|
64
|
+
u_c: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
65
|
+
U: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
66
|
+
k: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
67
|
+
type: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
68
|
+
A: "A";
|
|
69
|
+
B: "B";
|
|
70
|
+
}>>>;
|
|
71
|
+
}, z.core.$strip>>;
|
|
72
|
+
}, z.core.$strip>;
|
|
73
|
+
type Measurement = z.infer<typeof MeasurementSchema>;
|
|
74
|
+
declare const CalibrationStatusSchema: z.ZodEnum<{
|
|
75
|
+
none: "none";
|
|
76
|
+
candidate_identified: "candidate_identified";
|
|
77
|
+
in_practice: "in_practice";
|
|
78
|
+
documented: "documented";
|
|
79
|
+
}>;
|
|
80
|
+
type CalibrationStatus = z.infer<typeof CalibrationStatusSchema>;
|
|
81
|
+
declare const SensorCalibrationSchema: z.ZodObject<{
|
|
82
|
+
status: z.ZodEnum<{
|
|
83
|
+
none: "none";
|
|
84
|
+
candidate_identified: "candidate_identified";
|
|
85
|
+
in_practice: "in_practice";
|
|
86
|
+
documented: "documented";
|
|
87
|
+
}>;
|
|
88
|
+
calibrated: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
|
|
89
|
+
currentMethod: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
90
|
+
traceableReference: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
91
|
+
referenceInUse: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
|
|
92
|
+
cadence: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
93
|
+
uncertaintyBudget: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
94
|
+
notes: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
95
|
+
}, z.core.$strip>;
|
|
96
|
+
type SensorCalibration = z.infer<typeof SensorCalibrationSchema>;
|
|
97
|
+
declare const SensorEntrySchema: z.ZodObject<{
|
|
98
|
+
id: z.ZodString;
|
|
99
|
+
name: z.ZodString;
|
|
100
|
+
modality: z.ZodEnum<{
|
|
101
|
+
audio: "audio";
|
|
102
|
+
electro_optical: "electro_optical";
|
|
103
|
+
radio_frequency: "radio_frequency";
|
|
104
|
+
quantum: "quantum";
|
|
105
|
+
environmental: "environmental";
|
|
106
|
+
biometric: "biometric";
|
|
107
|
+
}>;
|
|
108
|
+
manufacturerModel: z.ZodOptional<z.ZodString>;
|
|
109
|
+
inHouse: z.ZodOptional<z.ZodBoolean>;
|
|
110
|
+
compute: z.ZodOptional<z.ZodString>;
|
|
111
|
+
recordsMapping: z.ZodOptional<z.ZodObject<{
|
|
112
|
+
sensorType: z.ZodOptional<z.ZodString>;
|
|
113
|
+
detectionMethod: z.ZodOptional<z.ZodString>;
|
|
114
|
+
proposedSensorType: z.ZodOptional<z.ZodBoolean>;
|
|
115
|
+
proposedDetectionMethod: z.ZodOptional<z.ZodBoolean>;
|
|
116
|
+
}, z.core.$strip>>;
|
|
117
|
+
timing: z.ZodOptional<z.ZodObject<{
|
|
118
|
+
timeSource: z.ZodEnum<{
|
|
119
|
+
atomic_clock: "atomic_clock";
|
|
120
|
+
gps_disciplined: "gps_disciplined";
|
|
121
|
+
ntp: "ntp";
|
|
122
|
+
system: "system";
|
|
123
|
+
unknown: "unknown";
|
|
124
|
+
}>;
|
|
125
|
+
timeUncertaintyNs: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
126
|
+
}, z.core.$strip>>;
|
|
127
|
+
rawData: z.ZodOptional<z.ZodObject<{
|
|
128
|
+
format: z.ZodOptional<z.ZodString>;
|
|
129
|
+
locatorPattern: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
130
|
+
sampleRateHz: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
131
|
+
bitDepth: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
132
|
+
}, z.core.$strip>>;
|
|
133
|
+
measurements: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
134
|
+
name: z.ZodString;
|
|
135
|
+
unit: z.ZodString;
|
|
136
|
+
uncertainty: z.ZodOptional<z.ZodObject<{
|
|
137
|
+
u_c: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
138
|
+
U: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
139
|
+
k: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
140
|
+
type: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
141
|
+
A: "A";
|
|
142
|
+
B: "B";
|
|
143
|
+
}>>>;
|
|
144
|
+
}, z.core.$strip>>;
|
|
145
|
+
}, z.core.$strip>>>;
|
|
146
|
+
calibration: z.ZodOptional<z.ZodObject<{
|
|
147
|
+
status: z.ZodEnum<{
|
|
148
|
+
none: "none";
|
|
149
|
+
candidate_identified: "candidate_identified";
|
|
150
|
+
in_practice: "in_practice";
|
|
151
|
+
documented: "documented";
|
|
152
|
+
}>;
|
|
153
|
+
calibrated: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
|
|
154
|
+
currentMethod: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
155
|
+
traceableReference: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
156
|
+
referenceInUse: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
|
|
157
|
+
cadence: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
158
|
+
uncertaintyBudget: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
159
|
+
notes: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
160
|
+
}, z.core.$strip>>;
|
|
161
|
+
specs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
162
|
+
specSource: z.ZodOptional<z.ZodString>;
|
|
163
|
+
}, z.core.$strip>;
|
|
164
|
+
type SensorEntry = z.infer<typeof SensorEntrySchema>;
|
|
165
|
+
declare const UpgradeStatusSchema: z.ZodEnum<{
|
|
166
|
+
planned: "planned";
|
|
167
|
+
evaluating: "evaluating";
|
|
168
|
+
ordered: "ordered";
|
|
169
|
+
acquired: "acquired";
|
|
170
|
+
}>;
|
|
171
|
+
type UpgradeStatus = z.infer<typeof UpgradeStatusSchema>;
|
|
172
|
+
declare const FutureUpgradeSchema: z.ZodObject<{
|
|
173
|
+
name: z.ZodString;
|
|
174
|
+
modality: z.ZodEnum<{
|
|
175
|
+
audio: "audio";
|
|
176
|
+
electro_optical: "electro_optical";
|
|
177
|
+
radio_frequency: "radio_frequency";
|
|
178
|
+
quantum: "quantum";
|
|
179
|
+
environmental: "environmental";
|
|
180
|
+
biometric: "biometric";
|
|
181
|
+
}>;
|
|
182
|
+
status: z.ZodOptional<z.ZodEnum<{
|
|
183
|
+
planned: "planned";
|
|
184
|
+
evaluating: "evaluating";
|
|
185
|
+
ordered: "ordered";
|
|
186
|
+
acquired: "acquired";
|
|
187
|
+
}>>;
|
|
188
|
+
specs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
189
|
+
link: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
190
|
+
notes: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
191
|
+
}, z.core.$strip>;
|
|
192
|
+
type FutureUpgrade = z.infer<typeof FutureUpgradeSchema>;
|
|
193
|
+
declare const SensorManifestSchema: z.ZodObject<{
|
|
194
|
+
schemaVersion: z.ZodString;
|
|
195
|
+
org: z.ZodString;
|
|
196
|
+
orgSlug: z.ZodString;
|
|
197
|
+
orgUrl: z.ZodOptional<z.ZodString>;
|
|
198
|
+
generatedAt: z.ZodOptional<z.ZodString>;
|
|
199
|
+
sensors: z.ZodArray<z.ZodObject<{
|
|
200
|
+
id: z.ZodString;
|
|
201
|
+
name: z.ZodString;
|
|
202
|
+
modality: z.ZodEnum<{
|
|
203
|
+
audio: "audio";
|
|
204
|
+
electro_optical: "electro_optical";
|
|
205
|
+
radio_frequency: "radio_frequency";
|
|
206
|
+
quantum: "quantum";
|
|
207
|
+
environmental: "environmental";
|
|
208
|
+
biometric: "biometric";
|
|
209
|
+
}>;
|
|
210
|
+
manufacturerModel: z.ZodOptional<z.ZodString>;
|
|
211
|
+
inHouse: z.ZodOptional<z.ZodBoolean>;
|
|
212
|
+
compute: z.ZodOptional<z.ZodString>;
|
|
213
|
+
recordsMapping: z.ZodOptional<z.ZodObject<{
|
|
214
|
+
sensorType: z.ZodOptional<z.ZodString>;
|
|
215
|
+
detectionMethod: z.ZodOptional<z.ZodString>;
|
|
216
|
+
proposedSensorType: z.ZodOptional<z.ZodBoolean>;
|
|
217
|
+
proposedDetectionMethod: z.ZodOptional<z.ZodBoolean>;
|
|
218
|
+
}, z.core.$strip>>;
|
|
219
|
+
timing: z.ZodOptional<z.ZodObject<{
|
|
220
|
+
timeSource: z.ZodEnum<{
|
|
221
|
+
atomic_clock: "atomic_clock";
|
|
222
|
+
gps_disciplined: "gps_disciplined";
|
|
223
|
+
ntp: "ntp";
|
|
224
|
+
system: "system";
|
|
225
|
+
unknown: "unknown";
|
|
226
|
+
}>;
|
|
227
|
+
timeUncertaintyNs: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
228
|
+
}, z.core.$strip>>;
|
|
229
|
+
rawData: z.ZodOptional<z.ZodObject<{
|
|
230
|
+
format: z.ZodOptional<z.ZodString>;
|
|
231
|
+
locatorPattern: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
232
|
+
sampleRateHz: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
233
|
+
bitDepth: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
234
|
+
}, z.core.$strip>>;
|
|
235
|
+
measurements: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
236
|
+
name: z.ZodString;
|
|
237
|
+
unit: z.ZodString;
|
|
238
|
+
uncertainty: z.ZodOptional<z.ZodObject<{
|
|
239
|
+
u_c: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
240
|
+
U: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
241
|
+
k: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
242
|
+
type: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
243
|
+
A: "A";
|
|
244
|
+
B: "B";
|
|
245
|
+
}>>>;
|
|
246
|
+
}, z.core.$strip>>;
|
|
247
|
+
}, z.core.$strip>>>;
|
|
248
|
+
calibration: z.ZodOptional<z.ZodObject<{
|
|
249
|
+
status: z.ZodEnum<{
|
|
250
|
+
none: "none";
|
|
251
|
+
candidate_identified: "candidate_identified";
|
|
252
|
+
in_practice: "in_practice";
|
|
253
|
+
documented: "documented";
|
|
254
|
+
}>;
|
|
255
|
+
calibrated: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
|
|
256
|
+
currentMethod: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
257
|
+
traceableReference: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
258
|
+
referenceInUse: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
|
|
259
|
+
cadence: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
260
|
+
uncertaintyBudget: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
261
|
+
notes: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
262
|
+
}, z.core.$strip>>;
|
|
263
|
+
specs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
264
|
+
specSource: z.ZodOptional<z.ZodString>;
|
|
265
|
+
}, z.core.$strip>>;
|
|
266
|
+
futureUpgrades: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
267
|
+
name: z.ZodString;
|
|
268
|
+
modality: z.ZodEnum<{
|
|
269
|
+
audio: "audio";
|
|
270
|
+
electro_optical: "electro_optical";
|
|
271
|
+
radio_frequency: "radio_frequency";
|
|
272
|
+
quantum: "quantum";
|
|
273
|
+
environmental: "environmental";
|
|
274
|
+
biometric: "biometric";
|
|
275
|
+
}>;
|
|
276
|
+
status: z.ZodOptional<z.ZodEnum<{
|
|
277
|
+
planned: "planned";
|
|
278
|
+
evaluating: "evaluating";
|
|
279
|
+
ordered: "ordered";
|
|
280
|
+
acquired: "acquired";
|
|
281
|
+
}>>;
|
|
282
|
+
specs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
283
|
+
link: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
284
|
+
notes: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
285
|
+
}, z.core.$strip>>>;
|
|
286
|
+
}, z.core.$strip>;
|
|
287
|
+
type SensorManifest = z.infer<typeof SensorManifestSchema>;
|
|
288
|
+
|
|
289
|
+
export { type CalibrationStatus, CalibrationStatusSchema, type FutureUpgrade, FutureUpgradeSchema, type Measurement, MeasurementSchema, type MeasurementUncertainty, MeasurementUncertaintySchema, type Modality, ModalitySchema, type RawDataSpec, RawDataSpecSchema, type RecordsMapping, RecordsMappingSchema, type SensorCalibration, SensorCalibrationSchema, type SensorEntry, SensorEntrySchema, type SensorManifest, SensorManifestSchema, type SensorTiming, SensorTimingSchema, type TimeSource, TimeSourceSchema, type UncertaintyType, UncertaintyTypeSchema, type UpgradeStatus, UpgradeStatusSchema };
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
// src/manifest/types.ts
|
|
4
|
+
var KEBAB_CASE_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
|
|
5
|
+
var ModalitySchema = z.enum(["audio", "electro_optical", "radio_frequency", "quantum", "environmental", "biometric"]).describe("Top-level sensing modality the sensor belongs to.");
|
|
6
|
+
var TimeSourceSchema = z.enum(["atomic_clock", "gps_disciplined", "ntp", "system", "unknown"]).describe("Clock source that timestamps the sensor\u2019s data.");
|
|
7
|
+
var SensorTimingSchema = z.object({
|
|
8
|
+
timeSource: TimeSourceSchema,
|
|
9
|
+
timeUncertaintyNs: z.number().nullable().optional().describe("Timestamp uncertainty in nanoseconds. Null = not yet characterized.")
|
|
10
|
+
}).meta({ id: "SensorTiming" }).describe(
|
|
11
|
+
"Timing provenance. Timestamp error of even a few seconds confounds multi-station correlation, so the clock source must be declared, not assumed."
|
|
12
|
+
);
|
|
13
|
+
var RecordsMappingSchema = z.object({
|
|
14
|
+
sensorType: z.string().optional().describe("The `@disclosureos/records` SensorType this sensor maps to."),
|
|
15
|
+
detectionMethod: z.string().optional().describe("The `@disclosureos/records` DetectionMethod this sensor maps to."),
|
|
16
|
+
proposedSensorType: z.boolean().optional().describe("True = sensorType is not in the records enum yet and is proposed by the publisher."),
|
|
17
|
+
proposedDetectionMethod: z.boolean().optional().describe("True = detectionMethod is not in the records enum yet and is proposed by the publisher.")
|
|
18
|
+
}).meta({ id: "RecordsMapping" }).describe(
|
|
19
|
+
"How this sensor maps to the `SensorReading` vocabulary in `@disclosureos/records`. Values outside the records enums must carry the matching proposed* flag."
|
|
20
|
+
);
|
|
21
|
+
var RawDataSpecSchema = z.object({
|
|
22
|
+
format: z.string().optional().describe('Raw-data file format, e.g. "NDJSON.gz", "WAV", "MJPEG", "FITS", "CSV".'),
|
|
23
|
+
locatorPattern: z.string().nullable().optional().describe("Storage key pattern or path convention for locating the raw files."),
|
|
24
|
+
sampleRateHz: z.number().nullable().optional().describe("Sample rate in Hz, where applicable."),
|
|
25
|
+
bitDepth: z.number().nullable().optional().describe("Sample bit depth, where applicable.")
|
|
26
|
+
}).meta({ id: "RawDataSpec" }).describe(
|
|
27
|
+
"Raw-data format and locator. Supports a metadata-first architecture: circulate manifests widely, pull raw data on demand."
|
|
28
|
+
);
|
|
29
|
+
var UncertaintyTypeSchema = z.enum(["A", "B"]).describe("GUM uncertainty evaluation type: A (statistical) or B (other means).");
|
|
30
|
+
var MeasurementUncertaintySchema = z.object({
|
|
31
|
+
u_c: z.number().nullable().optional().describe("Combined standard uncertainty."),
|
|
32
|
+
U: z.number().nullable().optional().describe("Expanded uncertainty (= k \xD7 u_c)."),
|
|
33
|
+
k: z.number().nullable().optional().describe("Coverage factor (2 \u2248 95% confidence level)."),
|
|
34
|
+
type: UncertaintyTypeSchema.nullable().optional()
|
|
35
|
+
}).meta({ id: "MeasurementUncertainty" }).describe(
|
|
36
|
+
'GUM-style measurement uncertainty. Fields are nullable until an uncertainty budget exists \u2014 declaring "unknown" honestly is itself information.'
|
|
37
|
+
);
|
|
38
|
+
var MeasurementSchema = z.object({
|
|
39
|
+
name: z.string().min(1).describe('Measured quantity, e.g. "differential_pressure".'),
|
|
40
|
+
unit: z.string().min(1).describe('UCUM-style unit string, e.g. "Pa", "dB", "uT", "ppm", "/min".'),
|
|
41
|
+
uncertainty: MeasurementUncertaintySchema.optional()
|
|
42
|
+
}).meta({ id: "Measurement" }).describe("One measured quantity with its unit and uncertainty.");
|
|
43
|
+
var CalibrationStatusSchema = z.enum(["none", "candidate_identified", "in_practice", "documented"]).describe(
|
|
44
|
+
"Calibration maturity gradient: none = no calibration; candidate_identified = a reference is named but not used; in_practice = a real method is performed but not fully budgeted; documented = method + uncertainty budget published."
|
|
45
|
+
);
|
|
46
|
+
var SensorCalibrationSchema = z.object({
|
|
47
|
+
status: CalibrationStatusSchema,
|
|
48
|
+
calibrated: z.boolean().nullable().optional().describe("Coarse calibrated flag, mirroring `SensorReading.calibrated`. Null = undetermined."),
|
|
49
|
+
currentMethod: z.string().nullable().optional().describe("What the operator actually does today. Null = no calibration currently performed."),
|
|
50
|
+
traceableReference: z.string().nullable().optional().describe('Traceable reference, in use or identified as a candidate (e.g. "GPS/UTC", "USGS/INTERMAGNET").'),
|
|
51
|
+
referenceInUse: z.boolean().nullable().optional().describe("True = the traceable reference is part of current practice. False = identified candidate only. Null = undetermined."),
|
|
52
|
+
cadence: z.string().nullable().optional().describe("How often calibration is performed."),
|
|
53
|
+
uncertaintyBudget: z.string().nullable().optional().describe("Published uncertainty budget, if any."),
|
|
54
|
+
notes: z.string().nullable().optional().describe("Open questions or method caveats.")
|
|
55
|
+
}).meta({ id: "SensorCalibration" }).describe(
|
|
56
|
+
"Calibration provenance. Deliberately separates what an operator actually does today from the reference it has identified; honest nulls are first-class, so calibration gaps stay visible and comparable across operators."
|
|
57
|
+
);
|
|
58
|
+
var SensorEntrySchema = z.object({
|
|
59
|
+
id: z.string().regex(KEBAB_CASE_PATTERN).describe(
|
|
60
|
+
'Stable kebab-case id, unique within the manifest; addressable from a record via `SensorReading.sensorRef` ("<org-slug>:<sensor-id>").'
|
|
61
|
+
),
|
|
62
|
+
name: z.string().min(1).describe("Human-readable sensor name."),
|
|
63
|
+
modality: ModalitySchema,
|
|
64
|
+
manufacturerModel: z.string().optional().describe(
|
|
65
|
+
'Hardware class descriptor. Publishers MAY withhold specific make/model identities and publish spec-level class descriptors instead (e.g. "dual GM-tube counter" rather than a product name).'
|
|
66
|
+
),
|
|
67
|
+
inHouse: z.boolean().optional().describe("True if operator-built rather than off-the-shelf."),
|
|
68
|
+
compute: z.string().optional().describe("The compute unit this sensor is attached to, for platforms with several compute nodes."),
|
|
69
|
+
recordsMapping: RecordsMappingSchema.optional(),
|
|
70
|
+
timing: SensorTimingSchema.optional(),
|
|
71
|
+
rawData: RawDataSpecSchema.optional(),
|
|
72
|
+
measurements: z.array(MeasurementSchema).optional(),
|
|
73
|
+
calibration: SensorCalibrationSchema.optional(),
|
|
74
|
+
specs: z.record(z.string(), z.unknown()).optional().describe(
|
|
75
|
+
"Free-form hardware specifications from the operator\u2019s spec sheet (resolution, range, sensitivity, interface, \u2026). Keys vary by modality."
|
|
76
|
+
),
|
|
77
|
+
specSource: z.string().optional().describe("Provenance of the spec values.")
|
|
78
|
+
}).meta({ id: "SensorEntry" }).describe("One sensor: its class, spec, timing, raw-data locator, measurements, and calibration provenance.");
|
|
79
|
+
var UpgradeStatusSchema = z.enum(["planned", "evaluating", "ordered", "acquired"]).describe("Acquisition status of a declared future hardware upgrade.");
|
|
80
|
+
var FutureUpgradeSchema = z.object({
|
|
81
|
+
name: z.string().min(1),
|
|
82
|
+
modality: ModalitySchema,
|
|
83
|
+
status: UpgradeStatusSchema.optional(),
|
|
84
|
+
specs: z.record(z.string(), z.unknown()).optional(),
|
|
85
|
+
link: z.string().nullable().optional().describe("Public product or reference page, where the publisher chooses to share one."),
|
|
86
|
+
notes: z.string().nullable().optional()
|
|
87
|
+
}).meta({ id: "FutureUpgrade" }).describe(
|
|
88
|
+
"Planned hardware declared ahead of deployment so data consumers can anticipate new streams. Not part of the live sensor array."
|
|
89
|
+
);
|
|
90
|
+
var SensorManifestSchema = z.object({
|
|
91
|
+
schemaVersion: z.string().min(1).describe("Version of the sensor-manifest schema this instance targets (SemVer)."),
|
|
92
|
+
org: z.string().min(1).describe('Publishing organization, display form (e.g. "ELD\xC6ON").'),
|
|
93
|
+
orgSlug: z.string().regex(KEBAB_CASE_PATTERN).describe('Stable lowercase slug for the publisher (e.g. "eldaeon"); the org half of a `sensorRef`.'),
|
|
94
|
+
orgUrl: z.string().optional().describe("URL for the publishing organization."),
|
|
95
|
+
generatedAt: z.string().optional().describe("ISO date the manifest was generated."),
|
|
96
|
+
sensors: z.array(SensorEntrySchema).min(1),
|
|
97
|
+
futureUpgrades: z.array(FutureUpgradeSchema).optional()
|
|
98
|
+
}).meta({ id: "SensorManifest" }).describe(
|
|
99
|
+
"A published catalog of one organization\u2019s detection hardware. Any operator \u2014 vendor, research group, or institution \u2014 publishes its own manifest against this schema so datasets from different sensor arrays can be compared directly."
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
export { CalibrationStatusSchema, FutureUpgradeSchema, MeasurementSchema, MeasurementUncertaintySchema, ModalitySchema, RawDataSpecSchema, RecordsMappingSchema, SensorCalibrationSchema, SensorEntrySchema, SensorManifestSchema, SensorTimingSchema, TimeSourceSchema, UncertaintyTypeSchema, UpgradeStatusSchema };
|
|
103
|
+
//# sourceMappingURL=index.js.map
|
|
104
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/manifest/types.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { z } from 'zod';\n\n/**\n * The sensor manifest is the instrument layer of the standard: DisclosureOS\n * records describe *what was observed*; a sensor manifest describes *the\n * hardware that produced the data* — per sensor, in enough structured detail\n * that a field mission or data drop from one organization is comparable,\n * replicable, and verifiable by everyone else.\n *\n * Design lineage: proposed by ELDÆON (disclosurefoundation/disclosureos#5) and\n * promoted into the framework as a foundation package. The manifest is the\n * standard's first standalone document type besides `Observation`: it is not a\n * per-observation extension slot — observations point at manifest entries via\n * `SensorReading.sensorRef` (`\"<org-slug>:<sensor-id>\"`).\n */\n\nconst KEBAB_CASE_PATTERN = /^[a-z0-9][a-z0-9-]*$/;\n\nexport const ModalitySchema = z\n .enum(['audio', 'electro_optical', 'radio_frequency', 'quantum', 'environmental', 'biometric'])\n .describe('Top-level sensing modality the sensor belongs to.');\n\nexport type Modality = z.infer<typeof ModalitySchema>;\n\nexport const TimeSourceSchema = z\n .enum(['atomic_clock', 'gps_disciplined', 'ntp', 'system', 'unknown'])\n .describe('Clock source that timestamps the sensor\\u2019s data.');\n\nexport type TimeSource = z.infer<typeof TimeSourceSchema>;\n\nexport const SensorTimingSchema = z\n .object({\n timeSource: TimeSourceSchema,\n timeUncertaintyNs: z\n .number()\n .nullable()\n .optional()\n .describe('Timestamp uncertainty in nanoseconds. Null = not yet characterized.'),\n })\n .meta({ id: 'SensorTiming' })\n .describe(\n 'Timing provenance. Timestamp error of even a few seconds confounds multi-station correlation, so the clock source must be declared, not assumed.',\n );\n\nexport type SensorTiming = z.infer<typeof SensorTimingSchema>;\n\nexport const RecordsMappingSchema = z\n .object({\n sensorType: z\n .string()\n .optional()\n .describe('The `@disclosureos/records` SensorType this sensor maps to.'),\n detectionMethod: z\n .string()\n .optional()\n .describe('The `@disclosureos/records` DetectionMethod this sensor maps to.'),\n proposedSensorType: z\n .boolean()\n .optional()\n .describe('True = sensorType is not in the records enum yet and is proposed by the publisher.'),\n proposedDetectionMethod: z\n .boolean()\n .optional()\n .describe('True = detectionMethod is not in the records enum yet and is proposed by the publisher.'),\n })\n .meta({ id: 'RecordsMapping' })\n .describe(\n 'How this sensor maps to the `SensorReading` vocabulary in `@disclosureos/records`. Values outside the records enums must carry the matching proposed* flag.',\n );\n\nexport type RecordsMapping = z.infer<typeof RecordsMappingSchema>;\n\nexport const RawDataSpecSchema = z\n .object({\n format: z\n .string()\n .optional()\n .describe('Raw-data file format, e.g. \"NDJSON.gz\", \"WAV\", \"MJPEG\", \"FITS\", \"CSV\".'),\n locatorPattern: z\n .string()\n .nullable()\n .optional()\n .describe('Storage key pattern or path convention for locating the raw files.'),\n sampleRateHz: z.number().nullable().optional().describe('Sample rate in Hz, where applicable.'),\n bitDepth: z.number().nullable().optional().describe('Sample bit depth, where applicable.'),\n })\n .meta({ id: 'RawDataSpec' })\n .describe(\n 'Raw-data format and locator. Supports a metadata-first architecture: circulate manifests widely, pull raw data on demand.',\n );\n\nexport type RawDataSpec = z.infer<typeof RawDataSpecSchema>;\n\nexport const UncertaintyTypeSchema = z\n .enum(['A', 'B'])\n .describe('GUM uncertainty evaluation type: A (statistical) or B (other means).');\n\nexport type UncertaintyType = z.infer<typeof UncertaintyTypeSchema>;\n\nexport const MeasurementUncertaintySchema = z\n .object({\n u_c: z.number().nullable().optional().describe('Combined standard uncertainty.'),\n U: z.number().nullable().optional().describe('Expanded uncertainty (= k \\u00d7 u_c).'),\n k: z.number().nullable().optional().describe('Coverage factor (2 \\u2248 95% confidence level).'),\n type: UncertaintyTypeSchema.nullable().optional(),\n })\n .meta({ id: 'MeasurementUncertainty' })\n .describe(\n 'GUM-style measurement uncertainty. Fields are nullable until an uncertainty budget exists — declaring \"unknown\" honestly is itself information.',\n );\n\nexport type MeasurementUncertainty = z.infer<typeof MeasurementUncertaintySchema>;\n\nexport const MeasurementSchema = z\n .object({\n name: z.string().min(1).describe('Measured quantity, e.g. \"differential_pressure\".'),\n unit: z.string().min(1).describe('UCUM-style unit string, e.g. \"Pa\", \"dB\", \"uT\", \"ppm\", \"/min\".'),\n uncertainty: MeasurementUncertaintySchema.optional(),\n })\n .meta({ id: 'Measurement' })\n .describe('One measured quantity with its unit and uncertainty.');\n\nexport type Measurement = z.infer<typeof MeasurementSchema>;\n\nexport const CalibrationStatusSchema = z\n .enum(['none', 'candidate_identified', 'in_practice', 'documented'])\n .describe(\n 'Calibration maturity gradient: none = no calibration; candidate_identified = a reference is named but not used; in_practice = a real method is performed but not fully budgeted; documented = method + uncertainty budget published.',\n );\n\nexport type CalibrationStatus = z.infer<typeof CalibrationStatusSchema>;\n\nexport const SensorCalibrationSchema = z\n .object({\n status: CalibrationStatusSchema,\n calibrated: z\n .boolean()\n .nullable()\n .optional()\n .describe('Coarse calibrated flag, mirroring `SensorReading.calibrated`. Null = undetermined.'),\n currentMethod: z\n .string()\n .nullable()\n .optional()\n .describe('What the operator actually does today. Null = no calibration currently performed.'),\n traceableReference: z\n .string()\n .nullable()\n .optional()\n .describe('Traceable reference, in use or identified as a candidate (e.g. \"GPS/UTC\", \"USGS/INTERMAGNET\").'),\n referenceInUse: z\n .boolean()\n .nullable()\n .optional()\n .describe('True = the traceable reference is part of current practice. False = identified candidate only. Null = undetermined.'),\n cadence: z.string().nullable().optional().describe('How often calibration is performed.'),\n uncertaintyBudget: z.string().nullable().optional().describe('Published uncertainty budget, if any.'),\n notes: z.string().nullable().optional().describe('Open questions or method caveats.'),\n })\n .meta({ id: 'SensorCalibration' })\n .describe(\n 'Calibration provenance. Deliberately separates what an operator actually does today from the reference it has identified; honest nulls are first-class, so calibration gaps stay visible and comparable across operators.',\n );\n\nexport type SensorCalibration = z.infer<typeof SensorCalibrationSchema>;\n\nexport const SensorEntrySchema = z\n .object({\n id: z\n .string()\n .regex(KEBAB_CASE_PATTERN)\n .describe(\n 'Stable kebab-case id, unique within the manifest; addressable from a record via `SensorReading.sensorRef` (\"<org-slug>:<sensor-id>\").',\n ),\n name: z.string().min(1).describe('Human-readable sensor name.'),\n modality: ModalitySchema,\n manufacturerModel: z\n .string()\n .optional()\n .describe(\n 'Hardware class descriptor. Publishers MAY withhold specific make/model identities and publish spec-level class descriptors instead (e.g. \"dual GM-tube counter\" rather than a product name).',\n ),\n inHouse: z.boolean().optional().describe('True if operator-built rather than off-the-shelf.'),\n compute: z\n .string()\n .optional()\n .describe('The compute unit this sensor is attached to, for platforms with several compute nodes.'),\n recordsMapping: RecordsMappingSchema.optional(),\n timing: SensorTimingSchema.optional(),\n rawData: RawDataSpecSchema.optional(),\n measurements: z.array(MeasurementSchema).optional(),\n calibration: SensorCalibrationSchema.optional(),\n specs: z\n .record(z.string(), z.unknown())\n .optional()\n .describe(\n 'Free-form hardware specifications from the operator\\u2019s spec sheet (resolution, range, sensitivity, interface, \\u2026). Keys vary by modality.',\n ),\n specSource: z.string().optional().describe('Provenance of the spec values.'),\n })\n .meta({ id: 'SensorEntry' })\n .describe('One sensor: its class, spec, timing, raw-data locator, measurements, and calibration provenance.');\n\nexport type SensorEntry = z.infer<typeof SensorEntrySchema>;\n\nexport const UpgradeStatusSchema = z\n .enum(['planned', 'evaluating', 'ordered', 'acquired'])\n .describe('Acquisition status of a declared future hardware upgrade.');\n\nexport type UpgradeStatus = z.infer<typeof UpgradeStatusSchema>;\n\nexport const FutureUpgradeSchema = z\n .object({\n name: z.string().min(1),\n modality: ModalitySchema,\n status: UpgradeStatusSchema.optional(),\n specs: z.record(z.string(), z.unknown()).optional(),\n link: z.string().nullable().optional().describe('Public product or reference page, where the publisher chooses to share one.'),\n notes: z.string().nullable().optional(),\n })\n .meta({ id: 'FutureUpgrade' })\n .describe(\n 'Planned hardware declared ahead of deployment so data consumers can anticipate new streams. Not part of the live sensor array.',\n );\n\nexport type FutureUpgrade = z.infer<typeof FutureUpgradeSchema>;\n\nexport const SensorManifestSchema = z\n .object({\n schemaVersion: z.string().min(1).describe('Version of the sensor-manifest schema this instance targets (SemVer).'),\n org: z.string().min(1).describe('Publishing organization, display form (e.g. \"ELD\\u00c6ON\").'),\n orgSlug: z\n .string()\n .regex(KEBAB_CASE_PATTERN)\n .describe('Stable lowercase slug for the publisher (e.g. \"eldaeon\"); the org half of a `sensorRef`.'),\n orgUrl: z.string().optional().describe('URL for the publishing organization.'),\n generatedAt: z.string().optional().describe('ISO date the manifest was generated.'),\n sensors: z.array(SensorEntrySchema).min(1),\n futureUpgrades: z.array(FutureUpgradeSchema).optional(),\n })\n .meta({ id: 'SensorManifest' })\n .describe(\n 'A published catalog of one organization\\u2019s detection hardware. Any operator — vendor, research group, or institution — publishes its own manifest against this schema so datasets from different sensor arrays can be compared directly.',\n );\n\nexport type SensorManifest = z.infer<typeof SensorManifestSchema>;\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ValidationIssue } from '@disclosureos/records/shared';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Validate a sensor manifest. Schema validation plus the structural invariants
|
|
5
|
+
* Zod cannot express portably:
|
|
6
|
+
*
|
|
7
|
+
* 1. sensor ids are unique within the manifest;
|
|
8
|
+
* 2. every `recordsMapping` value either exists in the `@disclosureos/records`
|
|
9
|
+
* enums or carries the matching `proposed*` flag — so a manifest can never
|
|
10
|
+
* silently claim a mapping the records vocabulary does not have.
|
|
11
|
+
*
|
|
12
|
+
* Returns a flat issue list (empty when valid) — the ecosystem's single
|
|
13
|
+
* validation contract.
|
|
14
|
+
*/
|
|
15
|
+
declare function validateSensorManifest(value: unknown): ValidationIssue[];
|
|
16
|
+
|
|
17
|
+
export { validateSensorManifest };
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { validateWith } from '@disclosureos/records/shared';
|
|
2
|
+
import { SENSOR_TYPES, DETECTION_METHODS } from '@disclosureos/records/constants';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
|
|
5
|
+
// src/validators/index.ts
|
|
6
|
+
var KEBAB_CASE_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
|
|
7
|
+
var ModalitySchema = z.enum(["audio", "electro_optical", "radio_frequency", "quantum", "environmental", "biometric"]).describe("Top-level sensing modality the sensor belongs to.");
|
|
8
|
+
var TimeSourceSchema = z.enum(["atomic_clock", "gps_disciplined", "ntp", "system", "unknown"]).describe("Clock source that timestamps the sensor\u2019s data.");
|
|
9
|
+
var SensorTimingSchema = z.object({
|
|
10
|
+
timeSource: TimeSourceSchema,
|
|
11
|
+
timeUncertaintyNs: z.number().nullable().optional().describe("Timestamp uncertainty in nanoseconds. Null = not yet characterized.")
|
|
12
|
+
}).meta({ id: "SensorTiming" }).describe(
|
|
13
|
+
"Timing provenance. Timestamp error of even a few seconds confounds multi-station correlation, so the clock source must be declared, not assumed."
|
|
14
|
+
);
|
|
15
|
+
var RecordsMappingSchema = z.object({
|
|
16
|
+
sensorType: z.string().optional().describe("The `@disclosureos/records` SensorType this sensor maps to."),
|
|
17
|
+
detectionMethod: z.string().optional().describe("The `@disclosureos/records` DetectionMethod this sensor maps to."),
|
|
18
|
+
proposedSensorType: z.boolean().optional().describe("True = sensorType is not in the records enum yet and is proposed by the publisher."),
|
|
19
|
+
proposedDetectionMethod: z.boolean().optional().describe("True = detectionMethod is not in the records enum yet and is proposed by the publisher.")
|
|
20
|
+
}).meta({ id: "RecordsMapping" }).describe(
|
|
21
|
+
"How this sensor maps to the `SensorReading` vocabulary in `@disclosureos/records`. Values outside the records enums must carry the matching proposed* flag."
|
|
22
|
+
);
|
|
23
|
+
var RawDataSpecSchema = z.object({
|
|
24
|
+
format: z.string().optional().describe('Raw-data file format, e.g. "NDJSON.gz", "WAV", "MJPEG", "FITS", "CSV".'),
|
|
25
|
+
locatorPattern: z.string().nullable().optional().describe("Storage key pattern or path convention for locating the raw files."),
|
|
26
|
+
sampleRateHz: z.number().nullable().optional().describe("Sample rate in Hz, where applicable."),
|
|
27
|
+
bitDepth: z.number().nullable().optional().describe("Sample bit depth, where applicable.")
|
|
28
|
+
}).meta({ id: "RawDataSpec" }).describe(
|
|
29
|
+
"Raw-data format and locator. Supports a metadata-first architecture: circulate manifests widely, pull raw data on demand."
|
|
30
|
+
);
|
|
31
|
+
var UncertaintyTypeSchema = z.enum(["A", "B"]).describe("GUM uncertainty evaluation type: A (statistical) or B (other means).");
|
|
32
|
+
var MeasurementUncertaintySchema = z.object({
|
|
33
|
+
u_c: z.number().nullable().optional().describe("Combined standard uncertainty."),
|
|
34
|
+
U: z.number().nullable().optional().describe("Expanded uncertainty (= k \xD7 u_c)."),
|
|
35
|
+
k: z.number().nullable().optional().describe("Coverage factor (2 \u2248 95% confidence level)."),
|
|
36
|
+
type: UncertaintyTypeSchema.nullable().optional()
|
|
37
|
+
}).meta({ id: "MeasurementUncertainty" }).describe(
|
|
38
|
+
'GUM-style measurement uncertainty. Fields are nullable until an uncertainty budget exists \u2014 declaring "unknown" honestly is itself information.'
|
|
39
|
+
);
|
|
40
|
+
var MeasurementSchema = z.object({
|
|
41
|
+
name: z.string().min(1).describe('Measured quantity, e.g. "differential_pressure".'),
|
|
42
|
+
unit: z.string().min(1).describe('UCUM-style unit string, e.g. "Pa", "dB", "uT", "ppm", "/min".'),
|
|
43
|
+
uncertainty: MeasurementUncertaintySchema.optional()
|
|
44
|
+
}).meta({ id: "Measurement" }).describe("One measured quantity with its unit and uncertainty.");
|
|
45
|
+
var CalibrationStatusSchema = z.enum(["none", "candidate_identified", "in_practice", "documented"]).describe(
|
|
46
|
+
"Calibration maturity gradient: none = no calibration; candidate_identified = a reference is named but not used; in_practice = a real method is performed but not fully budgeted; documented = method + uncertainty budget published."
|
|
47
|
+
);
|
|
48
|
+
var SensorCalibrationSchema = z.object({
|
|
49
|
+
status: CalibrationStatusSchema,
|
|
50
|
+
calibrated: z.boolean().nullable().optional().describe("Coarse calibrated flag, mirroring `SensorReading.calibrated`. Null = undetermined."),
|
|
51
|
+
currentMethod: z.string().nullable().optional().describe("What the operator actually does today. Null = no calibration currently performed."),
|
|
52
|
+
traceableReference: z.string().nullable().optional().describe('Traceable reference, in use or identified as a candidate (e.g. "GPS/UTC", "USGS/INTERMAGNET").'),
|
|
53
|
+
referenceInUse: z.boolean().nullable().optional().describe("True = the traceable reference is part of current practice. False = identified candidate only. Null = undetermined."),
|
|
54
|
+
cadence: z.string().nullable().optional().describe("How often calibration is performed."),
|
|
55
|
+
uncertaintyBudget: z.string().nullable().optional().describe("Published uncertainty budget, if any."),
|
|
56
|
+
notes: z.string().nullable().optional().describe("Open questions or method caveats.")
|
|
57
|
+
}).meta({ id: "SensorCalibration" }).describe(
|
|
58
|
+
"Calibration provenance. Deliberately separates what an operator actually does today from the reference it has identified; honest nulls are first-class, so calibration gaps stay visible and comparable across operators."
|
|
59
|
+
);
|
|
60
|
+
var SensorEntrySchema = z.object({
|
|
61
|
+
id: z.string().regex(KEBAB_CASE_PATTERN).describe(
|
|
62
|
+
'Stable kebab-case id, unique within the manifest; addressable from a record via `SensorReading.sensorRef` ("<org-slug>:<sensor-id>").'
|
|
63
|
+
),
|
|
64
|
+
name: z.string().min(1).describe("Human-readable sensor name."),
|
|
65
|
+
modality: ModalitySchema,
|
|
66
|
+
manufacturerModel: z.string().optional().describe(
|
|
67
|
+
'Hardware class descriptor. Publishers MAY withhold specific make/model identities and publish spec-level class descriptors instead (e.g. "dual GM-tube counter" rather than a product name).'
|
|
68
|
+
),
|
|
69
|
+
inHouse: z.boolean().optional().describe("True if operator-built rather than off-the-shelf."),
|
|
70
|
+
compute: z.string().optional().describe("The compute unit this sensor is attached to, for platforms with several compute nodes."),
|
|
71
|
+
recordsMapping: RecordsMappingSchema.optional(),
|
|
72
|
+
timing: SensorTimingSchema.optional(),
|
|
73
|
+
rawData: RawDataSpecSchema.optional(),
|
|
74
|
+
measurements: z.array(MeasurementSchema).optional(),
|
|
75
|
+
calibration: SensorCalibrationSchema.optional(),
|
|
76
|
+
specs: z.record(z.string(), z.unknown()).optional().describe(
|
|
77
|
+
"Free-form hardware specifications from the operator\u2019s spec sheet (resolution, range, sensitivity, interface, \u2026). Keys vary by modality."
|
|
78
|
+
),
|
|
79
|
+
specSource: z.string().optional().describe("Provenance of the spec values.")
|
|
80
|
+
}).meta({ id: "SensorEntry" }).describe("One sensor: its class, spec, timing, raw-data locator, measurements, and calibration provenance.");
|
|
81
|
+
var UpgradeStatusSchema = z.enum(["planned", "evaluating", "ordered", "acquired"]).describe("Acquisition status of a declared future hardware upgrade.");
|
|
82
|
+
var FutureUpgradeSchema = z.object({
|
|
83
|
+
name: z.string().min(1),
|
|
84
|
+
modality: ModalitySchema,
|
|
85
|
+
status: UpgradeStatusSchema.optional(),
|
|
86
|
+
specs: z.record(z.string(), z.unknown()).optional(),
|
|
87
|
+
link: z.string().nullable().optional().describe("Public product or reference page, where the publisher chooses to share one."),
|
|
88
|
+
notes: z.string().nullable().optional()
|
|
89
|
+
}).meta({ id: "FutureUpgrade" }).describe(
|
|
90
|
+
"Planned hardware declared ahead of deployment so data consumers can anticipate new streams. Not part of the live sensor array."
|
|
91
|
+
);
|
|
92
|
+
var SensorManifestSchema = z.object({
|
|
93
|
+
schemaVersion: z.string().min(1).describe("Version of the sensor-manifest schema this instance targets (SemVer)."),
|
|
94
|
+
org: z.string().min(1).describe('Publishing organization, display form (e.g. "ELD\xC6ON").'),
|
|
95
|
+
orgSlug: z.string().regex(KEBAB_CASE_PATTERN).describe('Stable lowercase slug for the publisher (e.g. "eldaeon"); the org half of a `sensorRef`.'),
|
|
96
|
+
orgUrl: z.string().optional().describe("URL for the publishing organization."),
|
|
97
|
+
generatedAt: z.string().optional().describe("ISO date the manifest was generated."),
|
|
98
|
+
sensors: z.array(SensorEntrySchema).min(1),
|
|
99
|
+
futureUpgrades: z.array(FutureUpgradeSchema).optional()
|
|
100
|
+
}).meta({ id: "SensorManifest" }).describe(
|
|
101
|
+
"A published catalog of one organization\u2019s detection hardware. Any operator \u2014 vendor, research group, or institution \u2014 publishes its own manifest against this schema so datasets from different sensor arrays can be compared directly."
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
// src/validators/index.ts
|
|
105
|
+
var KNOWN_SENSOR_TYPES = new Set(SENSOR_TYPES);
|
|
106
|
+
var KNOWN_DETECTION_METHODS = new Set(DETECTION_METHODS);
|
|
107
|
+
function validateSensorManifest(value) {
|
|
108
|
+
const issues = validateWith(SensorManifestSchema, value);
|
|
109
|
+
if (issues.length > 0) return issues;
|
|
110
|
+
const manifest = value;
|
|
111
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
112
|
+
manifest.sensors.forEach((sensor, index) => {
|
|
113
|
+
const path = `sensors.${index}`;
|
|
114
|
+
if (seenIds.has(sensor.id)) {
|
|
115
|
+
issues.push({ path: `${path}.id`, message: `Duplicate sensor id "${sensor.id}".` });
|
|
116
|
+
}
|
|
117
|
+
seenIds.add(sensor.id);
|
|
118
|
+
const mapping = sensor.recordsMapping;
|
|
119
|
+
if (!mapping) return;
|
|
120
|
+
if (mapping.sensorType !== void 0 && !KNOWN_SENSOR_TYPES.has(mapping.sensorType) && mapping.proposedSensorType !== true) {
|
|
121
|
+
issues.push({
|
|
122
|
+
path: `${path}.recordsMapping.sensorType`,
|
|
123
|
+
message: `"${mapping.sensorType}" is not a records SensorType; flag it with proposedSensorType: true or use a value from the enum.`
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
if (mapping.detectionMethod !== void 0 && !KNOWN_DETECTION_METHODS.has(mapping.detectionMethod) && mapping.proposedDetectionMethod !== true) {
|
|
127
|
+
issues.push({
|
|
128
|
+
path: `${path}.recordsMapping.detectionMethod`,
|
|
129
|
+
message: `"${mapping.detectionMethod}" is not a records DetectionMethod; flag it with proposedDetectionMethod: true or use a value from the enum.`
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
return issues;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export { validateSensorManifest };
|
|
137
|
+
//# sourceMappingURL=index.js.map
|
|
138
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/manifest/types.ts","../../src/validators/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { z } from 'zod';\n\n/**\n * The sensor manifest is the instrument layer of the standard: DisclosureOS\n * records describe *what was observed*; a sensor manifest describes *the\n * hardware that produced the data* — per sensor, in enough structured detail\n * that a field mission or data drop from one organization is comparable,\n * replicable, and verifiable by everyone else.\n *\n * Design lineage: proposed by ELDÆON (disclosurefoundation/disclosureos#5) and\n * promoted into the framework as a foundation package. The manifest is the\n * standard's first standalone document type besides `Observation`: it is not a\n * per-observation extension slot — observations point at manifest entries via\n * `SensorReading.sensorRef` (`\"<org-slug>:<sensor-id>\"`).\n */\n\nconst KEBAB_CASE_PATTERN = /^[a-z0-9][a-z0-9-]*$/;\n\nexport const ModalitySchema = z\n .enum(['audio', 'electro_optical', 'radio_frequency', 'quantum', 'environmental', 'biometric'])\n .describe('Top-level sensing modality the sensor belongs to.');\n\nexport type Modality = z.infer<typeof ModalitySchema>;\n\nexport const TimeSourceSchema = z\n .enum(['atomic_clock', 'gps_disciplined', 'ntp', 'system', 'unknown'])\n .describe('Clock source that timestamps the sensor\\u2019s data.');\n\nexport type TimeSource = z.infer<typeof TimeSourceSchema>;\n\nexport const SensorTimingSchema = z\n .object({\n timeSource: TimeSourceSchema,\n timeUncertaintyNs: z\n .number()\n .nullable()\n .optional()\n .describe('Timestamp uncertainty in nanoseconds. Null = not yet characterized.'),\n })\n .meta({ id: 'SensorTiming' })\n .describe(\n 'Timing provenance. Timestamp error of even a few seconds confounds multi-station correlation, so the clock source must be declared, not assumed.',\n );\n\nexport type SensorTiming = z.infer<typeof SensorTimingSchema>;\n\nexport const RecordsMappingSchema = z\n .object({\n sensorType: z\n .string()\n .optional()\n .describe('The `@disclosureos/records` SensorType this sensor maps to.'),\n detectionMethod: z\n .string()\n .optional()\n .describe('The `@disclosureos/records` DetectionMethod this sensor maps to.'),\n proposedSensorType: z\n .boolean()\n .optional()\n .describe('True = sensorType is not in the records enum yet and is proposed by the publisher.'),\n proposedDetectionMethod: z\n .boolean()\n .optional()\n .describe('True = detectionMethod is not in the records enum yet and is proposed by the publisher.'),\n })\n .meta({ id: 'RecordsMapping' })\n .describe(\n 'How this sensor maps to the `SensorReading` vocabulary in `@disclosureos/records`. Values outside the records enums must carry the matching proposed* flag.',\n );\n\nexport type RecordsMapping = z.infer<typeof RecordsMappingSchema>;\n\nexport const RawDataSpecSchema = z\n .object({\n format: z\n .string()\n .optional()\n .describe('Raw-data file format, e.g. \"NDJSON.gz\", \"WAV\", \"MJPEG\", \"FITS\", \"CSV\".'),\n locatorPattern: z\n .string()\n .nullable()\n .optional()\n .describe('Storage key pattern or path convention for locating the raw files.'),\n sampleRateHz: z.number().nullable().optional().describe('Sample rate in Hz, where applicable.'),\n bitDepth: z.number().nullable().optional().describe('Sample bit depth, where applicable.'),\n })\n .meta({ id: 'RawDataSpec' })\n .describe(\n 'Raw-data format and locator. Supports a metadata-first architecture: circulate manifests widely, pull raw data on demand.',\n );\n\nexport type RawDataSpec = z.infer<typeof RawDataSpecSchema>;\n\nexport const UncertaintyTypeSchema = z\n .enum(['A', 'B'])\n .describe('GUM uncertainty evaluation type: A (statistical) or B (other means).');\n\nexport type UncertaintyType = z.infer<typeof UncertaintyTypeSchema>;\n\nexport const MeasurementUncertaintySchema = z\n .object({\n u_c: z.number().nullable().optional().describe('Combined standard uncertainty.'),\n U: z.number().nullable().optional().describe('Expanded uncertainty (= k \\u00d7 u_c).'),\n k: z.number().nullable().optional().describe('Coverage factor (2 \\u2248 95% confidence level).'),\n type: UncertaintyTypeSchema.nullable().optional(),\n })\n .meta({ id: 'MeasurementUncertainty' })\n .describe(\n 'GUM-style measurement uncertainty. Fields are nullable until an uncertainty budget exists — declaring \"unknown\" honestly is itself information.',\n );\n\nexport type MeasurementUncertainty = z.infer<typeof MeasurementUncertaintySchema>;\n\nexport const MeasurementSchema = z\n .object({\n name: z.string().min(1).describe('Measured quantity, e.g. \"differential_pressure\".'),\n unit: z.string().min(1).describe('UCUM-style unit string, e.g. \"Pa\", \"dB\", \"uT\", \"ppm\", \"/min\".'),\n uncertainty: MeasurementUncertaintySchema.optional(),\n })\n .meta({ id: 'Measurement' })\n .describe('One measured quantity with its unit and uncertainty.');\n\nexport type Measurement = z.infer<typeof MeasurementSchema>;\n\nexport const CalibrationStatusSchema = z\n .enum(['none', 'candidate_identified', 'in_practice', 'documented'])\n .describe(\n 'Calibration maturity gradient: none = no calibration; candidate_identified = a reference is named but not used; in_practice = a real method is performed but not fully budgeted; documented = method + uncertainty budget published.',\n );\n\nexport type CalibrationStatus = z.infer<typeof CalibrationStatusSchema>;\n\nexport const SensorCalibrationSchema = z\n .object({\n status: CalibrationStatusSchema,\n calibrated: z\n .boolean()\n .nullable()\n .optional()\n .describe('Coarse calibrated flag, mirroring `SensorReading.calibrated`. Null = undetermined.'),\n currentMethod: z\n .string()\n .nullable()\n .optional()\n .describe('What the operator actually does today. Null = no calibration currently performed.'),\n traceableReference: z\n .string()\n .nullable()\n .optional()\n .describe('Traceable reference, in use or identified as a candidate (e.g. \"GPS/UTC\", \"USGS/INTERMAGNET\").'),\n referenceInUse: z\n .boolean()\n .nullable()\n .optional()\n .describe('True = the traceable reference is part of current practice. False = identified candidate only. Null = undetermined.'),\n cadence: z.string().nullable().optional().describe('How often calibration is performed.'),\n uncertaintyBudget: z.string().nullable().optional().describe('Published uncertainty budget, if any.'),\n notes: z.string().nullable().optional().describe('Open questions or method caveats.'),\n })\n .meta({ id: 'SensorCalibration' })\n .describe(\n 'Calibration provenance. Deliberately separates what an operator actually does today from the reference it has identified; honest nulls are first-class, so calibration gaps stay visible and comparable across operators.',\n );\n\nexport type SensorCalibration = z.infer<typeof SensorCalibrationSchema>;\n\nexport const SensorEntrySchema = z\n .object({\n id: z\n .string()\n .regex(KEBAB_CASE_PATTERN)\n .describe(\n 'Stable kebab-case id, unique within the manifest; addressable from a record via `SensorReading.sensorRef` (\"<org-slug>:<sensor-id>\").',\n ),\n name: z.string().min(1).describe('Human-readable sensor name.'),\n modality: ModalitySchema,\n manufacturerModel: z\n .string()\n .optional()\n .describe(\n 'Hardware class descriptor. Publishers MAY withhold specific make/model identities and publish spec-level class descriptors instead (e.g. \"dual GM-tube counter\" rather than a product name).',\n ),\n inHouse: z.boolean().optional().describe('True if operator-built rather than off-the-shelf.'),\n compute: z\n .string()\n .optional()\n .describe('The compute unit this sensor is attached to, for platforms with several compute nodes.'),\n recordsMapping: RecordsMappingSchema.optional(),\n timing: SensorTimingSchema.optional(),\n rawData: RawDataSpecSchema.optional(),\n measurements: z.array(MeasurementSchema).optional(),\n calibration: SensorCalibrationSchema.optional(),\n specs: z\n .record(z.string(), z.unknown())\n .optional()\n .describe(\n 'Free-form hardware specifications from the operator\\u2019s spec sheet (resolution, range, sensitivity, interface, \\u2026). Keys vary by modality.',\n ),\n specSource: z.string().optional().describe('Provenance of the spec values.'),\n })\n .meta({ id: 'SensorEntry' })\n .describe('One sensor: its class, spec, timing, raw-data locator, measurements, and calibration provenance.');\n\nexport type SensorEntry = z.infer<typeof SensorEntrySchema>;\n\nexport const UpgradeStatusSchema = z\n .enum(['planned', 'evaluating', 'ordered', 'acquired'])\n .describe('Acquisition status of a declared future hardware upgrade.');\n\nexport type UpgradeStatus = z.infer<typeof UpgradeStatusSchema>;\n\nexport const FutureUpgradeSchema = z\n .object({\n name: z.string().min(1),\n modality: ModalitySchema,\n status: UpgradeStatusSchema.optional(),\n specs: z.record(z.string(), z.unknown()).optional(),\n link: z.string().nullable().optional().describe('Public product or reference page, where the publisher chooses to share one.'),\n notes: z.string().nullable().optional(),\n })\n .meta({ id: 'FutureUpgrade' })\n .describe(\n 'Planned hardware declared ahead of deployment so data consumers can anticipate new streams. Not part of the live sensor array.',\n );\n\nexport type FutureUpgrade = z.infer<typeof FutureUpgradeSchema>;\n\nexport const SensorManifestSchema = z\n .object({\n schemaVersion: z.string().min(1).describe('Version of the sensor-manifest schema this instance targets (SemVer).'),\n org: z.string().min(1).describe('Publishing organization, display form (e.g. \"ELD\\u00c6ON\").'),\n orgSlug: z\n .string()\n .regex(KEBAB_CASE_PATTERN)\n .describe('Stable lowercase slug for the publisher (e.g. \"eldaeon\"); the org half of a `sensorRef`.'),\n orgUrl: z.string().optional().describe('URL for the publishing organization.'),\n generatedAt: z.string().optional().describe('ISO date the manifest was generated.'),\n sensors: z.array(SensorEntrySchema).min(1),\n futureUpgrades: z.array(FutureUpgradeSchema).optional(),\n })\n .meta({ id: 'SensorManifest' })\n .describe(\n 'A published catalog of one organization\\u2019s detection hardware. Any operator — vendor, research group, or institution — publishes its own manifest against this schema so datasets from different sensor arrays can be compared directly.',\n );\n\nexport type SensorManifest = z.infer<typeof SensorManifestSchema>;\n","import { validateWith } from '@disclosureos/records/shared';\nimport type { ValidationIssue } from '@disclosureos/records/shared';\nimport { SENSOR_TYPES, DETECTION_METHODS } from '@disclosureos/records/constants';\nimport { SensorManifestSchema } from '../manifest/types';\nimport type { SensorManifest } from '../manifest/types';\n\nconst KNOWN_SENSOR_TYPES = new Set<string>(SENSOR_TYPES);\nconst KNOWN_DETECTION_METHODS = new Set<string>(DETECTION_METHODS);\n\n/**\n * Validate a sensor manifest. Schema validation plus the structural invariants\n * Zod cannot express portably:\n *\n * 1. sensor ids are unique within the manifest;\n * 2. every `recordsMapping` value either exists in the `@disclosureos/records`\n * enums or carries the matching `proposed*` flag — so a manifest can never\n * silently claim a mapping the records vocabulary does not have.\n *\n * Returns a flat issue list (empty when valid) — the ecosystem's single\n * validation contract.\n */\nexport function validateSensorManifest(value: unknown): ValidationIssue[] {\n const issues = validateWith(SensorManifestSchema, value);\n if (issues.length > 0) return issues;\n\n const manifest = value as SensorManifest;\n const seenIds = new Set<string>();\n\n manifest.sensors.forEach((sensor, index) => {\n const path = `sensors.${index}`;\n\n if (seenIds.has(sensor.id)) {\n issues.push({ path: `${path}.id`, message: `Duplicate sensor id \"${sensor.id}\".` });\n }\n seenIds.add(sensor.id);\n\n const mapping = sensor.recordsMapping;\n if (!mapping) return;\n\n if (\n mapping.sensorType !== undefined\n && !KNOWN_SENSOR_TYPES.has(mapping.sensorType)\n && mapping.proposedSensorType !== true\n ) {\n issues.push({\n path: `${path}.recordsMapping.sensorType`,\n message:\n `\"${mapping.sensorType}\" is not a records SensorType; flag it with proposedSensorType: true or use a value from the enum.`,\n });\n }\n\n if (\n mapping.detectionMethod !== undefined\n && !KNOWN_DETECTION_METHODS.has(mapping.detectionMethod)\n && mapping.proposedDetectionMethod !== true\n ) {\n issues.push({\n path: `${path}.recordsMapping.detectionMethod`,\n message:\n `\"${mapping.detectionMethod}\" is not a records DetectionMethod; flag it with proposedDetectionMethod: true or use a value from the enum.`,\n });\n }\n });\n\n return issues;\n}\n"]}
|