@aikdna/kdna-core 0.17.0 → 0.18.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.
@@ -126,8 +126,8 @@
126
126
  "required": ["kind", "path"],
127
127
  "additionalProperties": false,
128
128
  "properties": {
129
- "kind": { "type": ["string", "null"], "enum": ["dir", "file", null] },
130
- "path": { "type": "string" }
129
+ "kind": { "type": ["string", "null"], "enum": ["dir", "file", "memory", null] },
130
+ "path": { "type": ["string", "null"] }
131
131
  }
132
132
  }
133
133
  }
@@ -0,0 +1,68 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/aikdna/kdna/specs/runtime-capsule-1.schema.json",
4
+ "title": "KDNA Runtime Capsule 1",
5
+ "description": "Frozen compatibility schema. The historical asset_digest member means E (kdna-runtime-entry-set-v1), never the final container digest A.",
6
+ "type": "object",
7
+ "required": [
8
+ "type",
9
+ "version",
10
+ "domain",
11
+ "judgment_version",
12
+ "asset_digest",
13
+ "signature",
14
+ "access",
15
+ "risk_level",
16
+ "profile",
17
+ "context",
18
+ "trace"
19
+ ],
20
+ "additionalProperties": true,
21
+ "properties": {
22
+ "type": { "const": "kdna.context.capsule" },
23
+ "version": { "const": "1.0" },
24
+ "domain": { "type": ["string", "null"] },
25
+ "judgment_version": { "type": ["string", "null"] },
26
+ "asset_digest": {
27
+ "description": "Frozen Capsule 1 name for the runtime entry-set digest E.",
28
+ "oneOf": [{ "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" }, { "type": "null" }]
29
+ },
30
+ "signature": { "$ref": "#/$defs/signature" },
31
+ "access": { "type": "string" },
32
+ "risk_level": { "type": ["string", "null"] },
33
+ "profile": { "enum": ["index", "compact", "scenario", "full"] },
34
+ "context": { "type": "object" },
35
+ "trace": { "$ref": "#/$defs/trace" }
36
+ },
37
+ "$defs": {
38
+ "signature": {
39
+ "type": "object",
40
+ "required": ["state"],
41
+ "additionalProperties": false,
42
+ "properties": {
43
+ "state": { "enum": ["verified", "not_checked", "absent"] },
44
+ "issuer": { "type": "string", "minLength": 1 }
45
+ }
46
+ },
47
+ "trace": {
48
+ "type": "object",
49
+ "required": [
50
+ "payload_encoding",
51
+ "loaded_by",
52
+ "loaded_at",
53
+ "schema_valid",
54
+ "signature_state",
55
+ "profile"
56
+ ],
57
+ "additionalProperties": true,
58
+ "properties": {
59
+ "payload_encoding": { "const": "cbor" },
60
+ "loaded_by": { "const": "kdna-core" },
61
+ "loaded_at": { "type": "string", "format": "date-time" },
62
+ "schema_valid": { "type": "boolean" },
63
+ "signature_state": { "enum": ["verified", "not_checked", "absent"] },
64
+ "profile": { "enum": ["index", "compact", "scenario", "full"] }
65
+ }
66
+ }
67
+ }
68
+ }
@@ -0,0 +1,140 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/aikdna/kdna/specs/runtime-capsule-2.schema.json",
4
+ "title": "KDNA Runtime Capsule 2",
5
+ "description": "Opt-in Runtime Capsule carrying explicit A/C/E digest evidence. P is external delivery metadata and is never embedded here.",
6
+ "type": "object",
7
+ "required": [
8
+ "type",
9
+ "version",
10
+ "asset",
11
+ "digests",
12
+ "signature",
13
+ "access",
14
+ "risk_level",
15
+ "profile",
16
+ "context",
17
+ "trace"
18
+ ],
19
+ "additionalProperties": false,
20
+ "properties": {
21
+ "type": { "const": "kdna.context.capsule" },
22
+ "version": { "const": "2.0" },
23
+ "asset": { "$ref": "#/$defs/asset" },
24
+ "digests": {
25
+ "allOf": [
26
+ {
27
+ "$ref": "https://github.com/aikdna/kdna/specs/digest-evidence.schema.json"
28
+ },
29
+ {
30
+ "properties": {
31
+ "asset": { "$ref": "#/$defs/successfulDigest" },
32
+ "content": { "$ref": "#/$defs/successfulDigest" },
33
+ "runtime_entry_set": { "$ref": "#/$defs/successfulDigest" }
34
+ }
35
+ }
36
+ ]
37
+ },
38
+ "signature": { "$ref": "#/$defs/signature" },
39
+ "access": { "enum": ["public", "licensed", "remote"] },
40
+ "risk_level": { "type": ["string", "null"] },
41
+ "profile": { "enum": ["index", "compact", "scenario", "full"] },
42
+ "context": { "type": "object" },
43
+ "trace": { "$ref": "#/$defs/trace" },
44
+ "compatibility": { "$ref": "#/$defs/compatibility" }
45
+ },
46
+ "$defs": {
47
+ "sha256": {
48
+ "type": "string",
49
+ "pattern": "^sha256:[0-9a-f]{64}$"
50
+ },
51
+ "asset": {
52
+ "type": "object",
53
+ "required": ["asset_id", "asset_uid", "version", "judgment_version"],
54
+ "additionalProperties": false,
55
+ "properties": {
56
+ "asset_id": {
57
+ "type": "string",
58
+ "pattern": "^[a-zA-Z][a-zA-Z0-9_-]*(:[a-zA-Z0-9_.-]+)+$"
59
+ },
60
+ "asset_uid": { "type": "string", "format": "uri" },
61
+ "version": {
62
+ "type": "string",
63
+ "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+([+-].+)?$"
64
+ },
65
+ "judgment_version": {
66
+ "type": "string",
67
+ "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+([+-].+)?$"
68
+ }
69
+ }
70
+ },
71
+ "successfulDigest": {
72
+ "type": "object",
73
+ "properties": {
74
+ "value": { "$ref": "#/$defs/sha256" },
75
+ "comparison": {
76
+ "type": "object",
77
+ "properties": {
78
+ "state": { "enum": ["matched", "not_compared"] }
79
+ }
80
+ }
81
+ }
82
+ },
83
+ "signature": {
84
+ "type": "object",
85
+ "required": ["state"],
86
+ "additionalProperties": false,
87
+ "properties": {
88
+ "state": { "enum": ["verified", "not_checked", "absent"] },
89
+ "issuer": { "type": "string", "minLength": 1 }
90
+ }
91
+ },
92
+ "trace": {
93
+ "type": "object",
94
+ "required": [
95
+ "payload_encoding",
96
+ "loaded_by",
97
+ "loaded_at",
98
+ "input_kind",
99
+ "runtime_eligible",
100
+ "schema_valid",
101
+ "signature_state",
102
+ "profile"
103
+ ],
104
+ "additionalProperties": false,
105
+ "properties": {
106
+ "payload_encoding": { "const": "cbor" },
107
+ "loaded_by": { "const": "kdna-core" },
108
+ "loaded_at": { "type": "string", "format": "date-time" },
109
+ "input_kind": { "enum": ["packaged_file", "packaged_bytes"] },
110
+ "runtime_eligible": { "const": true },
111
+ "schema_valid": { "const": true },
112
+ "signature_state": { "enum": ["verified", "not_checked", "absent"] },
113
+ "profile": { "enum": ["index", "compact", "scenario", "full"] }
114
+ }
115
+ },
116
+ "compatibility": {
117
+ "description": "Adapter-only values with no Capsule 2 identity or routing authority.",
118
+ "type": "object",
119
+ "minProperties": 1,
120
+ "additionalProperties": false,
121
+ "properties": {
122
+ "capsule_1_domain": { "type": "string", "minLength": 1 },
123
+ "capsule_1_access": { "enum": ["open", "protected", "runtime"] },
124
+ "capsule_1_extensions": { "$ref": "#/$defs/capsule1Extensions" }
125
+ }
126
+ },
127
+ "capsule1Extensions": {
128
+ "description": "Frozen Capsule 1 extension values carried only for exact one-way adapter parity.",
129
+ "type": "object",
130
+ "minProperties": 1,
131
+ "additionalProperties": false,
132
+ "properties": {
133
+ "extends_chain": { "type": "array" },
134
+ "inheritance_applied": { "type": "boolean" },
135
+ "resolved_dependencies": { "type": "array" },
136
+ "rag_isolation_policy": { "type": "object" }
137
+ }
138
+ }
139
+ }
140
+ }
@@ -6,15 +6,13 @@ const fs = require('fs');
6
6
  const crypto = require('crypto');
7
7
  const zlib = require('zlib');
8
8
  const cbor = require('cbor-x');
9
- const { loadDomainFromFiles, formatContext } = require('./loader');
10
9
 
11
10
  const KDNA_MEDIA_TYPE = 'application/vnd.kdna.asset';
11
+ const ASSET_SOURCE_BYTES = Symbol.for('@aikdna/kdna-core.asset-source-bytes');
12
12
 
13
- // Standard KDNA domain data entries — kept in lockstep with loader.FILE_MAP.
14
- // Asset reader pre-loads these so callers don't have to enumerate entry names.
15
- // NOTE: kdna.json / manifest.json are read separately via readManifest(); do not
16
- // add them here. KDNA_Cluster is intentionally omitted — its schema exists but
17
- // is not yet wired into the loader contract.
13
+ // Deprecated legacy authoring source entry names. Current Runtime assets carry
14
+ // judgment only in payload.kdnab and never expose these as distribution entries.
15
+ // Kept for source-migration callers; loadProfile does not use this list.
18
16
  const STANDARD_ENTRIES = Object.freeze([
19
17
  'KDNA_Core.json',
20
18
  'KDNA_Patterns.json',
@@ -43,6 +41,14 @@ function stableStringify(value) {
43
41
  return JSON.stringify(value);
44
42
  }
45
43
 
44
+ function compareEntryNamesByUtf8(left, right) {
45
+ return Buffer.compare(Buffer.from(left, 'utf8'), Buffer.from(right, 'utf8'));
46
+ }
47
+
48
+ function sortedEntryNames(entries) {
49
+ return [...entries.keys()].sort(compareEntryNamesByUtf8);
50
+ }
51
+
46
52
  function parseJson(buf, entryName) {
47
53
  try {
48
54
  return JSON.parse(Buffer.isBuffer(buf) ? buf.toString('utf8') : String(buf));
@@ -51,6 +57,17 @@ function parseJson(buf, entryName) {
51
57
  }
52
58
  }
53
59
 
60
+ function validateDecodedEntry(buf, entryName) {
61
+ if (entryName === 'payload.kdnab') {
62
+ try {
63
+ return cbor.decode(buf);
64
+ } catch (e) {
65
+ throw new Error(`${entryName}: invalid CBOR: ${e.message}`, { cause: e });
66
+ }
67
+ }
68
+ return parseJson(buf, entryName);
69
+ }
70
+
54
71
  function encryptedEntries(manifest) {
55
72
  const entries = manifest?.encryption?.encrypted_entries;
56
73
  return Array.isArray(entries) ? entries : [];
@@ -188,7 +205,7 @@ function manifestForDigest(manifest) {
188
205
  function buildContentDigest(asset) {
189
206
  const parts = [];
190
207
  const excluded = new Set(['.DS_Store', 'signature.json', 'build-receipt.json']);
191
- for (const entryName of [...asset.entries.keys()].sort()) {
208
+ for (const entryName of sortedEntryNames(asset.entries)) {
192
209
  if (excluded.has(entryName)) continue;
193
210
  if (entryName.startsWith('reports/')) continue;
194
211
  const entryBuf = asset.readEntry(entryName);
@@ -243,7 +260,7 @@ function buildSigningPayload(asset, options = {}) {
243
260
  // byte strings and the signature would fail to verify. The fix
244
261
  // mirrors `buildContentDigest`'s exclusion set exactly.
245
262
  const parts = [];
246
- for (const entryName of [...asset.entries.keys()].sort()) {
263
+ for (const entryName of sortedEntryNames(asset.entries)) {
247
264
  if (entryName === '.DS_Store' || entryName === 'signature.json') continue;
248
265
  if (entryName === 'build-receipt.json') continue;
249
266
  if (entryName.startsWith('reports/')) continue;
@@ -324,7 +341,9 @@ function verifyHumanLockSignatures(coreData, manifest, errors, warnings) {
324
341
  ['stances', 'stance'],
325
342
  ];
326
343
 
327
- let verified = 0, missing = 0, invalid = 0;
344
+ let verified = 0,
345
+ missing = 0,
346
+ invalid = 0;
328
347
  for (const [arrayName] of CORE_CARD_ARRAYS) {
329
348
  const cards = coreData?.[arrayName];
330
349
  if (!Array.isArray(cards) || cards.length === 0) continue;
@@ -342,8 +361,11 @@ function verifyHumanLockSignatures(coreData, manifest, errors, warnings) {
342
361
  const sig = Buffer.from(String(hl.signature).replace(/^ed25519:/, ''), 'hex');
343
362
  const key = crypto.createPublicKey(publicKeyPEM);
344
363
  const ok = crypto.verify(null, Buffer.from(payload), key, sig);
345
- if (ok) { verified++; }
346
- else { invalid++; }
364
+ if (ok) {
365
+ verified++;
366
+ } else {
367
+ invalid++;
368
+ }
347
369
  } catch {
348
370
  invalid++;
349
371
  }
@@ -351,7 +373,9 @@ function verifyHumanLockSignatures(coreData, manifest, errors, warnings) {
351
373
  }
352
374
 
353
375
  if (invalid > 0) {
354
- errors.push(`${invalid} Human Lock signature(s) failed verification — judgment may have been altered`);
376
+ errors.push(
377
+ `${invalid} Human Lock signature(s) failed verification — judgment may have been altered`,
378
+ );
355
379
  }
356
380
  if (missing > 0) {
357
381
  warnings.push(`${missing} locked card(s) have no Human Lock signature`);
@@ -361,29 +385,10 @@ function verifyHumanLockSignatures(coreData, manifest, errors, warnings) {
361
385
  }
362
386
  }
363
387
 
364
- function validateManifestIdentity(manifest, errors, _warnings) {
365
- if (manifest.kdna_spec) {
366
- errors.push('kdna.json: kdna_spec is not allowed. Use kdna_version.');
367
- }
368
- if (manifest.format && manifest.format !== 'kdna') {
369
- errors.push(`kdna.json.format: invalid value "${manifest.format}". Expected "kdna".`);
370
- }
371
- if (!manifest.kdna_version) {
372
- errors.push('kdna.json: missing required field "kdna_version"');
373
- } else if (manifest.kdna_version !== '1.0') {
374
- errors.push(
375
- `kdna.json.kdna_version: invalid value "${manifest.kdna_version}". Expected "1.0".`,
376
- );
377
- }
378
- if (manifest.language) {
379
- errors.push('kdna.json: language is not allowed. Use default_language and languages.');
380
- }
381
- }
382
-
383
388
  function openAsset(input) {
384
389
  const { buffer, path } = normalizeInput(input);
385
390
  const entries = parseZipEntries(buffer);
386
- return {
391
+ const asset = {
387
392
  path,
388
393
  size: buffer.length,
389
394
  asset_digest: `sha256:${sha256Hex(buffer)}`,
@@ -394,6 +399,29 @@ function openAsset(input) {
394
399
  return readZipEntry(buffer, entry);
395
400
  },
396
401
  };
402
+ Object.defineProperty(asset, ASSET_SOURCE_BYTES, {
403
+ value: buffer,
404
+ enumerable: false,
405
+ writable: false,
406
+ });
407
+ return asset;
408
+ }
409
+
410
+ function validateCurrentContainer(asset) {
411
+ const bytes = asset[ASSET_SOURCE_BYTES];
412
+ if (!Buffer.isBuffer(bytes)) {
413
+ throw new Error('Current KDNA validation requires the original .kdna container bytes');
414
+ }
415
+ return require('./v1').validate(bytes);
416
+ }
417
+
418
+ function appendCurrentValidationErrors(asset, errors) {
419
+ try {
420
+ const validation = validateCurrentContainer(asset);
421
+ if (!validation.overall_valid) errors.push(...validation.problems);
422
+ } catch (e) {
423
+ errors.push(e.message);
424
+ }
397
425
  }
398
426
 
399
427
  function listEntries(asset) {
@@ -409,30 +437,18 @@ function readManifest(asset) {
409
437
  return parseJson(asset.readEntry('kdna.json'), 'kdna.json');
410
438
  }
411
439
 
412
- function readDataMapSync(asset, options = {}) {
413
- const dataMap = {};
414
- const manifest = readManifest(asset);
415
-
440
+ function readDataMapSync(asset, _options = {}) {
416
441
  if (asset.entries.has('payload.kdnab')) {
417
- const payloadBuf = asset.readEntry('payload.kdnab');
418
- const payload = cbor.decode(payloadBuf);
419
- if (payload && payload.judgment) {
420
- if (payload.judgment.core) dataMap['KDNA_Core.json'] = payload.judgment.core;
421
- if (payload.judgment.patterns) dataMap['KDNA_Patterns.json'] = payload.judgment.patterns;
422
- if (payload.judgment.scenarios) dataMap['KDNA_Scenarios.json'] = payload.judgment.scenarios;
423
- if (payload.judgment.cases) dataMap['KDNA_Cases.json'] = payload.judgment.cases;
424
- if (payload.judgment.reasoning) dataMap['KDNA_Reasoning.json'] = payload.judgment.reasoning;
425
- if (payload.judgment.evolution) dataMap['KDNA_Evolution.json'] = payload.judgment.evolution;
426
- }
427
-
428
- const encrypted = encryptedEntries(manifest);
429
- if (encrypted.length && typeof options.decryptEntry !== 'function') {
430
- throw new Error(`encrypted entries require decryptEntry hook: ${encrypted.join(', ')}`);
431
- }
432
- return dataMap;
442
+ const error = new Error(
443
+ 'readDataMap is a legacy source-tree API and does not project current payload.kdnab into KDNA_Core.json/KDNA_Patterns.json. Use loadProfile or loadAuthorized.',
444
+ );
445
+ error.code = 'KDNA_LEGACY_DATA_MAP_UNSUPPORTED';
446
+ throw error;
433
447
  }
434
448
 
435
- throw new Error('Not a KDNA asset: missing payload.kdnab');
449
+ const error = new Error('Not a current KDNA asset: missing payload.kdnab');
450
+ error.code = 'KDNA_FORMAT_INVALID';
451
+ throw error;
436
452
  }
437
453
 
438
454
  function verifySync(asset, options = {}) {
@@ -440,6 +456,12 @@ function verifySync(asset, options = {}) {
440
456
  const warnings = [];
441
457
  const entries = listEntries(asset);
442
458
 
459
+ // The current v1 implementation is the sole authority for container,
460
+ // manifest, CBOR payload, checksum, and load-contract validity. The reader
461
+ // adds transport identity and legacy signature hooks; it must not maintain a
462
+ // second manifest or payload dialect.
463
+ appendCurrentValidationErrors(asset, errors);
464
+
443
465
  if (!asset.entries.has('kdna.json')) errors.push('required entry missing: kdna.json');
444
466
  verifyMediaType(asset, errors);
445
467
  if (!asset.entries.has('payload.kdnab')) errors.push('required entry missing: payload.kdnab');
@@ -450,7 +472,9 @@ function verifySync(asset, options = {}) {
450
472
  errors.push(`asset digest mismatch: expected ${options.asset_digest}, got ${asset_digest}`);
451
473
  }
452
474
  if (options.content_digest && options.content_digest !== content_digest) {
453
- errors.push(`content digest mismatch: expected ${options.content_digest}, got ${content_digest}`);
475
+ errors.push(
476
+ `content digest mismatch: expected ${options.content_digest}, got ${content_digest}`,
477
+ );
454
478
  }
455
479
 
456
480
  let manifest = null;
@@ -458,7 +482,6 @@ function verifySync(asset, options = {}) {
458
482
  if (asset.entries.has('kdna.json')) {
459
483
  try {
460
484
  manifest = readManifest(asset);
461
- validateManifestIdentity(manifest, errors, warnings);
462
485
  const encrypted = encryptedEntries(manifest);
463
486
  if (encrypted.length) {
464
487
  warnings.push(`encrypted entries present: ${encrypted.join(', ')}`);
@@ -479,7 +502,7 @@ function verifySync(asset, options = {}) {
479
502
  asset.readEntry(entryName),
480
503
  options,
481
504
  );
482
- parseJson(decrypted, entryName);
505
+ validateDecodedEntry(decrypted, entryName);
483
506
  } catch (e) {
484
507
  errors.push(e.message);
485
508
  }
@@ -516,29 +539,15 @@ function verifySync(asset, options = {}) {
516
539
  }
517
540
 
518
541
  function loadProfileSync(asset, profile = 'compact', options = {}) {
519
- const manifest = readManifest(asset);
520
- if (profile === 'index') {
521
- return {
522
- profile,
523
- manifest,
524
- asset_digest: asset.asset_digest,
525
- content_digest: buildContentDigest(asset),
526
- entries: listEntries(asset),
527
- name: manifest.name || manifest.asset_id || null,
528
- version: manifest.version || null,
529
- judgment_version: manifest.judgment_version || null,
530
- keywords: manifest.keywords || [],
531
- };
532
- }
533
- const dataMap = readDataMapSync(asset, STANDARD_ENTRIES, options);
534
- const mode = profile === 'full' ? 'all' : profile === 'scenario' ? 'auto' : 'minimum';
535
- const domain = loadDomainFromFiles(dataMap, { mode, input: options.input || '' });
536
- return {
542
+ const bytes = asset[ASSET_SOURCE_BYTES];
543
+ if (!Buffer.isBuffer(bytes)) {
544
+ throw new Error('loadProfile requires the original .kdna container bytes');
545
+ }
546
+ return require('./runtime-api').loadAuthorized(bytes, {
547
+ ...options,
537
548
  profile,
538
- manifest,
539
- domain,
540
- context: options.context === false || !domain ? null : formatContext(domain),
541
- };
549
+ as: options.as || 'json',
550
+ });
542
551
  }
543
552
 
544
553
  function createKdnaAssetReader() {
@@ -565,7 +574,13 @@ function createKdnaAssetReader() {
565
574
  if (!asset.entries.has(entryName)) return null;
566
575
  const manifest =
567
576
  entryName === 'kdna.json' ? null : parseJson(asset.readEntry('kdna.json'), 'kdna.json');
568
- const buf = maybeDecryptEntrySync(asset, manifest, entryName, asset.readEntry(entryName), options);
577
+ const buf = maybeDecryptEntrySync(
578
+ asset,
579
+ manifest,
580
+ entryName,
581
+ asset.readEntry(entryName),
582
+ options,
583
+ );
569
584
  return parseJson(buf, entryName);
570
585
  },
571
586
 
@@ -591,21 +606,8 @@ function createKdnaAssetReader() {
591
606
 
592
607
  readDataMapSync,
593
608
 
594
- async readDataMap(asset, entries = STANDARD_ENTRIES, options = {}) {
595
- const dataMap = {};
596
- const manifest = await this.readManifest(asset);
597
- for (const entryName of entries) {
598
- if (!asset.entries.has(entryName)) continue;
599
- const buf = await maybeDecryptEntry(
600
- asset,
601
- manifest,
602
- entryName,
603
- asset.readEntry(entryName),
604
- options,
605
- );
606
- dataMap[entryName] = parseJson(buf, entryName);
607
- }
608
- return dataMap;
609
+ async readDataMap(asset, _entries = STANDARD_ENTRIES, options = {}) {
610
+ return readDataMapSync(asset, options);
609
611
  },
610
612
 
611
613
  contentDigestSync: buildContentDigest,
@@ -621,6 +623,8 @@ function createKdnaAssetReader() {
621
623
  const warnings = [];
622
624
  const entries = [...asset.entries.keys()].sort();
623
625
 
626
+ appendCurrentValidationErrors(asset, errors);
627
+
624
628
  if (!asset.entries.has('kdna.json')) errors.push('required entry missing: kdna.json');
625
629
  verifyMediaType(asset, errors);
626
630
  if (!asset.entries.has('payload.kdnab')) errors.push('required entry missing: payload.kdnab');
@@ -641,7 +645,6 @@ function createKdnaAssetReader() {
641
645
  if (asset.entries.has('kdna.json')) {
642
646
  try {
643
647
  manifest = parseJson(asset.readEntry('kdna.json'), 'kdna.json');
644
- validateManifestIdentity(manifest, errors, warnings);
645
648
  const encrypted = encryptedEntries(manifest);
646
649
  if (encrypted.length) {
647
650
  warnings.push(`encrypted entries present: ${encrypted.join(', ')}`);
@@ -662,7 +665,7 @@ function createKdnaAssetReader() {
662
665
  asset.readEntry(entryName),
663
666
  options,
664
667
  );
665
- parseJson(decrypted, entryName);
668
+ validateDecodedEntry(decrypted, entryName);
666
669
  } catch (e) {
667
670
  errors.push(e.message);
668
671
  }
@@ -692,30 +695,7 @@ function createKdnaAssetReader() {
692
695
  loadProfileSync,
693
696
 
694
697
  async loadProfile(asset, profile = 'compact', options = {}) {
695
- const manifest = await this.readManifest(asset);
696
- if (profile === 'index') {
697
- return {
698
- profile,
699
- manifest,
700
- asset_digest: asset.asset_digest,
701
- content_digest: buildContentDigest(asset),
702
- entries: await this.listEntries(asset),
703
- name: manifest.name || manifest.asset_id || null,
704
- version: manifest.version || null,
705
- judgment_version: manifest.judgment_version || null,
706
- keywords: manifest.keywords || [],
707
- };
708
- }
709
-
710
- const dataMap = await this.readDataMap(asset, STANDARD_ENTRIES, options);
711
- const mode = profile === 'full' ? 'all' : profile === 'scenario' ? 'auto' : 'minimum';
712
- const domain = loadDomainFromFiles(dataMap, { mode, input: options.input || '' });
713
- return {
714
- profile,
715
- manifest,
716
- domain,
717
- context: options.context === false || !domain ? null : formatContext(domain),
718
- };
698
+ return loadProfileSync(asset, profile, options);
719
699
  },
720
700
  };
721
701
  }