@parmanasystems/core 1.71.22 → 1.71.24

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/index.js CHANGED
@@ -10498,9 +10498,7 @@ import {
10498
10498
  getRuntimeManifest,
10499
10499
  evaluatePolicy,
10500
10500
  loadPolicy,
10501
- canonicalizeForSigning,
10502
- validateSignalsStrict,
10503
- violate
10501
+ canonicalizeForSigning
10504
10502
  } from "@parmanasystems/execution";
10505
10503
  import crypto from "crypto";
10506
10504
  import {
@@ -10509,17 +10507,13 @@ import {
10509
10507
  import {
10510
10508
  evaluatePolicy as evaluatePolicy2,
10511
10509
  loadPolicy as loadPolicy2,
10512
- validateSignalsStrict as validateSignalsStrict2
10510
+ validateSignalsStrict
10513
10511
  } from "@parmanasystems/execution";
10514
10512
  async function executeFromSignals(input, signer, verifier, replayStore) {
10515
10513
  const policy = loadPolicy(
10516
10514
  input.policyId,
10517
10515
  input.policyVersion
10518
10516
  );
10519
- validateSignalsStrict(
10520
- input.signals,
10521
- policy
10522
- );
10523
10517
  const decision = evaluatePolicy(
10524
10518
  policy,
10525
10519
  input.signals
@@ -10536,20 +10530,23 @@ async function executeFromSignals(input, signer, verifier, replayStore) {
10536
10530
  signals: input.signals
10537
10531
  })
10538
10532
  ).digest("hex");
10539
- const hasRun = await replayStore.hasExecuted(
10540
- execution_fingerprint
10541
- );
10542
- if (hasRun) {
10543
- violate(
10544
- "INV-013",
10545
- "replay",
10546
- `[INV-013@replay] Replay detected: execution_fingerprint ${execution_fingerprint} has already been consumed`,
10533
+ if (replayStore.reserve) {
10534
+ await replayStore.reserve(
10535
+ execution_fingerprint
10536
+ );
10537
+ } else {
10538
+ const alreadyExecuted = await replayStore.hasExecuted(
10539
+ execution_fingerprint
10540
+ );
10541
+ if (alreadyExecuted) {
10542
+ throw new Error(
10543
+ `[INV-013@replay] Replay detected: execution_fingerprint ${execution_fingerprint} has already been consumed`
10544
+ );
10545
+ }
10546
+ await replayStore.markExecuted(
10547
10547
  execution_fingerprint
10548
10548
  );
10549
10549
  }
10550
- await replayStore.markExecuted(
10551
- execution_fingerprint
10552
- );
10553
10550
  const runtimeManifest = getRuntimeManifest();
10554
10551
  const token = issueToken({
10555
10552
  executionId: execution_fingerprint,
@@ -10565,7 +10562,7 @@ async function executeFromSignals(input, signer, verifier, replayStore) {
10565
10562
  token
10566
10563
  )
10567
10564
  );
10568
- return executeDecision({
10565
+ const attestation = await executeDecision({
10569
10566
  token,
10570
10567
  execution_fingerprint,
10571
10568
  token_signature,
@@ -10579,16 +10576,34 @@ async function executeFromSignals(input, signer, verifier, replayStore) {
10579
10576
  supported_schemaVersions: runtimeManifest.supported_schemaVersions
10580
10577
  }
10581
10578
  });
10579
+ if (replayStore.confirm) {
10580
+ try {
10581
+ await replayStore.confirm(
10582
+ execution_fingerprint
10583
+ );
10584
+ } catch (err) {
10585
+ console.warn(
10586
+ "[PARMANA WARNING] Failed to confirm execution fingerprint after successful execution:",
10587
+ err
10588
+ );
10589
+ }
10590
+ }
10591
+ return attestation;
10582
10592
  }
10583
10593
  var RedisReplayStore = class {
10584
10594
  constructor(url) {
10585
10595
  this.client = new import_ioredis.default(url);
10586
10596
  }
10587
10597
  async hasExecuted(execution_fingerprint) {
10588
- const res = await this.client.exists(
10589
- `exec:${execution_fingerprint}`
10590
- );
10591
- return res === 1;
10598
+ const [confirmed, pending] = await Promise.all([
10599
+ this.client.exists(
10600
+ `exec:${execution_fingerprint}`
10601
+ ),
10602
+ this.client.exists(
10603
+ `exec:pending:${execution_fingerprint}`
10604
+ )
10605
+ ]);
10606
+ return confirmed === 1 || pending === 1;
10592
10607
  }
10593
10608
  async markExecuted(execution_fingerprint) {
10594
10609
  const result = await this.client.set(
@@ -10602,6 +10617,35 @@ var RedisReplayStore = class {
10602
10617
  );
10603
10618
  }
10604
10619
  }
10620
+ async reserve(execution_fingerprint) {
10621
+ const alreadyConfirmed = await this.client.exists(
10622
+ `exec:${execution_fingerprint}`
10623
+ );
10624
+ if (alreadyConfirmed === 1) {
10625
+ throw new Error(
10626
+ `[INV-013@replay] Replay detected: execution_fingerprint ${execution_fingerprint} has already been consumed`
10627
+ );
10628
+ }
10629
+ const result = await this.client.set(
10630
+ `exec:pending:${execution_fingerprint}`,
10631
+ "1",
10632
+ "NX"
10633
+ );
10634
+ if (result !== "OK") {
10635
+ throw new Error(
10636
+ `[INV-013@replay] Replay detected: execution_fingerprint ${execution_fingerprint} has already been consumed`
10637
+ );
10638
+ }
10639
+ }
10640
+ async confirm(execution_fingerprint) {
10641
+ await this.client.set(
10642
+ `exec:${execution_fingerprint}`,
10643
+ "1"
10644
+ );
10645
+ await this.client.del(
10646
+ `exec:pending:${execution_fingerprint}`
10647
+ );
10648
+ }
10605
10649
  async get(key) {
10606
10650
  return this.client.get(key);
10607
10651
  }
@@ -10618,27 +10662,60 @@ var RedisReplayStore = class {
10618
10662
  await this.client.quit();
10619
10663
  }
10620
10664
  };
10665
+ var DEFAULT_MAX_SIZE = 1e6;
10621
10666
  var MemoryReplayStore = class {
10622
- constructor() {
10623
- this.store = /* @__PURE__ */ new Set();
10667
+ constructor(options = {}) {
10668
+ this.reserved = /* @__PURE__ */ new Set();
10669
+ this.confirmed = /* @__PURE__ */ new Set();
10670
+ const {
10671
+ warnInProduction = true,
10672
+ maxSize = DEFAULT_MAX_SIZE
10673
+ } = options;
10674
+ this.maxSize = maxSize;
10675
+ if (warnInProduction && process.env["NODE_ENV"] === "production") {
10676
+ console.warn(
10677
+ "[PARMANA WARNING] MemoryReplayStore is not suitable for production. It loses all replay protection on process restart and does not work across multiple processes. Use RedisReplayStore in production."
10678
+ );
10679
+ }
10624
10680
  }
10625
- async markExecuted(execution_fingerprint) {
10626
- if (this.store.has(
10627
- execution_fingerprint
10628
- )) {
10681
+ async reserve(execution_fingerprint) {
10682
+ if (this.reserved.has(execution_fingerprint) || this.confirmed.has(execution_fingerprint)) {
10629
10683
  throw new Error(
10630
10684
  `[INV-013@replay] Replay detected: execution_fingerprint ${execution_fingerprint} has already been consumed`
10631
10685
  );
10632
10686
  }
10633
- this.store.add(
10687
+ this.checkMaxSize();
10688
+ this.reserved.add(
10634
10689
  execution_fingerprint
10635
10690
  );
10636
10691
  }
10637
- async hasExecuted(execution_fingerprint) {
10638
- return this.store.has(
10692
+ async confirm(execution_fingerprint) {
10693
+ this.reserved.delete(
10694
+ execution_fingerprint
10695
+ );
10696
+ this.confirmed.add(
10697
+ execution_fingerprint
10698
+ );
10699
+ }
10700
+ async markExecuted(execution_fingerprint) {
10701
+ await this.reserve(
10702
+ execution_fingerprint
10703
+ );
10704
+ await this.confirm(
10639
10705
  execution_fingerprint
10640
10706
  );
10641
10707
  }
10708
+ async hasExecuted(execution_fingerprint) {
10709
+ return this.reserved.has(execution_fingerprint) || this.confirmed.has(execution_fingerprint);
10710
+ }
10711
+ checkMaxSize() {
10712
+ const total = this.reserved.size + this.confirmed.size;
10713
+ if (total >= this.maxSize) {
10714
+ throw new Error(
10715
+ `MemoryReplayStore has reached maximum size of ${this.maxSize} entries. Switch to RedisReplayStore for production use.`
10716
+ );
10717
+ }
10718
+ }
10642
10719
  };
10643
10720
 
10644
10721
  // src/index.ts
@@ -10652,7 +10729,7 @@ import {
10652
10729
  import {
10653
10730
  INVARIANT_REGISTRY,
10654
10731
  InvariantViolation,
10655
- violate as violate2,
10732
+ violate,
10656
10733
  hashInput
10657
10734
  } from "@parmanasystems/execution";
10658
10735
 
@@ -10889,6 +10966,6 @@ export {
10889
10966
  verifyRuntime,
10890
10967
  verifyRuntimeCompatibility,
10891
10968
  verifyRuntimeManifest,
10892
- violate2 as violate
10969
+ violate
10893
10970
  };
10894
10971
  //# sourceMappingURL=index.js.map