@parmanasystems/core 1.71.22 → 1.71.26

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
@@ -10499,8 +10499,7 @@ import {
10499
10499
  evaluatePolicy,
10500
10500
  loadPolicy,
10501
10501
  canonicalizeForSigning,
10502
- validateSignalsStrict,
10503
- violate
10502
+ validateSignalsStrict
10504
10503
  } from "@parmanasystems/execution";
10505
10504
  import crypto from "crypto";
10506
10505
  import {
@@ -10536,20 +10535,23 @@ async function executeFromSignals(input, signer, verifier, replayStore) {
10536
10535
  signals: input.signals
10537
10536
  })
10538
10537
  ).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`,
10538
+ if (replayStore.reserve) {
10539
+ await replayStore.reserve(
10540
+ execution_fingerprint
10541
+ );
10542
+ } else {
10543
+ const alreadyExecuted = await replayStore.hasExecuted(
10544
+ execution_fingerprint
10545
+ );
10546
+ if (alreadyExecuted) {
10547
+ throw new Error(
10548
+ `[INV-013@replay] Replay detected: execution_fingerprint ${execution_fingerprint} has already been consumed`
10549
+ );
10550
+ }
10551
+ await replayStore.markExecuted(
10547
10552
  execution_fingerprint
10548
10553
  );
10549
10554
  }
10550
- await replayStore.markExecuted(
10551
- execution_fingerprint
10552
- );
10553
10555
  const runtimeManifest = getRuntimeManifest();
10554
10556
  const token = issueToken({
10555
10557
  executionId: execution_fingerprint,
@@ -10565,7 +10567,7 @@ async function executeFromSignals(input, signer, verifier, replayStore) {
10565
10567
  token
10566
10568
  )
10567
10569
  );
10568
- return executeDecision({
10570
+ const attestation = await executeDecision({
10569
10571
  token,
10570
10572
  execution_fingerprint,
10571
10573
  token_signature,
@@ -10579,16 +10581,34 @@ async function executeFromSignals(input, signer, verifier, replayStore) {
10579
10581
  supported_schemaVersions: runtimeManifest.supported_schemaVersions
10580
10582
  }
10581
10583
  });
10584
+ if (replayStore.confirm) {
10585
+ try {
10586
+ await replayStore.confirm(
10587
+ execution_fingerprint
10588
+ );
10589
+ } catch (err) {
10590
+ console.warn(
10591
+ "[PARMANA WARNING] Failed to confirm execution fingerprint after successful execution:",
10592
+ err
10593
+ );
10594
+ }
10595
+ }
10596
+ return attestation;
10582
10597
  }
10583
10598
  var RedisReplayStore = class {
10584
10599
  constructor(url) {
10585
10600
  this.client = new import_ioredis.default(url);
10586
10601
  }
10587
10602
  async hasExecuted(execution_fingerprint) {
10588
- const res = await this.client.exists(
10589
- `exec:${execution_fingerprint}`
10590
- );
10591
- return res === 1;
10603
+ const [confirmed, pending] = await Promise.all([
10604
+ this.client.exists(
10605
+ `exec:${execution_fingerprint}`
10606
+ ),
10607
+ this.client.exists(
10608
+ `exec:pending:${execution_fingerprint}`
10609
+ )
10610
+ ]);
10611
+ return confirmed === 1 || pending === 1;
10592
10612
  }
10593
10613
  async markExecuted(execution_fingerprint) {
10594
10614
  const result = await this.client.set(
@@ -10602,6 +10622,35 @@ var RedisReplayStore = class {
10602
10622
  );
10603
10623
  }
10604
10624
  }
10625
+ async reserve(execution_fingerprint) {
10626
+ const alreadyConfirmed = await this.client.exists(
10627
+ `exec:${execution_fingerprint}`
10628
+ );
10629
+ if (alreadyConfirmed === 1) {
10630
+ throw new Error(
10631
+ `[INV-013@replay] Replay detected: execution_fingerprint ${execution_fingerprint} has already been consumed`
10632
+ );
10633
+ }
10634
+ const result = await this.client.set(
10635
+ `exec:pending:${execution_fingerprint}`,
10636
+ "1",
10637
+ "NX"
10638
+ );
10639
+ if (result !== "OK") {
10640
+ throw new Error(
10641
+ `[INV-013@replay] Replay detected: execution_fingerprint ${execution_fingerprint} has already been consumed`
10642
+ );
10643
+ }
10644
+ }
10645
+ async confirm(execution_fingerprint) {
10646
+ await this.client.set(
10647
+ `exec:${execution_fingerprint}`,
10648
+ "1"
10649
+ );
10650
+ await this.client.del(
10651
+ `exec:pending:${execution_fingerprint}`
10652
+ );
10653
+ }
10605
10654
  async get(key) {
10606
10655
  return this.client.get(key);
10607
10656
  }
@@ -10618,27 +10667,60 @@ var RedisReplayStore = class {
10618
10667
  await this.client.quit();
10619
10668
  }
10620
10669
  };
10670
+ var DEFAULT_MAX_SIZE = 1e6;
10621
10671
  var MemoryReplayStore = class {
10622
- constructor() {
10623
- this.store = /* @__PURE__ */ new Set();
10672
+ constructor(options = {}) {
10673
+ this.reserved = /* @__PURE__ */ new Set();
10674
+ this.confirmed = /* @__PURE__ */ new Set();
10675
+ const {
10676
+ warnInProduction = true,
10677
+ maxSize = DEFAULT_MAX_SIZE
10678
+ } = options;
10679
+ this.maxSize = maxSize;
10680
+ if (warnInProduction && process.env["NODE_ENV"] === "production") {
10681
+ console.warn(
10682
+ "[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."
10683
+ );
10684
+ }
10624
10685
  }
10625
- async markExecuted(execution_fingerprint) {
10626
- if (this.store.has(
10627
- execution_fingerprint
10628
- )) {
10686
+ async reserve(execution_fingerprint) {
10687
+ if (this.reserved.has(execution_fingerprint) || this.confirmed.has(execution_fingerprint)) {
10629
10688
  throw new Error(
10630
10689
  `[INV-013@replay] Replay detected: execution_fingerprint ${execution_fingerprint} has already been consumed`
10631
10690
  );
10632
10691
  }
10633
- this.store.add(
10692
+ this.checkMaxSize();
10693
+ this.reserved.add(
10634
10694
  execution_fingerprint
10635
10695
  );
10636
10696
  }
10637
- async hasExecuted(execution_fingerprint) {
10638
- return this.store.has(
10697
+ async confirm(execution_fingerprint) {
10698
+ this.reserved.delete(
10699
+ execution_fingerprint
10700
+ );
10701
+ this.confirmed.add(
10702
+ execution_fingerprint
10703
+ );
10704
+ }
10705
+ async markExecuted(execution_fingerprint) {
10706
+ await this.reserve(
10707
+ execution_fingerprint
10708
+ );
10709
+ await this.confirm(
10639
10710
  execution_fingerprint
10640
10711
  );
10641
10712
  }
10713
+ async hasExecuted(execution_fingerprint) {
10714
+ return this.reserved.has(execution_fingerprint) || this.confirmed.has(execution_fingerprint);
10715
+ }
10716
+ checkMaxSize() {
10717
+ const total = this.reserved.size + this.confirmed.size;
10718
+ if (total >= this.maxSize) {
10719
+ throw new Error(
10720
+ `MemoryReplayStore has reached maximum size of ${this.maxSize} entries. Switch to RedisReplayStore for production use.`
10721
+ );
10722
+ }
10723
+ }
10642
10724
  };
10643
10725
 
10644
10726
  // src/index.ts
@@ -10652,7 +10734,7 @@ import {
10652
10734
  import {
10653
10735
  INVARIANT_REGISTRY,
10654
10736
  InvariantViolation,
10655
- violate as violate2,
10737
+ violate,
10656
10738
  hashInput
10657
10739
  } from "@parmanasystems/execution";
10658
10740
 
@@ -10889,6 +10971,6 @@ export {
10889
10971
  verifyRuntime,
10890
10972
  verifyRuntimeCompatibility,
10891
10973
  verifyRuntimeManifest,
10892
- violate2 as violate
10974
+ violate
10893
10975
  };
10894
10976
  //# sourceMappingURL=index.js.map