@wemush/wols 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/LICENSE +201 -0
- package/README.md +294 -0
- package/dist/cjs/compact-url.js +272 -0
- package/dist/cjs/compact-url.js.map +1 -0
- package/dist/cjs/crypto/decrypt.js +125 -0
- package/dist/cjs/crypto/decrypt.js.map +1 -0
- package/dist/cjs/crypto/encrypt.js +151 -0
- package/dist/cjs/crypto/encrypt.js.map +1 -0
- package/dist/cjs/crypto/index.js +16 -0
- package/dist/cjs/crypto/index.js.map +1 -0
- package/dist/cjs/errors.js +188 -0
- package/dist/cjs/errors.js.map +1 -0
- package/dist/cjs/index.js +81 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/parser.js +148 -0
- package/dist/cjs/parser.js.map +1 -0
- package/dist/cjs/qr/generate.js +275 -0
- package/dist/cjs/qr/generate.js.map +1 -0
- package/dist/cjs/qr/index.js +18 -0
- package/dist/cjs/qr/index.js.map +1 -0
- package/dist/cjs/specimen.js +163 -0
- package/dist/cjs/specimen.js.map +1 -0
- package/dist/cjs/types.js +78 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/cjs/utils/cuid.js +150 -0
- package/dist/cjs/utils/cuid.js.map +1 -0
- package/dist/cjs/utils/iso8601.js +131 -0
- package/dist/cjs/utils/iso8601.js.map +1 -0
- package/dist/cjs/validator.js +307 -0
- package/dist/cjs/validator.js.map +1 -0
- package/dist/esm/compact-url.js +264 -0
- package/dist/esm/compact-url.js.map +1 -0
- package/dist/esm/crypto/decrypt.js +122 -0
- package/dist/esm/crypto/decrypt.js.map +1 -0
- package/dist/esm/crypto/encrypt.js +147 -0
- package/dist/esm/crypto/encrypt.js.map +1 -0
- package/dist/esm/crypto/index.js +10 -0
- package/dist/esm/crypto/index.js.map +1 -0
- package/dist/esm/errors.js +178 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/index.js +47 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/parser.js +145 -0
- package/dist/esm/parser.js.map +1 -0
- package/dist/esm/qr/generate.js +235 -0
- package/dist/esm/qr/generate.js.map +1 -0
- package/dist/esm/qr/index.js +10 -0
- package/dist/esm/qr/index.js.map +1 -0
- package/dist/esm/specimen.js +159 -0
- package/dist/esm/specimen.js.map +1 -0
- package/dist/esm/types.js +71 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/utils/cuid.js +145 -0
- package/dist/esm/utils/cuid.js.map +1 -0
- package/dist/esm/utils/iso8601.js +122 -0
- package/dist/esm/utils/iso8601.js.map +1 -0
- package/dist/esm/validator.js +304 -0
- package/dist/esm/validator.js.map +1 -0
- package/dist/types/compact-url.d.ts +104 -0
- package/dist/types/compact-url.d.ts.map +1 -0
- package/dist/types/crypto/decrypt.d.ts +33 -0
- package/dist/types/crypto/decrypt.d.ts.map +1 -0
- package/dist/types/crypto/encrypt.d.ts +32 -0
- package/dist/types/crypto/encrypt.d.ts.map +1 -0
- package/dist/types/crypto/index.d.ts +10 -0
- package/dist/types/crypto/index.d.ts.map +1 -0
- package/dist/types/errors.d.ts +103 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/index.d.ts +21 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/parser.d.ts +30 -0
- package/dist/types/parser.d.ts.map +1 -0
- package/dist/types/qr/generate.d.ts +62 -0
- package/dist/types/qr/generate.d.ts.map +1 -0
- package/dist/types/qr/index.d.ts +10 -0
- package/dist/types/qr/index.d.ts.map +1 -0
- package/dist/types/specimen.d.ts +71 -0
- package/dist/types/specimen.d.ts.map +1 -0
- package/dist/types/types.d.ts +269 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/utils/cuid.d.ts +44 -0
- package/dist/types/utils/cuid.d.ts.map +1 -0
- package/dist/types/utils/iso8601.d.ts +79 -0
- package/dist/types/utils/iso8601.d.ts.map +1 -0
- package/dist/types/validator.d.ts +25 -0
- package/dist/types/validator.d.ts.map +1 -0
- package/package.json +95 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WOLS Specimen Validator
|
|
3
|
+
*
|
|
4
|
+
* This module provides validation functionality for WOLS specimen objects.
|
|
5
|
+
*
|
|
6
|
+
* @module validator
|
|
7
|
+
*/
|
|
8
|
+
import { WolsErrorCode } from './errors.js';
|
|
9
|
+
import { isGrowthStage, isSpecimenType, WOLS_CONTEXT, } from './types.js';
|
|
10
|
+
import { isValidISO8601 } from './utils/iso8601.js';
|
|
11
|
+
// =============================================================================
|
|
12
|
+
// VALIDATION PATTERNS
|
|
13
|
+
// =============================================================================
|
|
14
|
+
/**
|
|
15
|
+
* Pattern for valid specimen ID: wemush:[a-z0-9]+
|
|
16
|
+
*/
|
|
17
|
+
const SPECIMEN_ID_PATTERN = /^wemush:[a-z0-9]+$/;
|
|
18
|
+
/**
|
|
19
|
+
* Pattern for valid semver version: major.minor.patch
|
|
20
|
+
*/
|
|
21
|
+
const SEMVER_PATTERN = /^\d+\.\d+\.\d+$/;
|
|
22
|
+
/**
|
|
23
|
+
* Pattern for valid strain generation: P, F1, F2, F3, etc.
|
|
24
|
+
*/
|
|
25
|
+
const GENERATION_PATTERN = /^(P|F\d+)$/;
|
|
26
|
+
/**
|
|
27
|
+
* Known WOLS specimen fields (for unknown field detection).
|
|
28
|
+
*/
|
|
29
|
+
const KNOWN_FIELDS = new Set([
|
|
30
|
+
'@context',
|
|
31
|
+
'@type',
|
|
32
|
+
'id',
|
|
33
|
+
'version',
|
|
34
|
+
'type',
|
|
35
|
+
'species',
|
|
36
|
+
'strain',
|
|
37
|
+
'stage',
|
|
38
|
+
'created',
|
|
39
|
+
'batch',
|
|
40
|
+
'organization',
|
|
41
|
+
'creator',
|
|
42
|
+
'custom',
|
|
43
|
+
'signature',
|
|
44
|
+
]);
|
|
45
|
+
// =============================================================================
|
|
46
|
+
// HELPER FUNCTIONS
|
|
47
|
+
// =============================================================================
|
|
48
|
+
/**
|
|
49
|
+
* Create a validation error.
|
|
50
|
+
*/
|
|
51
|
+
function error(path, code, message) {
|
|
52
|
+
return { path, code, message };
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Create a validation warning.
|
|
56
|
+
*/
|
|
57
|
+
function warning(path, code, message, suggestion) {
|
|
58
|
+
const result = { path, code, message };
|
|
59
|
+
if (suggestion !== undefined) {
|
|
60
|
+
result.suggestion = suggestion;
|
|
61
|
+
}
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Check if a value is a non-empty string.
|
|
66
|
+
*/
|
|
67
|
+
function isNonEmptyString(value) {
|
|
68
|
+
return typeof value === 'string' && value.trim().length > 0;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Check if a value is a plain object.
|
|
72
|
+
*/
|
|
73
|
+
function isPlainObject(value) {
|
|
74
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
75
|
+
}
|
|
76
|
+
// =============================================================================
|
|
77
|
+
// FIELD VALIDATORS
|
|
78
|
+
// =============================================================================
|
|
79
|
+
/**
|
|
80
|
+
* Validate @context field.
|
|
81
|
+
*/
|
|
82
|
+
function validateContext(value, errors, _options) {
|
|
83
|
+
if (value === undefined || value === null) {
|
|
84
|
+
errors.push(error('@context', WolsErrorCode.INVALID_CONTEXT, '@context is required'));
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (value !== WOLS_CONTEXT) {
|
|
88
|
+
errors.push(error('@context', WolsErrorCode.INVALID_CONTEXT, `@context must be '${WOLS_CONTEXT}', got '${value}'`));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Validate @type field.
|
|
93
|
+
*/
|
|
94
|
+
function validateType(value, errors, _options) {
|
|
95
|
+
if (value === undefined || value === null) {
|
|
96
|
+
errors.push(error('@type', WolsErrorCode.INVALID_TYPE, '@type is required'));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (value !== 'Specimen') {
|
|
100
|
+
errors.push(error('@type', WolsErrorCode.INVALID_TYPE, `@type must be 'Specimen', got '${value}'`));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Validate id field.
|
|
105
|
+
*/
|
|
106
|
+
function validateId(value, errors, _options) {
|
|
107
|
+
if (value === undefined || value === null) {
|
|
108
|
+
errors.push(error('id', WolsErrorCode.REQUIRED_FIELD, 'id is required'));
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (typeof value !== 'string') {
|
|
112
|
+
errors.push(error('id', WolsErrorCode.INVALID_ID_FORMAT, 'id must be a string'));
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (!SPECIMEN_ID_PATTERN.test(value)) {
|
|
116
|
+
errors.push(error('id', WolsErrorCode.INVALID_ID_FORMAT, `id must match pattern 'wemush:[a-z0-9]+', got '${value}'`));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Validate version field.
|
|
121
|
+
*/
|
|
122
|
+
function validateVersion(value, errors, _options) {
|
|
123
|
+
if (value === undefined || value === null) {
|
|
124
|
+
errors.push(error('version', WolsErrorCode.REQUIRED_FIELD, 'version is required'));
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (typeof value !== 'string') {
|
|
128
|
+
errors.push(error('version', WolsErrorCode.INVALID_VERSION, 'version must be a string'));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (!SEMVER_PATTERN.test(value)) {
|
|
132
|
+
errors.push(error('version', WolsErrorCode.INVALID_VERSION, `version must be valid semver (major.minor.patch), got '${value}'`));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Validate specimen type field.
|
|
137
|
+
*/
|
|
138
|
+
function validateSpecimenType(value, errors, _options) {
|
|
139
|
+
if (value === undefined || value === null) {
|
|
140
|
+
errors.push(error('type', WolsErrorCode.REQUIRED_FIELD, 'type is required'));
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (!isSpecimenType(value)) {
|
|
144
|
+
errors.push(error('type', WolsErrorCode.INVALID_SPECIMEN_TYPE, `type must be one of CULTURE, SPAWN, SUBSTRATE, FRUITING, HARVEST, got '${value}'`));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Validate species field.
|
|
149
|
+
*/
|
|
150
|
+
function validateSpecies(value, errors, _options) {
|
|
151
|
+
if (value === undefined || value === null) {
|
|
152
|
+
errors.push(error('species', WolsErrorCode.REQUIRED_FIELD, 'species is required'));
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (!isNonEmptyString(value)) {
|
|
156
|
+
errors.push(error('species', WolsErrorCode.REQUIRED_FIELD, 'species must be a non-empty string'));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Validate optional stage field.
|
|
161
|
+
*/
|
|
162
|
+
function validateStage(value, errors, warnings, options) {
|
|
163
|
+
if (value === undefined || value === null) {
|
|
164
|
+
return; // Optional field
|
|
165
|
+
}
|
|
166
|
+
if (!isGrowthStage(value)) {
|
|
167
|
+
if (options.level === 'lenient') {
|
|
168
|
+
warnings.push(warning('stage', 'UNKNOWN_GROWTH_STAGE', `Unknown growth stage '${value}'`, 'Use one of: INOCULATION, COLONIZATION, FRUITING, HARVEST'));
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
errors.push(error('stage', 'INVALID_GROWTH_STAGE', `stage must be one of INOCULATION, COLONIZATION, FRUITING, HARVEST, got '${value}'`));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Validate optional created field.
|
|
177
|
+
*/
|
|
178
|
+
function validateCreated(value, errors, warnings, options) {
|
|
179
|
+
if (value === undefined || value === null) {
|
|
180
|
+
return; // Optional field
|
|
181
|
+
}
|
|
182
|
+
if (typeof value !== 'string') {
|
|
183
|
+
errors.push(error('created', WolsErrorCode.INVALID_DATE_FORMAT, 'created must be a string'));
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (!isValidISO8601(value)) {
|
|
187
|
+
if (options.level === 'lenient') {
|
|
188
|
+
warnings.push(warning('created', WolsErrorCode.INVALID_DATE_FORMAT, `Invalid ISO 8601 date format: '${value}'`, 'Use format: YYYY-MM-DDTHH:mm:ssZ'));
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
errors.push(error('created', WolsErrorCode.INVALID_DATE_FORMAT, `created must be valid ISO 8601 datetime, got '${value}'`));
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Validate strain object.
|
|
197
|
+
*/
|
|
198
|
+
function validateStrain(value, errors, _options) {
|
|
199
|
+
if (value === undefined || value === null) {
|
|
200
|
+
return; // Optional field
|
|
201
|
+
}
|
|
202
|
+
if (!isPlainObject(value)) {
|
|
203
|
+
errors.push(error('strain', WolsErrorCode.INVALID_FORMAT, 'strain must be an object'));
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const strain = value;
|
|
207
|
+
// name is required in Strain
|
|
208
|
+
if (!isNonEmptyString(strain.name)) {
|
|
209
|
+
errors.push(error('strain.name', WolsErrorCode.REQUIRED_FIELD, 'strain.name is required'));
|
|
210
|
+
}
|
|
211
|
+
// Validate generation format if present
|
|
212
|
+
if (strain.generation !== undefined) {
|
|
213
|
+
if (typeof strain.generation !== 'string' || !GENERATION_PATTERN.test(strain.generation)) {
|
|
214
|
+
errors.push(error('strain.generation', WolsErrorCode.INVALID_GENERATION, `strain.generation must match pattern 'P' or 'F<number>', got '${strain.generation}'`));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// Validate clonalGeneration if present
|
|
218
|
+
if (strain.clonalGeneration !== undefined) {
|
|
219
|
+
if (typeof strain.clonalGeneration !== 'number' ||
|
|
220
|
+
!Number.isInteger(strain.clonalGeneration) ||
|
|
221
|
+
strain.clonalGeneration < 1) {
|
|
222
|
+
errors.push(error('strain.clonalGeneration', WolsErrorCode.INVALID_FORMAT, 'strain.clonalGeneration must be a positive integer'));
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// Validate source if present (informational, no strict enum)
|
|
226
|
+
if (strain.source !== undefined && typeof strain.source !== 'string') {
|
|
227
|
+
errors.push(error('strain.source', WolsErrorCode.INVALID_FORMAT, 'strain.source must be a string'));
|
|
228
|
+
}
|
|
229
|
+
// Validate lineage if present
|
|
230
|
+
if (strain.lineage !== undefined && typeof strain.lineage !== 'string') {
|
|
231
|
+
errors.push(error('strain.lineage', WolsErrorCode.INVALID_FORMAT, 'strain.lineage must be a string'));
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Check for unknown fields and add warnings.
|
|
236
|
+
*/
|
|
237
|
+
function checkUnknownFields(specimen, warnings, options) {
|
|
238
|
+
if (options.allowUnknownFields) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
for (const key of Object.keys(specimen)) {
|
|
242
|
+
if (!KNOWN_FIELDS.has(key)) {
|
|
243
|
+
warnings.push(warning(key, 'UNKNOWN_FIELD', `Unknown field '${key}'`, 'Unknown fields should be placed in the custom object'));
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
// =============================================================================
|
|
248
|
+
// MAIN VALIDATION FUNCTION
|
|
249
|
+
// =============================================================================
|
|
250
|
+
/**
|
|
251
|
+
* Validate a specimen object against the WOLS v1.1.0 schema.
|
|
252
|
+
*
|
|
253
|
+
* @param specimen - The specimen object to validate
|
|
254
|
+
* @param options - Validation options
|
|
255
|
+
* @returns ValidationResult with errors and warnings
|
|
256
|
+
*
|
|
257
|
+
* @example
|
|
258
|
+
* ```typescript
|
|
259
|
+
* const result = validateSpecimen(specimen);
|
|
260
|
+
* if (!result.valid) {
|
|
261
|
+
* console.error('Validation errors:', result.errors);
|
|
262
|
+
* }
|
|
263
|
+
* ```
|
|
264
|
+
*/
|
|
265
|
+
export function validateSpecimen(specimen, options = {}) {
|
|
266
|
+
const errors = [];
|
|
267
|
+
const warnings = [];
|
|
268
|
+
// Default options
|
|
269
|
+
const opts = {
|
|
270
|
+
allowUnknownFields: options.allowUnknownFields ?? false,
|
|
271
|
+
level: options.level ?? 'strict',
|
|
272
|
+
};
|
|
273
|
+
// Handle null/undefined input
|
|
274
|
+
if (specimen === null || specimen === undefined) {
|
|
275
|
+
errors.push(error('', WolsErrorCode.REQUIRED_FIELD, 'Specimen is required'));
|
|
276
|
+
return { valid: false, errors, warnings };
|
|
277
|
+
}
|
|
278
|
+
// Handle non-object input
|
|
279
|
+
if (!isPlainObject(specimen)) {
|
|
280
|
+
errors.push(error('', WolsErrorCode.INVALID_FORMAT, 'Specimen must be an object'));
|
|
281
|
+
return { valid: false, errors, warnings };
|
|
282
|
+
}
|
|
283
|
+
const data = specimen;
|
|
284
|
+
// Validate required JSON-LD fields
|
|
285
|
+
validateContext(data['@context'], errors, opts);
|
|
286
|
+
validateType(data['@type'], errors, opts);
|
|
287
|
+
// Validate required specimen fields
|
|
288
|
+
validateId(data['id'], errors, opts);
|
|
289
|
+
validateVersion(data['version'], errors, opts);
|
|
290
|
+
validateSpecimenType(data['type'], errors, opts);
|
|
291
|
+
validateSpecies(data['species'], errors, opts);
|
|
292
|
+
// Validate optional fields
|
|
293
|
+
validateStage(data['stage'], errors, warnings, opts);
|
|
294
|
+
validateCreated(data['created'], errors, warnings, opts);
|
|
295
|
+
validateStrain(data['strain'], errors, opts);
|
|
296
|
+
// Check for unknown fields
|
|
297
|
+
checkUnknownFields(data, warnings, opts);
|
|
298
|
+
return {
|
|
299
|
+
valid: errors.length === 0,
|
|
300
|
+
errors,
|
|
301
|
+
warnings,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
//# sourceMappingURL=validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compact URL Format Functions
|
|
3
|
+
*
|
|
4
|
+
* This module provides functions to generate and parse compact URL format
|
|
5
|
+
* for WOLS specimens. The compact format is designed for small QR codes
|
|
6
|
+
* (petri dishes, culture tubes) where space is limited.
|
|
7
|
+
*
|
|
8
|
+
* Format: wemush://v1/{id}?s={species_code}&st={stage}&t={timestamp}
|
|
9
|
+
*
|
|
10
|
+
* @module compact-url
|
|
11
|
+
*/
|
|
12
|
+
import type { Specimen, ParseResult, SpecimenRef } from './types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Standard species codes from the WOLS specification
|
|
15
|
+
*
|
|
16
|
+
* @see https://github.com/wemush/open-standard for additional codes
|
|
17
|
+
*/
|
|
18
|
+
export declare const SPECIES_CODES: Record<string, string>;
|
|
19
|
+
/**
|
|
20
|
+
* Get the full species name from a species code
|
|
21
|
+
*
|
|
22
|
+
* @param code - Species code (e.g., "POSTR")
|
|
23
|
+
* @returns Species name or undefined if code is unknown
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* getSpeciesFromCode('POSTR') // Returns "Pleurotus ostreatus"
|
|
28
|
+
* getSpeciesFromCode('XXXXX') // Returns undefined
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare function getSpeciesFromCode(code: string): string | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Get the species code from a species name
|
|
34
|
+
*
|
|
35
|
+
* @param species - Full species name (e.g., "Pleurotus ostreatus")
|
|
36
|
+
* @returns Species code or undefined if species is not registered
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* getCodeFromSpecies('Pleurotus ostreatus') // Returns "POSTR"
|
|
41
|
+
* getCodeFromSpecies('Unknown species') // Returns undefined
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare function getCodeFromSpecies(species: string): string | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Register a custom species code
|
|
47
|
+
*
|
|
48
|
+
* Use this to add species codes that are not in the standard WOLS list.
|
|
49
|
+
*
|
|
50
|
+
* @param code - Species code (uppercase, 5 characters recommended)
|
|
51
|
+
* @param species - Full species name
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* registerSpeciesCode('CCOMA', 'Coprinus comatus');
|
|
56
|
+
* getSpeciesFromCode('CCOMA') // Returns "Coprinus comatus"
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare function registerSpeciesCode(code: string, species: string): void;
|
|
60
|
+
/**
|
|
61
|
+
* Generate a compact URL from a specimen
|
|
62
|
+
*
|
|
63
|
+
* The compact URL format is designed for small QR codes:
|
|
64
|
+
* ```
|
|
65
|
+
* wemush://v1/{id}?s={species_code}&st={stage}&t={timestamp}
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* @param specimen - The specimen to encode
|
|
69
|
+
* @returns Compact URL string
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* const specimen = createSpecimen({
|
|
74
|
+
* type: 'CULTURE',
|
|
75
|
+
* species: 'Pleurotus ostreatus',
|
|
76
|
+
* stage: 'COLONIZATION'
|
|
77
|
+
* });
|
|
78
|
+
*
|
|
79
|
+
* const url = toCompactUrl(specimen);
|
|
80
|
+
* // wemush://v1/clx1a2b3c4?s=POSTR&st=COLONIZATION&ty=CULTURE&t=1734307200
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export declare function toCompactUrl(specimen: Specimen): string;
|
|
84
|
+
/**
|
|
85
|
+
* Parse a compact URL into a SpecimenRef
|
|
86
|
+
*
|
|
87
|
+
* Returns a reference object containing the minimal information
|
|
88
|
+
* encoded in the compact URL. Use the id to fetch full specimen
|
|
89
|
+
* data from the API if needed.
|
|
90
|
+
*
|
|
91
|
+
* @param url - Compact URL to parse (wemush://v1/...)
|
|
92
|
+
* @returns ParseResult with SpecimenRef on success, error on failure
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* const result = parseCompactUrl('wemush://v1/clx1a2b3c4?s=POSTR&st=COLONIZATION');
|
|
97
|
+
*
|
|
98
|
+
* if (result.success) {
|
|
99
|
+
* console.log(result.data.species); // "Pleurotus ostreatus"
|
|
100
|
+
* }
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export declare function parseCompactUrl(url: string): ParseResult<SpecimenRef>;
|
|
104
|
+
//# sourceMappingURL=compact-url.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compact-url.d.ts","sourceRoot":"","sources":["../../src/compact-url.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAA6B,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEhG;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAWhD,CAAC;AAYF;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEnE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEtE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CASvE;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAsDvD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAAC,WAAW,CAAC,CA6GrE"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WOLS Decryption Module
|
|
3
|
+
*
|
|
4
|
+
* Provides AES-256-GCM decryption for encrypted specimens using Web Crypto API.
|
|
5
|
+
* Supports both password-based (PBKDF2) and raw CryptoKey decryption.
|
|
6
|
+
*
|
|
7
|
+
* @module crypto/decrypt
|
|
8
|
+
*/
|
|
9
|
+
import type { Specimen, EncryptedSpecimen, DecryptionOptions, ParseResult } from '../types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Decrypt an encrypted specimen using AES-256-GCM
|
|
12
|
+
*
|
|
13
|
+
* @param encrypted - The encrypted specimen wrapper
|
|
14
|
+
* @param options - Decryption options (key required)
|
|
15
|
+
* @returns Promise resolving to ParseResult with decrypted specimen or error
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import { decryptSpecimen } from '@wemush/wols/crypto';
|
|
20
|
+
*
|
|
21
|
+
* const result = await decryptSpecimen(encrypted, {
|
|
22
|
+
* key: 'my-secret-password',
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* if (result.success) {
|
|
26
|
+
* console.log(result.data);
|
|
27
|
+
* } else {
|
|
28
|
+
* console.error(result.error);
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare function decryptSpecimen(encrypted: EncryptedSpecimen, options: DecryptionOptions): Promise<ParseResult<Specimen>>;
|
|
33
|
+
//# sourceMappingURL=decrypt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decrypt.d.ts","sourceRoot":"","sources":["../../../src/crypto/decrypt.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAqE/F;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,iBAAiB,EAC5B,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAqDhC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WOLS Encryption Module
|
|
3
|
+
*
|
|
4
|
+
* Provides AES-256-GCM encryption for specimens using Web Crypto API.
|
|
5
|
+
* Supports both password-based (PBKDF2) and raw CryptoKey encryption.
|
|
6
|
+
*
|
|
7
|
+
* @module crypto/encrypt
|
|
8
|
+
*/
|
|
9
|
+
import type { Specimen, EncryptedSpecimen, EncryptionOptions } from '../types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Encrypt a specimen using AES-256-GCM
|
|
12
|
+
*
|
|
13
|
+
* @param specimen - The specimen to encrypt
|
|
14
|
+
* @param options - Encryption options (key required)
|
|
15
|
+
* @returns Promise resolving to encrypted specimen wrapper
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import { encryptSpecimen } from '@wemush/wols/crypto';
|
|
20
|
+
*
|
|
21
|
+
* const encrypted = await encryptSpecimen(specimen, {
|
|
22
|
+
* key: 'my-secret-password',
|
|
23
|
+
* });
|
|
24
|
+
* // Returns: { encrypted: true, payload: "...", iv: "...", algorithm: "AES-256-GCM" }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function encryptSpecimen(specimen: Specimen, options: EncryptionOptions): Promise<EncryptedSpecimen>;
|
|
28
|
+
/**
|
|
29
|
+
* Type guard to check if an object is an encrypted specimen
|
|
30
|
+
*/
|
|
31
|
+
export declare function isEncrypted(value: unknown): value is EncryptedSpecimen;
|
|
32
|
+
//# sourceMappingURL=encrypt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encrypt.d.ts","sourceRoot":"","sources":["../../../src/crypto/encrypt.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAwElF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,iBAAiB,CAAC,CAgC5B;AA+CD;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,iBAAiB,CAStE"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WOLS Crypto Module
|
|
3
|
+
*
|
|
4
|
+
* Provides AES-256-GCM encryption and decryption for specimens.
|
|
5
|
+
*
|
|
6
|
+
* @module crypto
|
|
7
|
+
*/
|
|
8
|
+
export { encryptSpecimen, isEncrypted } from './encrypt.js';
|
|
9
|
+
export { decryptSpecimen } from './decrypt.js';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/crypto/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WOLS Error Types
|
|
3
|
+
*
|
|
4
|
+
* This module defines all error classes and error codes
|
|
5
|
+
* used by the WOLS TypeScript library.
|
|
6
|
+
*
|
|
7
|
+
* @module errors
|
|
8
|
+
*/
|
|
9
|
+
import type { ValidationError } from './types.js';
|
|
10
|
+
/**
|
|
11
|
+
* WOLS error codes (stable, for programmatic handling).
|
|
12
|
+
*/
|
|
13
|
+
export declare enum WolsErrorCode {
|
|
14
|
+
/** General parse error */
|
|
15
|
+
PARSE_ERROR = "WOLS_PARSE_ERROR",
|
|
16
|
+
/** Invalid JSON syntax */
|
|
17
|
+
INVALID_JSON = "WOLS_INVALID_JSON",
|
|
18
|
+
/** Not a valid WOLS format */
|
|
19
|
+
INVALID_FORMAT = "WOLS_INVALID_FORMAT",
|
|
20
|
+
/** Missing or invalid @context field */
|
|
21
|
+
INVALID_CONTEXT = "WOLS_INVALID_CONTEXT",
|
|
22
|
+
/** Missing or invalid @type field */
|
|
23
|
+
INVALID_TYPE = "WOLS_INVALID_TYPE",
|
|
24
|
+
/** ID doesn't match wemush:[a-z0-9]+ pattern */
|
|
25
|
+
INVALID_ID_FORMAT = "WOLS_INVALID_ID_FORMAT",
|
|
26
|
+
/** Version not valid semver */
|
|
27
|
+
INVALID_VERSION = "WOLS_INVALID_VERSION",
|
|
28
|
+
/** Type not in SpecimenType enum */
|
|
29
|
+
INVALID_SPECIMEN_TYPE = "WOLS_INVALID_SPECIMEN_TYPE",
|
|
30
|
+
/** Required field is missing */
|
|
31
|
+
REQUIRED_FIELD = "WOLS_REQUIRED_FIELD",
|
|
32
|
+
/** Date not in ISO 8601 format */
|
|
33
|
+
INVALID_DATE_FORMAT = "WOLS_INVALID_DATE_FORMAT",
|
|
34
|
+
/** Strain generation format is invalid */
|
|
35
|
+
INVALID_GENERATION = "WOLS_INVALID_GENERATION",
|
|
36
|
+
/** Invalid compact URL format */
|
|
37
|
+
INVALID_URL = "WOLS_INVALID_URL",
|
|
38
|
+
/** Encryption operation failed */
|
|
39
|
+
ENCRYPTION_ERROR = "WOLS_ENCRYPTION_ERROR",
|
|
40
|
+
/** Decryption operation failed */
|
|
41
|
+
DECRYPTION_ERROR = "WOLS_DECRYPTION_ERROR",
|
|
42
|
+
/** Invalid encryption key */
|
|
43
|
+
INVALID_KEY = "WOLS_INVALID_KEY",
|
|
44
|
+
/** Payload exceeds QR code capacity */
|
|
45
|
+
SIZE_EXCEEDED = "WOLS_SIZE_EXCEEDED",
|
|
46
|
+
/** Unknown or unspecified error */
|
|
47
|
+
UNKNOWN_ERROR = "WOLS_UNKNOWN_ERROR"
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Base WOLS error class.
|
|
51
|
+
* All WOLS-specific errors extend this class.
|
|
52
|
+
*/
|
|
53
|
+
export declare class WolsError extends Error {
|
|
54
|
+
/** Error code for programmatic handling */
|
|
55
|
+
readonly code: WolsErrorCode;
|
|
56
|
+
/** Additional error details */
|
|
57
|
+
readonly details: Record<string, unknown> | undefined;
|
|
58
|
+
constructor(code: WolsErrorCode, message: string, details?: Record<string, unknown>);
|
|
59
|
+
/**
|
|
60
|
+
* Convert error to JSON for serialization.
|
|
61
|
+
*/
|
|
62
|
+
toJSON(): Record<string, unknown>;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Parse error (JSON/format issues).
|
|
66
|
+
* Thrown when parsing JSON or WOLS data fails.
|
|
67
|
+
*/
|
|
68
|
+
export declare class WolsParseError extends WolsError {
|
|
69
|
+
/** Character position in the input where error occurred */
|
|
70
|
+
readonly position: number | undefined;
|
|
71
|
+
constructor(code: WolsErrorCode, message: string, details?: Record<string, unknown> & {
|
|
72
|
+
position?: number;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Validation error (schema violations).
|
|
77
|
+
* Thrown when specimen data fails validation.
|
|
78
|
+
*/
|
|
79
|
+
export declare class WolsValidationError extends WolsError {
|
|
80
|
+
/** Array of validation errors */
|
|
81
|
+
readonly errors: ValidationError[];
|
|
82
|
+
constructor(message: string, errors: ValidationError[]);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Encryption/decryption error.
|
|
86
|
+
* Thrown when crypto operations fail.
|
|
87
|
+
*/
|
|
88
|
+
export declare class WolsEncryptionError extends WolsError {
|
|
89
|
+
constructor(code: WolsErrorCode, message: string, details?: Record<string, unknown>);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Create a required field error.
|
|
93
|
+
*/
|
|
94
|
+
export declare function requiredFieldError(field: string, path?: string): WolsValidationError;
|
|
95
|
+
/**
|
|
96
|
+
* Create an invalid format error.
|
|
97
|
+
*/
|
|
98
|
+
export declare function invalidFormatError(field: string, expected: string, path?: string): WolsValidationError;
|
|
99
|
+
/**
|
|
100
|
+
* Create a parse error from a caught exception.
|
|
101
|
+
*/
|
|
102
|
+
export declare function parseErrorFromException(error: unknown, _input?: string): WolsParseError;
|
|
103
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAMlD;;GAEG;AACH,oBAAY,aAAa;IACvB,0BAA0B;IAC1B,WAAW,qBAAqB;IAChC,0BAA0B;IAC1B,YAAY,sBAAsB;IAClC,8BAA8B;IAC9B,cAAc,wBAAwB;IACtC,wCAAwC;IACxC,eAAe,yBAAyB;IACxC,qCAAqC;IACrC,YAAY,sBAAsB;IAClC,gDAAgD;IAChD,iBAAiB,2BAA2B;IAC5C,+BAA+B;IAC/B,eAAe,yBAAyB;IACxC,oCAAoC;IACpC,qBAAqB,+BAA+B;IACpD,gCAAgC;IAChC,cAAc,wBAAwB;IACtC,kCAAkC;IAClC,mBAAmB,6BAA6B;IAChD,0CAA0C;IAC1C,kBAAkB,4BAA4B;IAC9C,iCAAiC;IACjC,WAAW,qBAAqB;IAChC,kCAAkC;IAClC,gBAAgB,0BAA0B;IAC1C,kCAAkC;IAClC,gBAAgB,0BAA0B;IAC1C,6BAA6B;IAC7B,WAAW,qBAAqB;IAChC,uCAAuC;IACvC,aAAa,uBAAuB;IACpC,mCAAmC;IACnC,aAAa,uBAAuB;CACrC;AAMD;;;GAGG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAClC,2CAA2C;IAC3C,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,+BAA+B;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;gBAE1C,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAYnF;;OAEG;IACH,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAQlC;AAED;;;GAGG;AACH,qBAAa,cAAe,SAAQ,SAAS;IAC3C,2DAA2D;IAC3D,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;gBAGpC,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE;CAU5D;AAED;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,SAAS;IAChD,iCAAiC;IACjC,QAAQ,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC;gBAEvB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE;CASvD;AAED;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,SAAS;gBACpC,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAQpF;AAMD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,MAAc,GAAG,mBAAmB,CAQ3F;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,MAAc,GACnB,mBAAmB,CAQrB;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,cAAc,CAoBvF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @wemush/wols - Official WOLS TypeScript Library
|
|
3
|
+
*
|
|
4
|
+
* WeMush Open Labeling Standard (WOLS) v1.1.0 implementation
|
|
5
|
+
* for biological specimen labeling and traceability.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
* @module @wemush/wols
|
|
9
|
+
* @version 1.1.0
|
|
10
|
+
*/
|
|
11
|
+
export { WOLS_VERSION, WOLS_CONTEXT } from './types.js';
|
|
12
|
+
export type { Brand, SpecimenId, SpecimenType, GrowthStage, Strain, Specimen, SpecimenInput, ParseResult, ValidationResult, ValidationError, ValidationWarning, ValidationOptions, SpecimenRef, QRCodeOptions, EncryptionOptions, DecryptionOptions, EncryptedSpecimen, } from './types.js';
|
|
13
|
+
export { asSpecimenId, isSpecimenType, isGrowthStage, isStrain, SPECIMEN_TYPES, GROWTH_STAGES, } from './types.js';
|
|
14
|
+
export { WolsErrorCode, WolsError, WolsParseError, WolsValidationError, WolsEncryptionError, } from './errors.js';
|
|
15
|
+
export { createSpecimen, serializeSpecimen } from './specimen.js';
|
|
16
|
+
export { validateSpecimen } from './validator.js';
|
|
17
|
+
export { parseSpecimen } from './parser.js';
|
|
18
|
+
export { toCompactUrl, parseCompactUrl, SPECIES_CODES, getSpeciesFromCode, getCodeFromSpecies, registerSpeciesCode, } from './compact-url.js';
|
|
19
|
+
export { encryptSpecimen, isEncrypted, decryptSpecimen } from './crypto/index.js';
|
|
20
|
+
export { toQRCode, toQRCodeDataURL, toQRCodeSVG, isQRAvailable, isQRAvailableSync, } from './qr/index.js';
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAKxD,YAAY,EAEV,KAAK,EACL,UAAU,EAGV,YAAY,EACZ,WAAW,EACX,MAAM,EACN,QAAQ,EACR,aAAa,EAGb,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EAGjB,WAAW,EAGX,aAAa,EAGb,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,YAAY,CAAC;AAKpB,OAAO,EACL,YAAY,EACZ,cAAc,EACd,aAAa,EACb,QAAQ,EACR,cAAc,EACd,aAAa,GACd,MAAM,YAAY,CAAC;AAKpB,OAAO,EACL,aAAa,EACb,SAAS,EACT,cAAc,EACd,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,aAAa,CAAC;AAKrB,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAKlE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAKlD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAK5C,OAAO,EACL,YAAY,EACZ,eAAe,EACf,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAK1B,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAKlF,OAAO,EACL,QAAQ,EACR,eAAe,EACf,WAAW,EACX,aAAa,EACb,iBAAiB,GAClB,MAAM,eAAe,CAAC"}
|