@siduri-x/core 2.0.0 → 2.0.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/dist/action-policy.d.ts +28 -1
- package/dist/action-policy.js +167 -7
- package/dist/action-policy.test.js +104 -0
- package/dist/adversarial.test.js +4 -2
- package/dist/capability.d.ts +11 -2
- package/dist/capability.js +8 -1
- package/dist/capability.test.js +43 -1
- package/dist/index.d.ts +9 -7
- package/dist/runtime.d.ts +6 -5
- package/dist/runtime.js +19 -8
- package/dist/schema-validator.test.js +2 -2
- package/dist/siduri-db.d.ts +27 -8
- package/dist/siduri-db.js +260 -17
- package/dist/siduri-db.test.js +283 -0
- package/dist/sqlite-action-store.d.ts +3 -2
- package/dist/sqlite-action-store.js +27 -4
- package/dist/sqlite-action-store.test.js +1 -0
- package/package.json +6 -6
package/dist/siduri-db.test.js
CHANGED
|
@@ -72,6 +72,15 @@ describe('SiduriDatabase', () => {
|
|
|
72
72
|
memDb.close();
|
|
73
73
|
}).not.toThrow();
|
|
74
74
|
});
|
|
75
|
+
it('initializes schema and WAL mode within the startup latency budget (<100ms in CI, typical <20ms locally)', () => {
|
|
76
|
+
const start = performance.now();
|
|
77
|
+
const benchDb = new siduri_db_1.SiduriDatabase({ dbPath });
|
|
78
|
+
const duration = performance.now() - start;
|
|
79
|
+
benchDb.close();
|
|
80
|
+
// In bare-metal local development, SQLite cold init is ~2-5ms.
|
|
81
|
+
// Under virtualized CI runners with concurrent Turbo tasks, allow a safe 100ms budget.
|
|
82
|
+
expect(duration).toBeLessThan(100);
|
|
83
|
+
});
|
|
75
84
|
it('stores and retrieves companion identity', () => {
|
|
76
85
|
db = new siduri_db_1.SiduriDatabase({ dbPath });
|
|
77
86
|
const identity = {
|
|
@@ -465,6 +474,91 @@ describe('SiduriDatabase', () => {
|
|
|
465
474
|
// More occurrences of "dark" → better BM25 rank (lower rank value = better match)
|
|
466
475
|
expect(results[0].id).toBe(c1.id);
|
|
467
476
|
});
|
|
477
|
+
it('excludes pending and rejected claims from searchClaims in SiduriDatabase', () => {
|
|
478
|
+
db = new siduri_db_1.SiduriDatabase({ dbPath });
|
|
479
|
+
const pending = db.proposeClaim({
|
|
480
|
+
id: crypto.randomUUID(),
|
|
481
|
+
companionId: 'siduri-test',
|
|
482
|
+
subject: 'SecretProject',
|
|
483
|
+
predicate: 'status',
|
|
484
|
+
value: 'unapproved draft specification',
|
|
485
|
+
confidence: 0.9,
|
|
486
|
+
assertedAt: new Date().toISOString(),
|
|
487
|
+
});
|
|
488
|
+
// Must not match while pending
|
|
489
|
+
let results = db.searchClaims('siduri-test', 'unapproved');
|
|
490
|
+
expect(results.some((r) => r.id === pending.id)).toBe(false);
|
|
491
|
+
// Approve: now it matches
|
|
492
|
+
db.approveClaim(pending.id, 'siduri-test');
|
|
493
|
+
results = db.searchClaims('siduri-test', 'unapproved');
|
|
494
|
+
expect(results.some((r) => r.id === pending.id)).toBe(true);
|
|
495
|
+
// Revoke: must no longer match
|
|
496
|
+
db.revokeClaim(pending.id, 'siduri-test');
|
|
497
|
+
results = db.searchClaims('siduri-test', 'unapproved');
|
|
498
|
+
expect(results.some((r) => r.id === pending.id)).toBe(false);
|
|
499
|
+
// Explicitly rejected claims must also not match
|
|
500
|
+
const rejected = db.proposeClaim({
|
|
501
|
+
id: crypto.randomUUID(),
|
|
502
|
+
companionId: 'siduri-test',
|
|
503
|
+
subject: 'RejectedFact',
|
|
504
|
+
predicate: 'status',
|
|
505
|
+
value: 'unapproved rejection draft',
|
|
506
|
+
confidence: 0.1,
|
|
507
|
+
});
|
|
508
|
+
db.rejectClaim(rejected.id, 'siduri-test');
|
|
509
|
+
results = db.searchClaims('siduri-test', 'rejection');
|
|
510
|
+
expect(results.some((r) => r.id === rejected.id)).toBe(false);
|
|
511
|
+
});
|
|
512
|
+
it('bounds approveClaim to specific companionId when provided', () => {
|
|
513
|
+
db = new siduri_db_1.SiduriDatabase({ dbPath });
|
|
514
|
+
const claim = db.proposeClaim({
|
|
515
|
+
id: crypto.randomUUID(),
|
|
516
|
+
companionId: 'companion-target',
|
|
517
|
+
subject: 'ProtectedFact',
|
|
518
|
+
predicate: 'belongsTo',
|
|
519
|
+
value: 'Target',
|
|
520
|
+
confidence: 1.0,
|
|
521
|
+
assertedAt: new Date().toISOString(),
|
|
522
|
+
});
|
|
523
|
+
// Attempting to approve for a different companion must not affect it
|
|
524
|
+
db.approveClaim(claim.id, 'companion-intruder');
|
|
525
|
+
expect(db.getApprovedClaims('companion-target')).toHaveLength(0);
|
|
526
|
+
// Approving with the correct companionId succeeds
|
|
527
|
+
db.approveClaim(claim.id, 'companion-target');
|
|
528
|
+
expect(db.getApprovedClaims('companion-target')).toHaveLength(1);
|
|
529
|
+
});
|
|
530
|
+
it('resets memory for the specified companion only', () => {
|
|
531
|
+
db = new siduri_db_1.SiduriDatabase({ dbPath });
|
|
532
|
+
const c1 = db.proposeClaim({
|
|
533
|
+
id: crypto.randomUUID(),
|
|
534
|
+
companionId: 'comp-1',
|
|
535
|
+
subject: 'Fact1',
|
|
536
|
+
predicate: 'is',
|
|
537
|
+
value: 'One',
|
|
538
|
+
confidence: 1.0,
|
|
539
|
+
});
|
|
540
|
+
const c2 = db.proposeClaim({
|
|
541
|
+
id: crypto.randomUUID(),
|
|
542
|
+
companionId: 'comp-2',
|
|
543
|
+
subject: 'Fact2',
|
|
544
|
+
predicate: 'is',
|
|
545
|
+
value: 'Two',
|
|
546
|
+
confidence: 1.0,
|
|
547
|
+
});
|
|
548
|
+
db.approveClaim(c1.id, 'comp-1');
|
|
549
|
+
db.approveClaim(c2.id, 'comp-2');
|
|
550
|
+
db.recordEvent({
|
|
551
|
+
id: crypto.randomUUID(),
|
|
552
|
+
companionId: 'comp-1',
|
|
553
|
+
sourceType: 'chat_turn',
|
|
554
|
+
occurredAt: new Date().toISOString(),
|
|
555
|
+
payload: { text: 'Hello' },
|
|
556
|
+
});
|
|
557
|
+
db.resetMemory('comp-1');
|
|
558
|
+
expect(db.getApprovedClaims('comp-1')).toHaveLength(0);
|
|
559
|
+
expect(db.getRecentEvents('comp-1')).toHaveLength(0);
|
|
560
|
+
expect(db.getApprovedClaims('comp-2')).toHaveLength(1);
|
|
561
|
+
});
|
|
468
562
|
});
|
|
469
563
|
// ==========================================
|
|
470
564
|
// Cross-Domain & Persistence Tests
|
|
@@ -576,5 +670,194 @@ describe('SiduriDatabase', () => {
|
|
|
576
670
|
expect(db.searchClaims(cId, 'anything')).toHaveLength(0);
|
|
577
671
|
expect(db.getApprovedClaims(cId)).toHaveLength(0);
|
|
578
672
|
});
|
|
673
|
+
it('enforces directive state transitions (pending -> active -> disabled/rejected/revoked)', () => {
|
|
674
|
+
db = new siduri_db_1.SiduriDatabase({ dbPath });
|
|
675
|
+
const cId = 'directive-state-test';
|
|
676
|
+
const dId = 'dir-lifecycle-1';
|
|
677
|
+
// 1. Commit directive in PENDING state
|
|
678
|
+
db.commitDirective({
|
|
679
|
+
id: dId,
|
|
680
|
+
companionId: cId,
|
|
681
|
+
priority: 60,
|
|
682
|
+
directive: 'Always verify claims',
|
|
683
|
+
status: 'PENDING',
|
|
684
|
+
category: 'behavioral',
|
|
685
|
+
});
|
|
686
|
+
// Pending directives must not be returned by getActiveDirectives
|
|
687
|
+
expect(db.getActiveDirectives(cId)).toHaveLength(0);
|
|
688
|
+
// 2. Approve directive
|
|
689
|
+
db.approveDirective(dId);
|
|
690
|
+
const active = db.getActiveDirectives(cId);
|
|
691
|
+
expect(active).toHaveLength(1);
|
|
692
|
+
expect(active[0].id).toBe(dId);
|
|
693
|
+
expect(active[0].status).toBe('ACTIVE');
|
|
694
|
+
// 3. Revoke directive
|
|
695
|
+
db.revokeDirective(dId);
|
|
696
|
+
expect(db.getActiveDirectives(cId)).toHaveLength(0);
|
|
697
|
+
// 4. Reject directive
|
|
698
|
+
const d2Id = 'dir-lifecycle-2';
|
|
699
|
+
db.commitDirective({
|
|
700
|
+
id: d2Id,
|
|
701
|
+
companionId: cId,
|
|
702
|
+
priority: 50,
|
|
703
|
+
directive: 'Unsafe rule',
|
|
704
|
+
status: 'PENDING',
|
|
705
|
+
category: 'behavioral',
|
|
706
|
+
});
|
|
707
|
+
db.rejectDirective(d2Id);
|
|
708
|
+
expect(db.getActiveDirectives(cId)).toHaveLength(0);
|
|
709
|
+
});
|
|
710
|
+
it('rejects invalid directive state transitions (throws when approving non-PENDING directive)', () => {
|
|
711
|
+
db = new siduri_db_1.SiduriDatabase({ dbPath });
|
|
712
|
+
const cId = 'directive-invalid-transition-test';
|
|
713
|
+
// 1. Commit directive in REJECTED state
|
|
714
|
+
db.commitDirective({
|
|
715
|
+
id: 'dir-rejected-1',
|
|
716
|
+
companionId: cId,
|
|
717
|
+
priority: 50,
|
|
718
|
+
directive: 'Rejected directive',
|
|
719
|
+
status: 'REJECTED',
|
|
720
|
+
category: 'behavioral',
|
|
721
|
+
});
|
|
722
|
+
expect(() => db.approveDirective('dir-rejected-1')).toThrow(/invalid transition from status 'REJECTED' to 'ACTIVE'/);
|
|
723
|
+
// 2. Commit directive in ACTIVE state
|
|
724
|
+
db.commitDirective({
|
|
725
|
+
id: 'dir-active-1',
|
|
726
|
+
companionId: cId,
|
|
727
|
+
priority: 50,
|
|
728
|
+
directive: 'Already active directive',
|
|
729
|
+
status: 'ACTIVE',
|
|
730
|
+
category: 'behavioral',
|
|
731
|
+
});
|
|
732
|
+
expect(() => db.approveDirective('dir-active-1')).toThrow(/invalid transition from status 'ACTIVE' to 'ACTIVE'/);
|
|
733
|
+
// 3. Rejecting an already ACTIVE directive throws
|
|
734
|
+
expect(() => db.rejectDirective('dir-active-1')).toThrow(/invalid transition from status 'ACTIVE' to 'REJECTED'/);
|
|
735
|
+
});
|
|
736
|
+
it('automatically marks prior directive as SUPERSEDED when approving superseding directive', () => {
|
|
737
|
+
db = new siduri_db_1.SiduriDatabase({ dbPath });
|
|
738
|
+
const cId = 'directive-supersede-test';
|
|
739
|
+
// 1. Initial directive active
|
|
740
|
+
db.commitDirective({
|
|
741
|
+
id: 'dir-original-1',
|
|
742
|
+
companionId: cId,
|
|
743
|
+
priority: 50,
|
|
744
|
+
directive: 'Original rule',
|
|
745
|
+
status: 'ACTIVE',
|
|
746
|
+
category: 'behavioral',
|
|
747
|
+
});
|
|
748
|
+
expect(db.getActiveDirectives(cId)).toHaveLength(1);
|
|
749
|
+
// 2. Propose a superseding directive
|
|
750
|
+
db.commitDirective({
|
|
751
|
+
id: 'dir-replacement-1',
|
|
752
|
+
companionId: cId,
|
|
753
|
+
priority: 55,
|
|
754
|
+
directive: 'Updated replacement rule',
|
|
755
|
+
status: 'PENDING',
|
|
756
|
+
category: 'behavioral',
|
|
757
|
+
supersedesId: 'dir-original-1',
|
|
758
|
+
});
|
|
759
|
+
// Original is still active, replacement is pending
|
|
760
|
+
expect(db.getActiveDirectives(cId)).toHaveLength(1);
|
|
761
|
+
expect(db.getActiveDirectives(cId)[0].id).toBe('dir-original-1');
|
|
762
|
+
// 3. Approve replacement directive
|
|
763
|
+
db.approveDirective('dir-replacement-1', cId);
|
|
764
|
+
const active = db.getActiveDirectives(cId);
|
|
765
|
+
expect(active).toHaveLength(1);
|
|
766
|
+
expect(active[0].id).toBe('dir-replacement-1');
|
|
767
|
+
const original = db.getDirective('dir-original-1', cId);
|
|
768
|
+
expect(original?.status).toBe('SUPERSEDED');
|
|
769
|
+
});
|
|
770
|
+
it('enforces companion isolation on directive approval', () => {
|
|
771
|
+
db = new siduri_db_1.SiduriDatabase({ dbPath });
|
|
772
|
+
const cIdA = 'companion-alpha';
|
|
773
|
+
const cIdB = 'companion-beta';
|
|
774
|
+
db.commitDirective({
|
|
775
|
+
id: 'dir-beta-1',
|
|
776
|
+
companionId: cIdB,
|
|
777
|
+
priority: 50,
|
|
778
|
+
directive: 'Beta private rule',
|
|
779
|
+
status: 'PENDING',
|
|
780
|
+
category: 'behavioral',
|
|
781
|
+
});
|
|
782
|
+
// Alpha attempts to approve Beta's directive scoped to Alpha
|
|
783
|
+
db.approveDirective('dir-beta-1', cIdA);
|
|
784
|
+
// Beta's directive must remain PENDING and unapproved
|
|
785
|
+
const betaDirective = db.getDirective('dir-beta-1', cIdB);
|
|
786
|
+
expect(betaDirective?.status).toBe('PENDING');
|
|
787
|
+
expect(db.getActiveDirectives(cIdB)).toHaveLength(0);
|
|
788
|
+
// Beta approves its own directive successfully
|
|
789
|
+
db.approveDirective('dir-beta-1', cIdB);
|
|
790
|
+
expect(db.getActiveDirectives(cIdB)).toHaveLength(1);
|
|
791
|
+
});
|
|
792
|
+
it('enforces claim state transitions (pending -> approved -> revoked/expired/session_only)', () => {
|
|
793
|
+
db = new siduri_db_1.SiduriDatabase({ dbPath });
|
|
794
|
+
const cId = 'claim-state-test';
|
|
795
|
+
const claim = db.proposeClaim({
|
|
796
|
+
id: 'claim-1',
|
|
797
|
+
companionId: cId,
|
|
798
|
+
subject: 'user',
|
|
799
|
+
predicate: 'likes',
|
|
800
|
+
value: 'matcha',
|
|
801
|
+
});
|
|
802
|
+
expect(claim.status).toBe('PENDING');
|
|
803
|
+
expect(db.getApprovedClaims(cId)).toHaveLength(0);
|
|
804
|
+
// Approve
|
|
805
|
+
db.approveClaim('claim-1');
|
|
806
|
+
expect(db.getApprovedClaims(cId)).toHaveLength(1);
|
|
807
|
+
// Revoke
|
|
808
|
+
db.revokeClaim('claim-1');
|
|
809
|
+
expect(db.getApprovedClaims(cId)).toHaveLength(0);
|
|
810
|
+
// Session only
|
|
811
|
+
const claim2 = db.proposeClaim({
|
|
812
|
+
id: 'claim-2',
|
|
813
|
+
companionId: cId,
|
|
814
|
+
subject: 'session',
|
|
815
|
+
predicate: 'topic',
|
|
816
|
+
value: 'investigation',
|
|
817
|
+
});
|
|
818
|
+
db.markClaimSessionOnly('claim-2');
|
|
819
|
+
expect(db.getApprovedClaims(cId)).toHaveLength(0);
|
|
820
|
+
// Expire
|
|
821
|
+
db.expireClaim('claim-2');
|
|
822
|
+
expect(db.getApprovedClaims(cId)).toHaveLength(0);
|
|
823
|
+
});
|
|
824
|
+
it('strictly rejects illegal claim state transitions in approveClaim', () => {
|
|
825
|
+
db = new siduri_db_1.SiduriDatabase({ dbPath });
|
|
826
|
+
const cId = 'claim-transition-test';
|
|
827
|
+
// 1. Propose and reject claim
|
|
828
|
+
const rejectedClaim = db.proposeClaim({
|
|
829
|
+
id: 'claim-rejected',
|
|
830
|
+
companionId: cId,
|
|
831
|
+
subject: 'fact',
|
|
832
|
+
predicate: 'is',
|
|
833
|
+
value: 'false',
|
|
834
|
+
});
|
|
835
|
+
db.rejectClaim(rejectedClaim.id);
|
|
836
|
+
// Attempting to approve a REJECTED claim must throw
|
|
837
|
+
expect(() => db.approveClaim(rejectedClaim.id)).toThrow(/invalid transition from status 'REJECTED' to 'APPROVED'/);
|
|
838
|
+
// 2. Propose and approve claim, then revoke
|
|
839
|
+
const revokedClaim = db.proposeClaim({
|
|
840
|
+
id: 'claim-revoked',
|
|
841
|
+
companionId: cId,
|
|
842
|
+
subject: 'fact',
|
|
843
|
+
predicate: 'is',
|
|
844
|
+
value: 'outdated',
|
|
845
|
+
});
|
|
846
|
+
db.approveClaim(revokedClaim.id);
|
|
847
|
+
db.revokeClaim(revokedClaim.id);
|
|
848
|
+
// Attempting to approve a REVOKED claim must throw
|
|
849
|
+
expect(() => db.approveClaim(revokedClaim.id)).toThrow(/invalid transition from status 'REVOKED' to 'APPROVED'/);
|
|
850
|
+
// 3. Propose and expire claim
|
|
851
|
+
const expiredClaim = db.proposeClaim({
|
|
852
|
+
id: 'claim-expired',
|
|
853
|
+
companionId: cId,
|
|
854
|
+
subject: 'fact',
|
|
855
|
+
predicate: 'is',
|
|
856
|
+
value: 'temporary',
|
|
857
|
+
});
|
|
858
|
+
db.expireClaim(expiredClaim.id);
|
|
859
|
+
// Attempting to approve an EXPIRED claim must throw
|
|
860
|
+
expect(() => db.approveClaim(expiredClaim.id)).toThrow(/invalid transition from status 'EXPIRED' to 'APPROVED'/);
|
|
861
|
+
});
|
|
579
862
|
});
|
|
580
863
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ActionAuditEvent } from './action';
|
|
2
|
-
import { ActionStore, PersistentExecutionRecord } from './capability';
|
|
2
|
+
import { ActionStore, PersistentExecutionRecord, ActionApprovalRecord } from './capability';
|
|
3
3
|
export interface SqliteActionStoreOptions {
|
|
4
4
|
dbPath?: string;
|
|
5
5
|
}
|
|
@@ -12,8 +12,9 @@ export declare class SqliteActionStore implements ActionStore {
|
|
|
12
12
|
reserveExecution(record: PersistentExecutionRecord): Promise<boolean>;
|
|
13
13
|
updateExecution(record: PersistentExecutionRecord): Promise<void>;
|
|
14
14
|
getExecution(executionId: string): Promise<PersistentExecutionRecord | undefined>;
|
|
15
|
-
saveApproval(executionId: string, approverActorId: string, reason?: string): Promise<void>;
|
|
15
|
+
saveApproval(executionId: string, approverActorId: string, reason?: string, approverRole?: string): Promise<void>;
|
|
16
16
|
isActionApproved(executionId: string): Promise<boolean>;
|
|
17
|
+
getApproval(executionId: string): Promise<ActionApprovalRecord | undefined>;
|
|
17
18
|
appendAudit(event: ActionAuditEvent): Promise<void>;
|
|
18
19
|
getAuditLog(executionId?: string): Promise<ActionAuditEvent[]>;
|
|
19
20
|
close(): void;
|
|
@@ -36,6 +36,7 @@ class SqliteActionStore {
|
|
|
36
36
|
execution_id TEXT PRIMARY KEY,
|
|
37
37
|
approver_actor_id TEXT NOT NULL,
|
|
38
38
|
reason TEXT,
|
|
39
|
+
approver_role TEXT,
|
|
39
40
|
approved_at TEXT NOT NULL
|
|
40
41
|
);
|
|
41
42
|
|
|
@@ -62,6 +63,12 @@ class SqliteActionStore {
|
|
|
62
63
|
timestamp TEXT NOT NULL
|
|
63
64
|
);
|
|
64
65
|
`);
|
|
66
|
+
try {
|
|
67
|
+
this.db.exec('ALTER TABLE action_approvals ADD COLUMN approver_role TEXT;');
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// Column already exists or table freshly created
|
|
71
|
+
}
|
|
65
72
|
}
|
|
66
73
|
initLastAuditHash() {
|
|
67
74
|
const row = this.db.prepare('SELECT event_hash FROM action_audit_log ORDER BY id DESC LIMIT 1').get();
|
|
@@ -127,22 +134,37 @@ class SqliteActionStore {
|
|
|
127
134
|
updatedAt: row.updated_at,
|
|
128
135
|
};
|
|
129
136
|
}
|
|
130
|
-
async saveApproval(executionId, approverActorId, reason) {
|
|
137
|
+
async saveApproval(executionId, approverActorId, reason, approverRole) {
|
|
131
138
|
const stmt = this.db.prepare(`
|
|
132
|
-
INSERT INTO action_approvals (execution_id, approver_actor_id, reason, approved_at)
|
|
133
|
-
VALUES (?, ?, ?, ?)
|
|
139
|
+
INSERT INTO action_approvals (execution_id, approver_actor_id, reason, approver_role, approved_at)
|
|
140
|
+
VALUES (?, ?, ?, ?, ?)
|
|
134
141
|
ON CONFLICT(execution_id) DO UPDATE SET
|
|
135
142
|
approver_actor_id = excluded.approver_actor_id,
|
|
136
143
|
reason = excluded.reason,
|
|
144
|
+
approver_role = excluded.approver_role,
|
|
137
145
|
approved_at = excluded.approved_at
|
|
138
146
|
`);
|
|
139
|
-
stmt.run(executionId, approverActorId, reason ?? null, new Date().toISOString());
|
|
147
|
+
stmt.run(executionId, approverActorId, reason ?? null, approverRole ?? null, new Date().toISOString());
|
|
140
148
|
}
|
|
141
149
|
async isActionApproved(executionId) {
|
|
142
150
|
const stmt = this.db.prepare('SELECT 1 FROM action_approvals WHERE execution_id = ?');
|
|
143
151
|
const row = stmt.get(executionId);
|
|
144
152
|
return !!row;
|
|
145
153
|
}
|
|
154
|
+
async getApproval(executionId) {
|
|
155
|
+
const stmt = this.db.prepare('SELECT * FROM action_approvals WHERE execution_id = ?');
|
|
156
|
+
const row = stmt.get(executionId);
|
|
157
|
+
if (!row) {
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
executionId: row.execution_id,
|
|
162
|
+
approverActorId: row.approver_actor_id,
|
|
163
|
+
reason: row.reason ?? undefined,
|
|
164
|
+
approverRole: row.approver_role ?? undefined,
|
|
165
|
+
approvedAt: row.approved_at,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
146
168
|
async appendAudit(event) {
|
|
147
169
|
const prevHash = this.lastAuditHash;
|
|
148
170
|
const eventPayload = {
|
|
@@ -164,6 +186,7 @@ class SqliteActionStore {
|
|
|
164
186
|
decisionCode: event.decision.decisionCode,
|
|
165
187
|
} : null,
|
|
166
188
|
parametersHash: event.parametersHash || null,
|
|
189
|
+
resultHash: event.resultHash || null,
|
|
167
190
|
error: event.error || null,
|
|
168
191
|
timestamp: event.timestamp,
|
|
169
192
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@siduri-x/core",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Core runtime types, evidence protocol, action dispatcher, capability validation, and SiduriRuntime protocol",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"LICENSE"
|
|
18
18
|
],
|
|
19
19
|
"engines": {
|
|
20
|
-
"node": ">=
|
|
20
|
+
"node": ">=22.16.0"
|
|
21
21
|
},
|
|
22
22
|
"main": "dist/index.js",
|
|
23
23
|
"types": "dist/index.d.ts",
|
|
@@ -29,11 +29,11 @@
|
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@types/jest": "^
|
|
33
|
-
"@types/node": "^26.
|
|
34
|
-
"jest": "^
|
|
32
|
+
"@types/jest": "^30.0.0",
|
|
33
|
+
"@types/node": "^26.5.1",
|
|
34
|
+
"jest": "^30.5.1",
|
|
35
35
|
"ts-jest": "^29.4.12",
|
|
36
|
-
"typescript": "^5.
|
|
36
|
+
"typescript": "^5.9.3"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
39
|
"build": "tsc",
|