@aikdna/kdna-core 0.12.5 → 0.12.6

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/v1/index.js +81 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aikdna/kdna-core",
3
- "version": "0.12.5",
3
+ "version": "0.12.6",
4
4
  "description": "KDNA Core library for validating, planning, and loading local .kdna judgment assets.",
5
5
  "type": "commonjs",
6
6
  "main": "src/index.js",
package/src/v1/index.js CHANGED
@@ -1008,7 +1008,7 @@ function finalizeLoadPlan(plan) {
1008
1008
  return plan;
1009
1009
  }
1010
1010
 
1011
- function inputFingerprint(inputPath, v1) {
1011
+ function computeSourceFingerprint(inputPath, v1) {
1012
1012
  const absPath = path.resolve(inputPath);
1013
1013
  if (v1.kind === 'file') {
1014
1014
  return `sha256:${crypto.createHash('sha256').update(fs.readFileSync(absPath)).digest('hex')}`;
@@ -1027,7 +1027,20 @@ function inputFingerprint(inputPath, v1) {
1027
1027
  return `sha256:${hash.digest('hex')}`;
1028
1028
  }
1029
1029
 
1030
- function baseLoadPlan(inputPath, v1, validation) {
1030
+ function inputFingerprint(inputPath, v1, opts = {}) {
1031
+ const allowedEntitlement = new Set(['active', 'expired', 'revoked', 'offline_grace']);
1032
+ const entitlementInput = (
1033
+ opts.entitlement && allowedEntitlement.has(opts.entitlement.status)
1034
+ ) ? opts.entitlement.status : null;
1035
+
1036
+ return {
1037
+ has_password_input: opts.hasPassword === true,
1038
+ entitlement_input: entitlementInput,
1039
+ source_fingerprint: computeSourceFingerprint(inputPath, v1),
1040
+ };
1041
+ }
1042
+
1043
+ function baseLoadPlan(inputPath, v1, validation, opts = {}) {
1031
1044
  const manifest = v1.manifest;
1032
1045
  const accessInfo = normalizeAccess(manifest.access);
1033
1046
  const entitlementProfile = inferEntitlementProfile(manifest);
@@ -1049,7 +1062,7 @@ function baseLoadPlan(inputPath, v1, validation) {
1049
1062
  required_action: 'block',
1050
1063
  can_load_now: false,
1051
1064
  projection_policy: 'none',
1052
- input_fingerprint: inputFingerprint(inputPath, v1),
1065
+ input_fingerprint: inputFingerprint(inputPath, v1, opts),
1053
1066
  checks: {
1054
1067
  format_valid: validation.format_valid,
1055
1068
  schema_valid: validation.schema_valid,
@@ -1122,7 +1135,7 @@ function planLoad(inputPath, opts = {}) {
1122
1135
  }
1123
1136
 
1124
1137
  const validation = runValidate(v1);
1125
- const plan = baseLoadPlan(inputPath, v1, validation);
1138
+ const plan = baseLoadPlan(inputPath, v1, validation, opts);
1126
1139
 
1127
1140
  if (!validation.overall_valid) {
1128
1141
  plan.state = 'invalid';
@@ -1253,8 +1266,8 @@ function planLoad(inputPath, opts = {}) {
1253
1266
  }
1254
1267
 
1255
1268
  if (opts.entitlement && opts.entitlement.status === 'expired') {
1256
- plan.state = 'expired';
1257
- plan.required_action = 'sync';
1269
+ plan.state = 'expired_grace';
1270
+ plan.required_action = 'renew_entitlement';
1258
1271
  plan.can_load_now = false;
1259
1272
  plan.projection_policy = 'none';
1260
1273
  plan.issues.push(buildLoadPlanIssue(
@@ -1266,8 +1279,8 @@ function planLoad(inputPath, opts = {}) {
1266
1279
  }
1267
1280
 
1268
1281
  if (opts.entitlement && opts.entitlement.status === 'revoked') {
1269
- plan.state = 'revoked';
1270
- plan.required_action = 'block';
1282
+ plan.state = 'denied';
1283
+ plan.required_action = 'contact_issuer';
1271
1284
  plan.can_load_now = false;
1272
1285
  plan.projection_policy = 'none';
1273
1286
  plan.issues.push(buildLoadPlanIssue(
@@ -1316,6 +1329,66 @@ function planLoad(inputPath, opts = {}) {
1316
1329
  return finalizeLoadPlan(plan);
1317
1330
  }
1318
1331
 
1332
+ if (opts.entitlement && opts.entitlement.status === 'expired') {
1333
+ plan.state = 'expired_grace';
1334
+ plan.required_action = 'renew_entitlement';
1335
+ plan.can_load_now = false;
1336
+ plan.projection_policy = 'none';
1337
+ plan.issues.push(buildLoadPlanIssue(
1338
+ 'KDNA_AUTH_EXPIRED',
1339
+ 'blocking',
1340
+ 'The entitlement is expired.',
1341
+ ));
1342
+ return finalizeLoadPlan(plan);
1343
+ }
1344
+
1345
+ if (opts.entitlement && opts.entitlement.status === 'revoked') {
1346
+ plan.state = 'denied';
1347
+ plan.required_action = 'contact_issuer';
1348
+ plan.can_load_now = false;
1349
+ plan.projection_policy = 'none';
1350
+ plan.issues.push(buildLoadPlanIssue(
1351
+ 'KDNA_AUTH_REVOKED',
1352
+ 'blocking',
1353
+ 'The entitlement has been revoked.',
1354
+ ));
1355
+ return finalizeLoadPlan(plan);
1356
+ }
1357
+
1358
+ if (opts.entitlement && opts.entitlement.status === 'offline_grace') {
1359
+ plan.state = 'offline_grace';
1360
+ plan.required_action = 'sync';
1361
+ plan.can_load_now = true;
1362
+ plan.projection_policy = 'minimal';
1363
+ plan.issues.push(buildLoadPlanIssue(
1364
+ 'KDNA_AUTH_OFFLINE_GRACE_ACTIVE',
1365
+ 'warning',
1366
+ 'The entitlement can load during offline grace but must sync before grace expires.',
1367
+ ));
1368
+ return finalizeLoadPlan(plan);
1369
+ }
1370
+
1371
+ if (opts.entitlement && opts.entitlement.status === 'active') {
1372
+ plan.state = 'ready';
1373
+ plan.required_action = 'load';
1374
+ plan.can_load_now = true;
1375
+ plan.projection_policy = 'minimal';
1376
+ plan.issues.push(buildLoadPlanIssue(
1377
+ 'KDNA_AUTH_ACTIVE_DIAGNOSTIC',
1378
+ 'info',
1379
+ 'Entitlement active diagnostic signal acknowledged.',
1380
+ ));
1381
+ return finalizeLoadPlan(plan);
1382
+ }
1383
+
1384
+ if (opts.hasPassword === true && !opts.password) {
1385
+ plan.issues.push(buildLoadPlanIssue(
1386
+ 'KDNA_AUTH_PASSWORD_DIAGNOSTIC',
1387
+ 'info',
1388
+ 'hasPassword is a diagnostic credential-presence signal only; it does not verify the password.',
1389
+ ));
1390
+ }
1391
+
1319
1392
  plan.state = 'ready';
1320
1393
  plan.required_action = 'load';
1321
1394
  plan.can_load_now = true;