@aikdna/kdna-core 0.8.0 → 0.9.1
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/package.json +2 -2
- package/src/asset-reader.js +20 -34
- package/src/lint-pure.js +3 -3
- package/src/types.d.ts +2 -2
- package/src/workpack-pure.js +2 -2
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aikdna/kdna-core",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "KDNA core library —
|
|
3
|
+
"version": "0.9.1",
|
|
4
|
+
"description": "KDNA core library — load, validate, lint, and render KDNA domain judgment assets. Supports KDNA Container format (payload.kdnab via CBOR).",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "src/index.js",
|
|
7
7
|
"module": "src/index.mjs",
|
package/src/asset-reader.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* KDNA Asset Reader — direct .kdna container access.
|
|
3
|
-
*
|
|
4
|
-
* Supports KDNA Container v2 (payload.kdnab via CBOR).
|
|
5
|
-
* V1 plaintext containers (KDNA_Core.json etc. as ZIP entries) are rejected.
|
|
6
3
|
*/
|
|
7
4
|
|
|
8
5
|
const fs = require('fs');
|
|
@@ -11,28 +8,25 @@ const zlib = require('zlib');
|
|
|
11
8
|
const cbor = require('cbor-x');
|
|
12
9
|
const { loadDomainFromFiles, formatContext } = require('./loader');
|
|
13
10
|
|
|
14
|
-
const
|
|
15
|
-
'kdna.json',
|
|
16
|
-
'payload.kdnab',
|
|
17
|
-
'KDNA_Core.json',
|
|
18
|
-
'KDNA_Patterns.json',
|
|
19
|
-
'KDNA_Scenarios.json',
|
|
20
|
-
'KDNA_Cases.json',
|
|
21
|
-
'KDNA_Reasoning.json',
|
|
22
|
-
'KDNA_Evolution.json',
|
|
23
|
-
];
|
|
11
|
+
const KDNA_MEDIA_TYPE = 'application/vnd.aikdna.kdna+zip';
|
|
24
12
|
|
|
25
|
-
|
|
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.
|
|
18
|
+
const STANDARD_ENTRIES = Object.freeze([
|
|
26
19
|
'KDNA_Core.json',
|
|
27
20
|
'KDNA_Patterns.json',
|
|
28
21
|
'KDNA_Scenarios.json',
|
|
29
22
|
'KDNA_Cases.json',
|
|
30
23
|
'KDNA_Reasoning.json',
|
|
31
24
|
'KDNA_Evolution.json',
|
|
32
|
-
];
|
|
25
|
+
]);
|
|
33
26
|
|
|
27
|
+
// Matches any entry that holds JSON content (used to canonicalize the entry
|
|
28
|
+
// before hashing/signing so digests are stable across re-serialization).
|
|
34
29
|
const JSON_ENTRY_RE = /\.json$/i;
|
|
35
|
-
const KDNA_MEDIA_TYPE = 'application/vnd.aikdna.kdna+zip';
|
|
36
30
|
|
|
37
31
|
function sha256Hex(buf) {
|
|
38
32
|
return crypto.createHash('sha256').update(buf).digest('hex');
|
|
@@ -338,9 +332,9 @@ function validateManifestIdentity(manifest, errors, _warnings) {
|
|
|
338
332
|
if (manifest.format && manifest.format !== 'kdna') {
|
|
339
333
|
errors.push(`kdna.json.format: invalid value "${manifest.format}". Expected "kdna".`);
|
|
340
334
|
}
|
|
341
|
-
if (manifest.format_version && manifest.format_version !== '
|
|
335
|
+
if (manifest.format_version && manifest.format_version !== '2.0') {
|
|
342
336
|
errors.push(
|
|
343
|
-
`kdna.json.format_version: invalid value "${manifest.format_version}". Expected "
|
|
337
|
+
`kdna.json.format_version: invalid value "${manifest.format_version}". Expected "2.0".`,
|
|
344
338
|
);
|
|
345
339
|
}
|
|
346
340
|
if (!manifest.spec_version) errors.push('kdna.json: missing required field "spec_version"');
|
|
@@ -380,11 +374,10 @@ function readManifest(asset) {
|
|
|
380
374
|
return parseJson(asset.readEntry('kdna.json'), 'kdna.json');
|
|
381
375
|
}
|
|
382
376
|
|
|
383
|
-
function readDataMapSync(asset,
|
|
377
|
+
function readDataMapSync(asset, options = {}) {
|
|
384
378
|
const dataMap = {};
|
|
385
379
|
const manifest = readManifest(asset);
|
|
386
380
|
|
|
387
|
-
// ── KDNA Container v2: decode CBOR payload ──
|
|
388
381
|
if (asset.entries.has('payload.kdnab')) {
|
|
389
382
|
const payloadBuf = asset.readEntry('payload.kdnab');
|
|
390
383
|
const payload = cbor.decode(payloadBuf);
|
|
@@ -396,19 +389,15 @@ function readDataMapSync(asset, entries = STANDARD_ENTRIES, options = {}) {
|
|
|
396
389
|
if (payload.judgment.reasoning) dataMap['KDNA_Reasoning.json'] = payload.judgment.reasoning;
|
|
397
390
|
if (payload.judgment.evolution) dataMap['KDNA_Evolution.json'] = payload.judgment.evolution;
|
|
398
391
|
}
|
|
392
|
+
|
|
393
|
+
const encrypted = encryptedEntries(manifest);
|
|
394
|
+
if (encrypted.length && typeof options.decryptEntry !== 'function') {
|
|
395
|
+
throw new Error(`encrypted entries require decryptEntry hook: ${encrypted.join(', ')}`);
|
|
396
|
+
}
|
|
399
397
|
return dataMap;
|
|
400
398
|
}
|
|
401
399
|
|
|
402
|
-
|
|
403
|
-
if (encrypted.length && typeof options.decryptEntry !== 'function') {
|
|
404
|
-
throw new Error(`encrypted entries require decryptEntry hook: ${encrypted.join(', ')}`);
|
|
405
|
-
}
|
|
406
|
-
for (const entryName of entries) {
|
|
407
|
-
if (!asset.entries.has(entryName)) continue;
|
|
408
|
-
const buf = maybeDecryptEntrySync(asset, manifest, entryName, asset.readEntry(entryName), options);
|
|
409
|
-
dataMap[entryName] = parseJson(buf, entryName);
|
|
410
|
-
}
|
|
411
|
-
return dataMap;
|
|
400
|
+
throw new Error('Not a KDNA asset: missing payload.kdnab');
|
|
412
401
|
}
|
|
413
402
|
|
|
414
403
|
function verifySync(asset, options = {}) {
|
|
@@ -418,10 +407,7 @@ function verifySync(asset, options = {}) {
|
|
|
418
407
|
|
|
419
408
|
if (!asset.entries.has('kdna.json')) errors.push('required entry missing: kdna.json');
|
|
420
409
|
verifyMediaType(asset, errors);
|
|
421
|
-
if (!asset.entries.has('
|
|
422
|
-
if (!asset.entries.has('KDNA_Patterns.json')) {
|
|
423
|
-
errors.push('required entry missing: KDNA_Patterns.json');
|
|
424
|
-
}
|
|
410
|
+
if (!asset.entries.has('payload.kdnab')) errors.push('required entry missing: payload.kdnab');
|
|
425
411
|
|
|
426
412
|
const content_digest = buildContentDigest(asset);
|
|
427
413
|
const asset_digest = asset.asset_digest;
|
package/src/lint-pure.js
CHANGED
|
@@ -258,7 +258,7 @@ function lintDomain(dataMap) {
|
|
|
258
258
|
*/
|
|
259
259
|
const VALID_STATUS = new Set(['draft', 'experimental', 'stable', 'deprecated', 'staging']);
|
|
260
260
|
const VALID_BADGE = new Set(['untested', 'tested', 'validated', 'expert_reviewed', 'production_ready']);
|
|
261
|
-
const VALID_ACCESS = new Set(['
|
|
261
|
+
const VALID_ACCESS = new Set(['public', 'licensed', 'remote']);
|
|
262
262
|
const VALID_RISK = new Set(['R0', 'R1', 'R2', 'R3']);
|
|
263
263
|
const VALID_I18N = new Set(['L0', 'L1', 'L2', 'L3']);
|
|
264
264
|
const VALID_PRIVACY = new Set(['public', 'private', 'sensitive', 'regulated']);
|
|
@@ -318,9 +318,9 @@ function validateManifest(manifest) {
|
|
|
318
318
|
if (manifest.format && manifest.format !== 'kdna') {
|
|
319
319
|
errors.push(`kdna.json.format: invalid value "${manifest.format}". Expected "kdna".`);
|
|
320
320
|
}
|
|
321
|
-
if (manifest.format_version && manifest.format_version !== '
|
|
321
|
+
if (manifest.format_version && manifest.format_version !== '2.0') {
|
|
322
322
|
errors.push(
|
|
323
|
-
`kdna.json.format_version: invalid value "${manifest.format_version}". Expected "
|
|
323
|
+
`kdna.json.format_version: invalid value "${manifest.format_version}". Expected "2.0".`,
|
|
324
324
|
);
|
|
325
325
|
}
|
|
326
326
|
if (manifest.status && !VALID_STATUS.has(manifest.status)) {
|
package/src/types.d.ts
CHANGED
|
@@ -204,14 +204,14 @@ export interface KDNAFileDataMap {
|
|
|
204
204
|
|
|
205
205
|
export interface KDNAManifest {
|
|
206
206
|
format: 'kdna';
|
|
207
|
-
format_version: '
|
|
207
|
+
format_version: '2.0';
|
|
208
208
|
spec_version: string;
|
|
209
209
|
name: string;
|
|
210
210
|
version: string;
|
|
211
211
|
judgment_version: string;
|
|
212
212
|
status: 'draft' | 'experimental' | 'stable' | 'deprecated' | 'staging';
|
|
213
213
|
quality_badge: 'untested' | 'tested' | 'validated' | 'expert_reviewed' | 'production_ready';
|
|
214
|
-
access: '
|
|
214
|
+
access: 'public' | 'licensed' | 'remote';
|
|
215
215
|
language?: string;
|
|
216
216
|
default_language: string;
|
|
217
217
|
languages: string[];
|
package/src/workpack-pure.js
CHANGED
|
@@ -25,7 +25,7 @@ const WORK_PACK_SCHEMA = {
|
|
|
25
25
|
version: { type: 'string', pattern: '^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.]+)?(\\+[a-zA-Z0-9.]+)?$' },
|
|
26
26
|
description: { type: 'string', maxLength: 280 },
|
|
27
27
|
status: { type: 'string', enum: ['draft', 'experimental', 'stable', 'deprecated'] },
|
|
28
|
-
access: { type: 'string', enum: ['
|
|
28
|
+
access: { type: 'string', enum: ['public', 'licensed', 'remote', 'enterprise', 'partner'], default: 'public' },
|
|
29
29
|
license: { type: 'string', default: 'Apache-2.0' },
|
|
30
30
|
kdna: {
|
|
31
31
|
type: 'object',
|
|
@@ -179,7 +179,7 @@ function inspectWorkPack(manifest, rootDir) {
|
|
|
179
179
|
version: manifest.version,
|
|
180
180
|
description: manifest.description,
|
|
181
181
|
status: manifest.status,
|
|
182
|
-
access: manifest.access || '
|
|
182
|
+
access: manifest.access || 'public',
|
|
183
183
|
license: manifest.license || 'Apache-2.0',
|
|
184
184
|
format_version: manifest.format_version,
|
|
185
185
|
kdna: {
|