@smartledger/bsv 3.2.1 → 3.3.2

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.
Files changed (70) hide show
  1. package/CHANGELOG.md +147 -0
  2. package/README.md +289 -55
  3. package/architecture_demo.js +247 -0
  4. package/bsv-covenant.min.js +10 -0
  5. package/bsv-gdaf.min.js +37 -0
  6. package/bsv-ltp.min.js +37 -0
  7. package/bsv-script-helper.min.js +10 -0
  8. package/bsv-security.min.js +31 -0
  9. package/bsv-shamir.min.js +12 -0
  10. package/bsv-smartcontract.min.js +37 -0
  11. package/bsv.bundle.js +9 -9
  12. package/bsv.min.js +3 -3
  13. package/build/bsv-covenant.min.js +10 -0
  14. package/build/bsv-script-helper.min.js +10 -0
  15. package/build/bsv-security.min.js +31 -0
  16. package/build/bsv-smartcontract.min.js +39 -0
  17. package/build/bsv.bundle.js +39 -0
  18. package/build/bsv.min.js +39 -0
  19. package/build/webpack.bundle.config.js +22 -0
  20. package/build/webpack.config.js +18 -0
  21. package/build/webpack.covenant.config.js +27 -0
  22. package/build/webpack.gdaf.config.js +54 -0
  23. package/build/webpack.ltp.config.js +17 -0
  24. package/build/webpack.script-helper.config.js +27 -0
  25. package/build/webpack.security.config.js +23 -0
  26. package/build/webpack.smartcontract.config.js +25 -0
  27. package/build/webpack.subproject.config.js +6 -0
  28. package/bundle-entry.js +341 -0
  29. package/complete_ltp_demo.js +511 -0
  30. package/covenant-entry.js +44 -0
  31. package/docs/pushtx-key-insights.md +106 -0
  32. package/gdaf-entry.js +54 -0
  33. package/index.js +272 -5
  34. package/lib/crypto/shamir.js +360 -0
  35. package/lib/gdaf/attestation-signer.js +461 -0
  36. package/lib/gdaf/attestation-verifier.js +600 -0
  37. package/lib/gdaf/did-resolver.js +382 -0
  38. package/lib/gdaf/index.js +471 -0
  39. package/lib/gdaf/schema-validator.js +682 -0
  40. package/lib/gdaf/smartledger-anchor.js +486 -0
  41. package/lib/gdaf/zk-prover.js +507 -0
  42. package/lib/ltp/anchor.js +438 -0
  43. package/lib/ltp/claim.js +1026 -0
  44. package/lib/ltp/index.js +470 -0
  45. package/lib/ltp/obligation.js +945 -0
  46. package/lib/ltp/proof.js +828 -0
  47. package/lib/ltp/registry.js +702 -0
  48. package/lib/ltp/right.js +765 -0
  49. package/lib/smart_contract/API_REFERENCE.md +1 -1
  50. package/lib/smart_contract/EXAMPLES.md +2 -2
  51. package/lib/smart_contract/QUICK_START.md +2 -2
  52. package/lib/smart_contract/README.md +1 -1
  53. package/lib/smart_contract/index.js +4 -0
  54. package/ltp-entry.js +92 -0
  55. package/package.json +91 -20
  56. package/script-helper-entry.js +49 -0
  57. package/security-entry.js +70 -0
  58. package/shamir-entry.js +173 -0
  59. package/shamir_demo.js +121 -0
  60. package/simple_demo.js +204 -0
  61. package/smartcontract-entry.js +133 -0
  62. package/test_shamir.js +221 -0
  63. package/test_standalone_shamir.html +83 -0
  64. package/tests/bundle-completeness-test.html +131 -0
  65. package/tests/bundle-demo.html +476 -0
  66. package/tests/smartcontract-test.html +239 -0
  67. package/tests/standalone-modules-test.html +260 -0
  68. package/tests/test.html +612 -0
  69. package/tests/unpkg-demo.html +194 -0
  70. package/docs/nchain.md +0 -958
@@ -0,0 +1,682 @@
1
+ 'use strict'
2
+
3
+ var $ = require('../util/preconditions')
4
+
5
+ /**
6
+ * VC Schema System
7
+ *
8
+ * Provides W3C Verifiable Credential schema definitions and validation
9
+ * for the Global Digital Attestation Framework (GDAF). Includes
10
+ * predefined schemas for common credential types and custom schema
11
+ * validation capabilities.
12
+ */
13
+
14
+ /**
15
+ * Schema definitions
16
+ */
17
+ var schemas = {
18
+ // Email Verification Credential
19
+ EmailVerifiedCredential: {
20
+ '@context': [
21
+ 'https://www.w3.org/2018/credentials/v1',
22
+ 'https://smartledger.technology/contexts/email/v1'
23
+ ],
24
+ type: ['VerifiableCredential', 'EmailVerifiedCredential'],
25
+ requiredFields: [
26
+ 'credentialSubject.email',
27
+ 'credentialSubject.verified'
28
+ ],
29
+ properties: {
30
+ credentialSubject: {
31
+ type: 'object',
32
+ required: ['email', 'verified'],
33
+ properties: {
34
+ email: {
35
+ type: 'string',
36
+ format: 'email'
37
+ },
38
+ verified: {
39
+ type: 'boolean'
40
+ },
41
+ verificationMethod: {
42
+ type: 'string'
43
+ },
44
+ verificationTimestamp: {
45
+ type: 'string',
46
+ format: 'date-time'
47
+ }
48
+ }
49
+ }
50
+ }
51
+ },
52
+
53
+ // Age Verification Credential
54
+ AgeVerifiedCredential: {
55
+ '@context': [
56
+ 'https://www.w3.org/2018/credentials/v1',
57
+ 'https://smartledger.technology/contexts/age/v1'
58
+ ],
59
+ type: ['VerifiableCredential', 'AgeVerifiedCredential'],
60
+ requiredFields: [
61
+ 'credentialSubject.ageOver',
62
+ 'credentialSubject.verified'
63
+ ],
64
+ properties: {
65
+ credentialSubject: {
66
+ type: 'object',
67
+ required: ['ageOver', 'verified'],
68
+ properties: {
69
+ ageOver: {
70
+ type: 'number',
71
+ minimum: 0,
72
+ maximum: 150
73
+ },
74
+ verified: {
75
+ type: 'boolean'
76
+ },
77
+ birthDateHash: {
78
+ type: 'string',
79
+ pattern: '^[a-fA-F0-9]{64}$'
80
+ },
81
+ verificationMethod: {
82
+ type: 'string'
83
+ }
84
+ }
85
+ }
86
+ }
87
+ },
88
+
89
+ // KYC Verification Credential
90
+ KYCVerifiedCredential: {
91
+ '@context': [
92
+ 'https://www.w3.org/2018/credentials/v1',
93
+ 'https://smartledger.technology/contexts/kyc/v1'
94
+ ],
95
+ type: ['VerifiableCredential', 'KYCVerifiedCredential'],
96
+ requiredFields: [
97
+ 'credentialSubject.kycLevel',
98
+ 'credentialSubject.verified',
99
+ 'credentialSubject.verifyingAuthority'
100
+ ],
101
+ properties: {
102
+ credentialSubject: {
103
+ type: 'object',
104
+ required: ['kycLevel', 'verified', 'verifyingAuthority'],
105
+ properties: {
106
+ kycLevel: {
107
+ type: 'string',
108
+ enum: ['basic', 'enhanced', 'premium', 'institutional']
109
+ },
110
+ verified: {
111
+ type: 'boolean'
112
+ },
113
+ verifyingAuthority: {
114
+ type: 'string'
115
+ },
116
+ verificationTimestamp: {
117
+ type: 'string',
118
+ format: 'date-time'
119
+ },
120
+ firstNameHash: {
121
+ type: 'string',
122
+ pattern: '^[a-fA-F0-9]{64}$'
123
+ },
124
+ lastNameHash: {
125
+ type: 'string',
126
+ pattern: '^[a-fA-F0-9]{64}$'
127
+ },
128
+ ssnHash: {
129
+ type: 'string',
130
+ pattern: '^[a-fA-F0-9]{64}$'
131
+ }
132
+ }
133
+ }
134
+ }
135
+ },
136
+
137
+ // Organization Credential
138
+ OrganizationCredential: {
139
+ '@context': [
140
+ 'https://www.w3.org/2018/credentials/v1',
141
+ 'https://smartledger.technology/contexts/organization/v1'
142
+ ],
143
+ type: ['VerifiableCredential', 'OrganizationCredential'],
144
+ requiredFields: [
145
+ 'credentialSubject.name',
146
+ 'credentialSubject.type',
147
+ 'credentialSubject.verified'
148
+ ],
149
+ properties: {
150
+ credentialSubject: {
151
+ type: 'object',
152
+ required: ['name', 'type', 'verified'],
153
+ properties: {
154
+ name: {
155
+ type: 'string'
156
+ },
157
+ type: {
158
+ type: 'string',
159
+ enum: ['Corporation', 'LLC', 'Partnership', 'NGO', 'Government', 'Other']
160
+ },
161
+ verified: {
162
+ type: 'boolean'
163
+ },
164
+ taxIdHash: {
165
+ type: 'string',
166
+ pattern: '^[a-fA-F0-9]{64}$'
167
+ },
168
+ incorporationState: {
169
+ type: 'string'
170
+ },
171
+ industry: {
172
+ type: 'string'
173
+ },
174
+ verificationMethod: {
175
+ type: 'string'
176
+ },
177
+ verificationTimestamp: {
178
+ type: 'string',
179
+ format: 'date-time'
180
+ }
181
+ }
182
+ }
183
+ }
184
+ },
185
+
186
+ // SSN Verification Credential
187
+ SSNVerifiedCredential: {
188
+ '@context': [
189
+ 'https://www.w3.org/2018/credentials/v1',
190
+ 'https://smartledger.technology/contexts/ssn/v1'
191
+ ],
192
+ type: ['VerifiableCredential', 'SSNVerifiedCredential'],
193
+ requiredFields: [
194
+ 'credentialSubject.ssnHash',
195
+ 'credentialSubject.verified',
196
+ 'credentialSubject.verifyingAuthority'
197
+ ],
198
+ properties: {
199
+ credentialSubject: {
200
+ type: 'object',
201
+ required: ['ssnHash', 'verified', 'verifyingAuthority'],
202
+ properties: {
203
+ ssnHash: {
204
+ type: 'string',
205
+ pattern: '^[a-fA-F0-9]{64}$'
206
+ },
207
+ verified: {
208
+ type: 'boolean'
209
+ },
210
+ verifyingAuthority: {
211
+ type: 'string'
212
+ },
213
+ verificationTimestamp: {
214
+ type: 'string',
215
+ format: 'date-time'
216
+ },
217
+ issuingState: {
218
+ type: 'string'
219
+ }
220
+ }
221
+ }
222
+ }
223
+ },
224
+
225
+ // Educational Credential
226
+ EducationalCredential: {
227
+ '@context': [
228
+ 'https://www.w3.org/2018/credentials/v1',
229
+ 'https://smartledger.technology/contexts/education/v1'
230
+ ],
231
+ type: ['VerifiableCredential', 'EducationalCredential'],
232
+ requiredFields: [
233
+ 'credentialSubject.degree',
234
+ 'credentialSubject.institution',
235
+ 'credentialSubject.graduationDate'
236
+ ],
237
+ properties: {
238
+ credentialSubject: {
239
+ type: 'object',
240
+ required: ['degree', 'institution', 'graduationDate'],
241
+ properties: {
242
+ degree: {
243
+ type: 'string'
244
+ },
245
+ institution: {
246
+ type: 'string'
247
+ },
248
+ graduationDate: {
249
+ type: 'string',
250
+ format: 'date'
251
+ },
252
+ gpa: {
253
+ type: 'number',
254
+ minimum: 0.0,
255
+ maximum: 4.0
256
+ },
257
+ major: {
258
+ type: 'string'
259
+ },
260
+ honors: {
261
+ type: 'array',
262
+ items: {
263
+ type: 'string'
264
+ }
265
+ }
266
+ }
267
+ }
268
+ }
269
+ },
270
+
271
+ // Professional License Credential
272
+ ProfessionalLicenseCredential: {
273
+ '@context': [
274
+ 'https://www.w3.org/2018/credentials/v1',
275
+ 'https://smartledger.technology/contexts/license/v1'
276
+ ],
277
+ type: ['VerifiableCredential', 'ProfessionalLicenseCredential'],
278
+ requiredFields: [
279
+ 'credentialSubject.licenseType',
280
+ 'credentialSubject.licenseNumber',
281
+ 'credentialSubject.issuingAuthority',
282
+ 'credentialSubject.isValid'
283
+ ],
284
+ properties: {
285
+ credentialSubject: {
286
+ type: 'object',
287
+ required: ['licenseType', 'licenseNumber', 'issuingAuthority', 'isValid'],
288
+ properties: {
289
+ licenseType: {
290
+ type: 'string'
291
+ },
292
+ licenseNumber: {
293
+ type: 'string'
294
+ },
295
+ issuingAuthority: {
296
+ type: 'string'
297
+ },
298
+ issuingState: {
299
+ type: 'string'
300
+ },
301
+ isValid: {
302
+ type: 'boolean'
303
+ },
304
+ issueDate: {
305
+ type: 'string',
306
+ format: 'date'
307
+ },
308
+ expirationDate: {
309
+ type: 'string',
310
+ format: 'date'
311
+ }
312
+ }
313
+ }
314
+ }
315
+ }
316
+ }
317
+
318
+ /**
319
+ * Schema validator
320
+ */
321
+ var SchemaValidator = {
322
+
323
+ /**
324
+ * Get schema by credential type
325
+ * @param {String} credentialType - Type of credential
326
+ * @returns {Object} Schema definition
327
+ */
328
+ getSchema: function(credentialType) {
329
+ return schemas[credentialType] || null
330
+ },
331
+
332
+ /**
333
+ * Get all available schemas
334
+ * @returns {Object} All schema definitions
335
+ */
336
+ getAllSchemas: function() {
337
+ return schemas
338
+ },
339
+
340
+ /**
341
+ * Validate credential against schema
342
+ * @param {Object} credential - Credential to validate
343
+ * @param {String|Object} schema - Schema name or definition
344
+ * @returns {Object} Validation result
345
+ */
346
+ validate: function(credential, schema) {
347
+ try {
348
+ $.checkArgument(credential && typeof credential === 'object', 'Invalid credential')
349
+
350
+ var schemaDefinition
351
+ if (typeof schema === 'string') {
352
+ schemaDefinition = schemas[schema]
353
+ if (!schemaDefinition) {
354
+ return {
355
+ valid: false,
356
+ errors: ['Unknown schema type: ' + schema]
357
+ }
358
+ }
359
+ } else if (typeof schema === 'object') {
360
+ schemaDefinition = schema
361
+ } else {
362
+ return {
363
+ valid: false,
364
+ errors: ['Invalid schema parameter']
365
+ }
366
+ }
367
+
368
+ var errors = []
369
+ var warnings = []
370
+
371
+ // Validate required credential structure
372
+ this._validateCredentialStructure(credential, errors)
373
+
374
+ // Validate credential types
375
+ this._validateCredentialTypes(credential, schemaDefinition, errors)
376
+
377
+ // Validate required fields
378
+ this._validateRequiredFields(credential, schemaDefinition, errors)
379
+
380
+ // Validate field properties
381
+ this._validateFieldProperties(credential, schemaDefinition, errors, warnings)
382
+
383
+ return {
384
+ valid: errors.length === 0,
385
+ errors: errors,
386
+ warnings: warnings
387
+ }
388
+
389
+ } catch (error) {
390
+ return {
391
+ valid: false,
392
+ errors: ['Schema validation error: ' + error.message]
393
+ }
394
+ }
395
+ },
396
+
397
+ /**
398
+ * Validate basic credential structure
399
+ * @private
400
+ */
401
+ _validateCredentialStructure: function(credential, errors) {
402
+ if (!credential['@context']) {
403
+ errors.push('Missing @context')
404
+ }
405
+
406
+ if (!credential.type) {
407
+ errors.push('Missing type')
408
+ }
409
+
410
+ if (!credential.issuer) {
411
+ errors.push('Missing issuer')
412
+ }
413
+
414
+ if (!credential.issuanceDate) {
415
+ errors.push('Missing issuanceDate')
416
+ }
417
+
418
+ if (!credential.credentialSubject) {
419
+ errors.push('Missing credentialSubject')
420
+ }
421
+ },
422
+
423
+ /**
424
+ * Validate credential types
425
+ * @private
426
+ */
427
+ _validateCredentialTypes: function(credential, schema, errors) {
428
+ if (!Array.isArray(credential.type)) {
429
+ errors.push('Credential type must be array')
430
+ return
431
+ }
432
+
433
+ if (schema.type && Array.isArray(schema.type)) {
434
+ for (var i = 0; i < schema.type.length; i++) {
435
+ if (!credential.type.includes(schema.type[i])) {
436
+ errors.push('Missing required type: ' + schema.type[i])
437
+ }
438
+ }
439
+ }
440
+ },
441
+
442
+ /**
443
+ * Validate required fields
444
+ * @private
445
+ */
446
+ _validateRequiredFields: function(credential, schema, errors) {
447
+ if (schema.requiredFields && Array.isArray(schema.requiredFields)) {
448
+ for (var i = 0; i < schema.requiredFields.length; i++) {
449
+ var fieldPath = schema.requiredFields[i]
450
+ var value = this._getNestedProperty(credential, fieldPath)
451
+
452
+ if (value === undefined || value === null) {
453
+ errors.push('Missing required field: ' + fieldPath)
454
+ }
455
+ }
456
+ }
457
+ },
458
+
459
+ /**
460
+ * Validate field properties
461
+ * @private
462
+ */
463
+ _validateFieldProperties: function(credential, schema, errors, warnings) {
464
+ if (schema.properties && schema.properties.credentialSubject) {
465
+ this._validateObjectProperties(
466
+ credential.credentialSubject,
467
+ schema.properties.credentialSubject,
468
+ 'credentialSubject',
469
+ errors,
470
+ warnings
471
+ )
472
+ }
473
+ },
474
+
475
+ /**
476
+ * Validate object properties recursively
477
+ * @private
478
+ */
479
+ _validateObjectProperties: function(obj, schema, path, errors, warnings) {
480
+ if (!obj || typeof obj !== 'object') {
481
+ return
482
+ }
483
+
484
+ if (schema.properties) {
485
+ Object.keys(schema.properties).forEach(function(prop) {
486
+ var value = obj[prop]
487
+ var propSchema = schema.properties[prop]
488
+ var propPath = path + '.' + prop
489
+
490
+ if (value !== undefined && value !== null) {
491
+ this._validateProperty(value, propSchema, propPath, errors, warnings)
492
+ }
493
+ }.bind(this))
494
+ }
495
+ },
496
+
497
+ /**
498
+ * Validate individual property
499
+ * @private
500
+ */
501
+ _validateProperty: function(value, schema, path, errors, warnings) {
502
+ // Type validation
503
+ if (schema.type) {
504
+ var actualType = Array.isArray(value) ? 'array' : typeof value
505
+ if (actualType !== schema.type) {
506
+ errors.push('Invalid type for ' + path + ': expected ' + schema.type + ', got ' + actualType)
507
+ return
508
+ }
509
+ }
510
+
511
+ // String validations
512
+ if (schema.type === 'string') {
513
+ if (schema.format === 'email' && !this._isValidEmail(value)) {
514
+ errors.push('Invalid email format for ' + path)
515
+ }
516
+
517
+ if (schema.format === 'date' && !this._isValidDate(value)) {
518
+ errors.push('Invalid date format for ' + path)
519
+ }
520
+
521
+ if (schema.format === 'date-time' && !this._isValidDateTime(value)) {
522
+ errors.push('Invalid date-time format for ' + path)
523
+ }
524
+
525
+ if (schema.pattern && !new RegExp(schema.pattern).test(value)) {
526
+ errors.push('Value does not match pattern for ' + path)
527
+ }
528
+
529
+ if (schema.enum && !schema.enum.includes(value)) {
530
+ errors.push('Invalid enum value for ' + path + ': ' + value)
531
+ }
532
+ }
533
+
534
+ // Number validations
535
+ if (schema.type === 'number') {
536
+ if (schema.minimum !== undefined && value < schema.minimum) {
537
+ errors.push('Value below minimum for ' + path + ': ' + value + ' < ' + schema.minimum)
538
+ }
539
+
540
+ if (schema.maximum !== undefined && value > schema.maximum) {
541
+ errors.push('Value above maximum for ' + path + ': ' + value + ' > ' + schema.maximum)
542
+ }
543
+ }
544
+
545
+ // Array validations
546
+ if (schema.type === 'array' && schema.items) {
547
+ for (var i = 0; i < value.length; i++) {
548
+ this._validateProperty(value[i], schema.items, path + '[' + i + ']', errors, warnings)
549
+ }
550
+ }
551
+ },
552
+
553
+ /**
554
+ * Get nested property value
555
+ * @private
556
+ */
557
+ _getNestedProperty: function(obj, path) {
558
+ return path.split('.').reduce(function(current, prop) {
559
+ return current && current[prop]
560
+ }, obj)
561
+ },
562
+
563
+ /**
564
+ * Validate email format
565
+ * @private
566
+ */
567
+ _isValidEmail: function(email) {
568
+ var emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
569
+ return emailRegex.test(email)
570
+ },
571
+
572
+ /**
573
+ * Validate date format (YYYY-MM-DD)
574
+ * @private
575
+ */
576
+ _isValidDate: function(dateString) {
577
+ var date = new Date(dateString)
578
+ return !isNaN(date.getTime()) && dateString.match(/^\d{4}-\d{2}-\d{2}$/)
579
+ },
580
+
581
+ /**
582
+ * Validate date-time format (ISO 8601)
583
+ * @private
584
+ */
585
+ _isValidDateTime: function(dateTimeString) {
586
+ var date = new Date(dateTimeString)
587
+ return !isNaN(date.getTime())
588
+ },
589
+
590
+ /**
591
+ * Add custom schema
592
+ * @param {String} name - Schema name
593
+ * @param {Object} definition - Schema definition
594
+ */
595
+ addSchema: function(name, definition) {
596
+ $.checkArgument(typeof name === 'string', 'Schema name must be string')
597
+ $.checkArgument(definition && typeof definition === 'object', 'Invalid schema definition')
598
+
599
+ schemas[name] = definition
600
+ },
601
+
602
+ /**
603
+ * Create schema template
604
+ * @param {String} credentialType - Type of credential
605
+ * @returns {Object} Template credential
606
+ */
607
+ createTemplate: function(credentialType) {
608
+ var schema = schemas[credentialType]
609
+ if (!schema) {
610
+ throw new Error('Unknown credential type: ' + credentialType)
611
+ }
612
+
613
+ var template = {
614
+ '@context': schema['@context'] || ['https://www.w3.org/2018/credentials/v1'],
615
+ type: schema.type || ['VerifiableCredential'],
616
+ issuer: 'did:smartledger:ISSUER_DID_HERE',
617
+ issuanceDate: new Date().toISOString(),
618
+ credentialSubject: this._createSubjectTemplate(schema.properties ? schema.properties.credentialSubject : {})
619
+ }
620
+
621
+ return template
622
+ },
623
+
624
+ /**
625
+ * Create subject template from schema
626
+ * @private
627
+ */
628
+ _createSubjectTemplate: function(subjectSchema) {
629
+ var template = {
630
+ id: 'SUBJECT_ID_HERE'
631
+ }
632
+
633
+ if (subjectSchema.properties) {
634
+ Object.keys(subjectSchema.properties).forEach(function(prop) {
635
+ var propSchema = subjectSchema.properties[prop]
636
+ template[prop] = this._getDefaultValue(propSchema)
637
+ }.bind(this))
638
+ }
639
+
640
+ return template
641
+ },
642
+
643
+ /**
644
+ * Get default value for property type
645
+ * @private
646
+ */
647
+ _getDefaultValue: function(schema) {
648
+ switch (schema.type) {
649
+ case 'string':
650
+ if (schema.enum) {
651
+ return schema.enum[0]
652
+ }
653
+ if (schema.format === 'email') {
654
+ return 'example@example.com'
655
+ }
656
+ if (schema.format === 'date') {
657
+ return '2023-01-01'
658
+ }
659
+ if (schema.format === 'date-time') {
660
+ return new Date().toISOString()
661
+ }
662
+ return 'PLACEHOLDER_STRING'
663
+
664
+ case 'number':
665
+ return schema.minimum || 0
666
+
667
+ case 'boolean':
668
+ return true
669
+
670
+ case 'array':
671
+ return []
672
+
673
+ case 'object':
674
+ return {}
675
+
676
+ default:
677
+ return null
678
+ }
679
+ }
680
+ }
681
+
682
+ module.exports = SchemaValidator