@novasamatech/statement-store 0.8.11 → 0.8.12

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.
@@ -263,7 +263,7 @@ describe('session', () => {
263
263
  const { session } = makeSession({ peer: [peerRequest] });
264
264
  await delay();
265
265
  const result = await session.submitResponseMessage(requestId, 'success');
266
- expect(result.isOk()).toBe(true);
266
+ await expect(result).toBeOk();
267
267
  });
268
268
  it('treats an incoming request as already answered when our response is present (no resubmit)', async () => {
269
269
  const requestId = 'peer-request-id';
@@ -274,7 +274,7 @@ describe('session', () => {
274
274
  await delay();
275
275
  const submitsBefore = adapter.submitStatement.mock.calls.length;
276
276
  const result = await session.submitResponseMessage(requestId, 'success');
277
- expect(result.isOk()).toBe(true);
277
+ await expect(result).toBeOk();
278
278
  expect(adapter.submitStatement.mock.calls.length).toBe(submitsBefore); // no new submit
279
279
  });
280
280
  it('does not re-deliver an incoming request we already answered', async () => {
@@ -365,8 +365,7 @@ describe('session', () => {
365
365
  });
366
366
  await delay();
367
367
  const result = await responsePromise;
368
- expect(result.isOk()).toBe(true);
369
- expect(result.unwrapOr({ responseCode: 'unknown' }).responseCode).toBe('success');
368
+ await expect(result).toBeOkWith(expect.objectContaining({ responseCode: 'success' }));
370
369
  });
371
370
  it('does not resend a message that is already in flight (dedup)', async () => {
372
371
  const store = createInMemoryStatementStore();
@@ -401,8 +400,8 @@ describe('session', () => {
401
400
  isComplete: true,
402
401
  });
403
402
  await delay();
404
- expect((await w1).isOk()).toBe(true);
405
- expect((await w2).isOk()).toBe(true);
403
+ await expect(w1).toBeOk();
404
+ await expect(w2).toBeOk();
406
405
  });
407
406
  it('preserves FIFO order: a later fitting message does not overtake queued ones', async () => {
408
407
  const m1 = rawCodec.enc(new Uint8Array([1, 2, 3])); // first → in-flight batch
@@ -426,7 +425,7 @@ describe('session', () => {
426
425
  await delay();
427
426
  adapter.submitStatement.mockClear();
428
427
  const result = await session.submitRequestMessage(rawCodec, new Uint8Array([1, 2, 3, 4]));
429
- expect(result.isErr()).toBe(true);
428
+ await expect(result).toBeErr();
430
429
  expect(adapter.submitStatement).not.toHaveBeenCalled();
431
430
  });
432
431
  });
@@ -524,7 +523,7 @@ describe('session', () => {
524
523
  const { session } = makeSession({ peer: [peerRequest] });
525
524
  await delay(); // init buffers the peer request
526
525
  const result = await session.waitForRequestMessage(rawCodec, () => 'matched');
527
- expect(result._unsafeUnwrap()).toBe('matched');
526
+ await expect(result).toBeOkWith('matched');
528
527
  }, 2000);
529
528
  it('opens a single subscription on the incoming topic', () => {
530
529
  const store = createInMemoryStatementStore();
@@ -591,7 +590,7 @@ describe('session', () => {
591
590
  const { session } = makeSession();
592
591
  await delay();
593
592
  const result = await session.submitResponseMessage('wrong-id', 'success');
594
- expect(result.isErr()).toBe(true);
593
+ await expect(result).toBeErr();
595
594
  });
596
595
  it('NACKs an undecodable incoming request with decodingFailed', async () => {
597
596
  // A request (enum tag 0) whose requestId decodes but whose data vector claims more
@@ -650,7 +649,7 @@ describe('session', () => {
650
649
  expect(adapter.submitStatement).not.toHaveBeenCalled(); // no premature NACK
651
650
  // The legitimate response still goes through.
652
651
  const res = await session.submitResponseMessage(reqId, 'success');
653
- expect(res.isOk()).toBe(true);
652
+ await expect(res).toBeOk();
654
653
  const decoded = StatementData.dec(lastSubmitted(adapter).data);
655
654
  expect(decoded.tag === 'response' && decoded.value.responseCode).toBe('success');
656
655
  });
@@ -676,7 +675,7 @@ describe('session', () => {
676
675
  host.respondToRequests(RemoteMsg, () => 'success');
677
676
  await settle();
678
677
  const ack = await peer.request(RemoteMsg, requestMsg('p1'));
679
- expect(ack.isOk()).toBe(true);
678
+ await expect(ack).toBeOk();
680
679
  host.dispose();
681
680
  peer.dispose();
682
681
  });
@@ -688,7 +687,7 @@ describe('session', () => {
688
687
  host.respondToRequests(RemoteMsg, () => okAsync('decodingFailed'));
689
688
  await settle();
690
689
  const ack = await peer.request(RemoteMsg, requestMsg('p1'));
691
- expect(ack.isErr()).toBe(true);
690
+ await expect(ack).toBeErr();
692
691
  expect(ack._unsafeUnwrapErr()).toBeInstanceOf(DecodingError);
693
692
  host.dispose();
694
693
  peer.dispose();
@@ -701,7 +700,7 @@ describe('session', () => {
701
700
  host.respondToRequests(RemoteMsg, () => errAsync(new Error('handler boom')));
702
701
  await settle();
703
702
  const ack = await peer.request(RemoteMsg, requestMsg('p1'));
704
- expect(ack.isErr()).toBe(true);
703
+ await expect(ack).toBeErr();
705
704
  expect(ack._unsafeUnwrapErr()).toBeInstanceOf(UnknownError);
706
705
  host.dispose();
707
706
  peer.dispose();
@@ -731,8 +730,8 @@ describe('session', () => {
731
730
  await delay();
732
731
  const resA = await session.submitResponseMessage('A', 'success');
733
732
  const resB = await session.submitResponseMessage('B', 'success');
734
- expect(resA.isOk()).toBe(true);
735
- expect(resB.isOk()).toBe(true);
733
+ await expect(resA).toBeOk();
734
+ await expect(resB).toBeOk();
736
735
  });
737
736
  it('remains answerable after response submission retries are exhausted', async () => {
738
737
  const peerRequest = makeStatement({ tag: 'request', value: { requestId: 'rid', data: [] } });
@@ -740,11 +739,11 @@ describe('session', () => {
740
739
  await delay();
741
740
  adapter.submitStatement.mockReturnValue(errAsync(new Error('store rejected')));
742
741
  const first = await session.submitResponseMessage('rid', 'success'); // all retries fail → err + rollback
743
- expect(first.isErr()).toBe(true);
742
+ await expect(first).toBeErr();
744
743
  adapter.submitStatement.mockReturnValue(okAsync(undefined)); // store recovers
745
744
  const submitsBefore = adapter.submitStatement.mock.calls.length;
746
745
  const second = await session.submitResponseMessage('rid', 'success'); // retryable → submits and succeeds
747
- expect(second.isOk()).toBe(true);
746
+ await expect(second).toBeOk();
748
747
  expect(adapter.submitStatement.mock.calls.length).toBeGreaterThan(submitsBefore);
749
748
  }, 3000);
750
749
  it.each([
@@ -774,13 +773,13 @@ describe('session', () => {
774
773
  pendings.find(p => p.requestId === 'A').settle(err(new PriorityError(0n, 0n))); // A lands late, rejected
775
774
  const resA = await resAPromise;
776
775
  const resB = await resBPromise;
777
- expect(resB.isOk()).toBe(true);
778
- expect(resA.isOk()).toBe(true); // superseded rejection absorbed, not surfaced as an error
776
+ await expect(resB).toBeOk();
777
+ await expect(resA).toBeOk(); // superseded rejection absorbed, not surfaced as an error
779
778
  // A stays answered: re-answering it must NOT submit again (which would clobber B's response).
780
779
  const submitsBefore = adapter.submitStatement.mock.calls.length;
781
780
  const reAnswer = await session.submitResponseMessage('A', 'success');
782
781
  await delay();
783
- expect(reAnswer.isOk()).toBe(true);
782
+ await expect(reAnswer).toBeOk();
784
783
  expect(adapter.submitStatement.mock.calls.length).toBe(submitsBefore); // deduped → no resubmit
785
784
  session.dispose();
786
785
  }, 3000);
@@ -793,7 +792,7 @@ describe('session', () => {
793
792
  await delay();
794
793
  const before = adapter.submitStatement.mock.calls.length;
795
794
  const result = await session.clearOutgoingStatement();
796
- expect(result.isOk()).toBe(true);
795
+ await expect(result).toBeOk();
797
796
  expect(adapter.submitStatement.mock.calls.length).toBe(before);
798
797
  });
799
798
  it('absorbs an ExpiryTooLow on the superseding empty batch as success', async () => {
@@ -809,7 +808,7 @@ describe('session', () => {
809
808
  void session.submitRequestMessage(rawCodec, new Uint8Array([1]));
810
809
  await delay();
811
810
  const cleared = await session.clearOutgoingStatement();
812
- expect(cleared.isOk()).toBe(true); // ExpiryTooLow suppressed
811
+ await expect(cleared).toBeOk(); // ExpiryTooLow suppressed
813
812
  session.dispose();
814
813
  }, 3000);
815
814
  it('submits an empty batch on the same channel at a higher expiry and clears local state', async () => {
@@ -823,7 +822,7 @@ describe('session', () => {
823
822
  if (liveDecoded.tag === 'request')
824
823
  expect(liveDecoded.value.data.length).toBe(1);
825
824
  const result = await session.clearOutgoingStatement();
826
- expect(result.isOk()).toBe(true);
825
+ await expect(result).toBeOk();
827
826
  const clearCall = adapter.submitStatement.mock.calls.at(-1)?.[0];
828
827
  const clearDecoded = StatementData.dec(clearCall.data);
829
828
  expect(clearDecoded.tag).toBe('request');
@@ -848,7 +847,7 @@ describe('session', () => {
848
847
  void session.submitRequestMessage(rawCodec, new Uint8Array([1, 2, 3]));
849
848
  await settle();
850
849
  const result = await session.clearOutgoingStatement();
851
- expect(result.isOk()).toBe(true);
850
+ await expect(result).toBeOk();
852
851
  await settle();
853
852
  const requests = store
854
853
  .currentStatements()
@@ -862,12 +861,12 @@ describe('session', () => {
862
861
  const { session } = makeSession();
863
862
  await delay();
864
863
  const submit = await session.submitRequestMessage(rawCodec, new Uint8Array([9]));
865
- expect(submit.isOk()).toBe(true);
864
+ await expect(submit).toBeOk();
866
865
  const requestId = submit._unsafeUnwrap().requestId;
867
866
  const waiter = session.waitForResponseMessage(requestId);
868
867
  await session.clearOutgoingStatement();
869
868
  const waited = await waiter;
870
- expect(waited.isErr()).toBe(true);
869
+ await expect(waited).toBeErr();
871
870
  });
872
871
  it('clears local state and rejects waiters even when the supersede submission fails', async () => {
873
872
  const { session, adapter } = makeSession();
@@ -877,10 +876,10 @@ describe('session', () => {
877
876
  const waiter = session.waitForResponseMessage(requestId);
878
877
  adapter.submitStatement.mockReturnValueOnce(errAsync(new Error('store rejected')));
879
878
  const result = await session.clearOutgoingStatement();
880
- expect(result.isErr()).toBe(true);
879
+ await expect(result).toBeErr();
881
880
  // The pending waiter is rejected despite the failed submission.
882
881
  const waited = await waiter;
883
- expect(waited.isErr()).toBe(true);
882
+ await expect(waited).toBeErr();
884
883
  // State is cleared: the next message starts a brand-new batch (data length 1, not 2).
885
884
  adapter.submitStatement.mockReturnValue(okAsync(undefined));
886
885
  void session.submitRequestMessage(rawCodec, new Uint8Array([4]));
@@ -902,10 +901,10 @@ describe('session', () => {
902
901
  const waiter = session.waitForResponseMessage(requestId);
903
902
  const submitsBefore = adapter.submitStatement.mock.calls.length;
904
903
  const result = await session.clearOutgoingStatement();
905
- expect(result.isOk()).toBe(true);
904
+ await expect(result).toBeOk();
906
905
  // The queued waiter is rejected rather than left to be submitted after init.
907
906
  const waited = await waiter;
908
- expect(waited.isErr()).toBe(true);
907
+ await expect(waited).toBeErr();
909
908
  // No empty batch is submitted since there was no live on-chain request yet.
910
909
  expect(adapter.submitStatement.mock.calls.length).toBe(submitsBefore);
911
910
  });
@@ -1011,7 +1010,7 @@ describe('session', () => {
1011
1010
  const submit = await session.submitRequestMessage(rawCodec, new Uint8Array([1]));
1012
1011
  const requestId = submit._unsafeUnwrap().requestId;
1013
1012
  const waited = await session.waitForResponseMessage(requestId);
1014
- expect(waited.isErr()).toBe(true);
1013
+ await expect(waited).toBeErr();
1015
1014
  }, 2000);
1016
1015
  it('absorbs a superseded older submission rejected as ExpiryTooLow without surfacing an error', async () => {
1017
1016
  // Two messages batch onto one outgoing request: the first submission (requestId A) is in
@@ -1055,7 +1054,7 @@ describe('session', () => {
1055
1054
  const waiter = session.waitForRequestMessage(rawCodec, () => 'x');
1056
1055
  session.dispose();
1057
1056
  const result = await waiter;
1058
- expect(result.isErr()).toBe(true);
1057
+ await expect(result).toBeErr();
1059
1058
  }, 2000);
1060
1059
  it('cancels a pending init retry (no further queries)', async () => {
1061
1060
  const queryStatements = vi.fn(() => errAsync(new Error('store down'))); // init always fails → schedules retry
@@ -1071,7 +1070,7 @@ describe('session', () => {
1071
1070
  await delay();
1072
1071
  session.dispose();
1073
1072
  const result = await session.submitRequestMessage(rawCodec, new Uint8Array([1]));
1074
- expect(result.isErr()).toBe(true); // surfaced immediately, not a token left pending forever
1073
+ await expect(result).toBeErr(); // surfaced immediately, not a token left pending forever
1075
1074
  expect(adapter.submitStatement).not.toHaveBeenCalled();
1076
1075
  });
1077
1076
  it('rejects submitResponseMessage after dispose', async () => {
@@ -1079,7 +1078,7 @@ describe('session', () => {
1079
1078
  await delay();
1080
1079
  session.dispose();
1081
1080
  const result = await session.submitResponseMessage('any-id', 'success');
1082
- expect(result.isErr()).toBe(true);
1081
+ await expect(result).toBeErr();
1083
1082
  });
1084
1083
  it('does not re-activate when disposed while init is in flight', async () => {
1085
1084
  // dispose() lands during init's query await; init must bail before restoring state / flipping
@@ -1089,13 +1088,13 @@ describe('session', () => {
1089
1088
  const queryStatements = vi.fn(() => ResultAsync.fromSafePromise(gate));
1090
1089
  const { session, adapter } = makeSession({ queryStatements });
1091
1090
  const queued = await session.submitRequestMessage(rawCodec, new Uint8Array([1])); // queued during init
1092
- expect(queued.isOk()).toBe(true);
1091
+ await expect(queued).toBeOk();
1093
1092
  session.dispose(); // dispose mid-init
1094
1093
  resolveQueries([]); // init resumes — must bail before draining the queue / activating
1095
1094
  await settle();
1096
1095
  expect(adapter.submitStatement).not.toHaveBeenCalled(); // no resurrection-driven submit
1097
1096
  const after = await session.submitRequestMessage(rawCodec, new Uint8Array([2]));
1098
- expect(after.isErr()).toBe(true); // session stays disposed
1097
+ await expect(after).toBeErr(); // session stays disposed
1099
1098
  }, 3000);
1100
1099
  });
1101
1100
  // The in-memory adapter replicates the store's observable contract; `fidelity` pins the double's
@@ -1123,7 +1122,7 @@ describe('session', () => {
1123
1122
  const store = createInMemoryStatementStore();
1124
1123
  await store.submitStatement(makeSignedStatement(hex(0xaa), 10n, hex(0x01), new Uint8Array([1])));
1125
1124
  const higher = await store.submitStatement(makeSignedStatement(hex(0xaa), 11n, hex(0x01), new Uint8Array([2])));
1126
- expect(higher.isOk()).toBe(true);
1125
+ await expect(higher).toBeOk();
1127
1126
  expect(store.currentStatements()).toHaveLength(1);
1128
1127
  expect(store.currentStatements()[0]?.expiry).toBe(11n);
1129
1128
  });
@@ -1132,9 +1131,9 @@ describe('session', () => {
1132
1131
  await store.submitStatement(makeSignedStatement(hex(0xaa), 10n, hex(0x01), new Uint8Array([1])));
1133
1132
  const equal = await store.submitStatement(makeSignedStatement(hex(0xaa), 10n, hex(0x01), new Uint8Array([9])));
1134
1133
  const lower = await store.submitStatement(makeSignedStatement(hex(0xaa), 5n, hex(0x01), new Uint8Array([9])));
1135
- expect(equal.isErr()).toBe(true);
1134
+ await expect(equal).toBeErr();
1136
1135
  expect(equal._unsafeUnwrapErr()).toBeInstanceOf(ExpiryTooLowError);
1137
- expect(lower.isErr()).toBe(true);
1136
+ await expect(lower).toBeErr();
1138
1137
  // The original statement is untouched.
1139
1138
  expect(store.currentStatements()[0]?.data).toEqual(new Uint8Array([1]));
1140
1139
  });
@@ -1143,7 +1142,7 @@ describe('session', () => {
1143
1142
  const stmt = makeSignedStatement(hex(0xaa), 10n, hex(0x01), new Uint8Array([1]));
1144
1143
  await store.submitStatement(stmt);
1145
1144
  const again = await store.submitStatement(stmt);
1146
- expect(again.isOk()).toBe(true);
1145
+ await expect(again).toBeOk();
1147
1146
  expect(store.currentStatements()).toHaveLength(1);
1148
1147
  });
1149
1148
  it('coexists statements on different channels sharing a topic', async () => {
@@ -1184,9 +1183,9 @@ describe('session', () => {
1184
1183
  const mobileReplyAck = mobileGotRequest.andThen(req => mobile.request(RemoteMsg, { id: 'm1', kind: 'reply', respondingTo: req.id, body: 'signature' }));
1185
1184
  const hostReply = host.waitForRequestMessage(RemoteMsg, msg => msg.kind === 'reply' && msg.respondingTo === 'h1' ? msg.body : undefined);
1186
1185
  await settle();
1187
- expect((await hostAck).isOk()).toBe(true); // mobile ACKed the host request
1188
- expect((await mobileReplyAck).isOk()).toBe(true); // host ACKed the mobile reply
1189
- expect((await hostReply)._unsafeUnwrap()).toBe('signature'); // host received the reply
1186
+ await expect(hostAck).toBeOk(); // mobile ACKed the host request
1187
+ await expect(mobileReplyAck).toBeOk(); // host ACKed the mobile reply
1188
+ await expect(hostReply).toBeOkWith('signature'); // host received the reply
1190
1189
  host.dispose();
1191
1190
  mobile.dispose();
1192
1191
  });
@@ -1212,7 +1211,7 @@ describe('session', () => {
1212
1211
  mobile = makeMobile(store);
1213
1212
  mobile.respondToRequests(RemoteMsg, () => 'success');
1214
1213
  await settle();
1215
- expect((await hostAck).isOk()).toBe(true);
1214
+ await expect(hostAck).toBeOk();
1216
1215
  host.dispose();
1217
1216
  mobile.dispose();
1218
1217
  });
@@ -1233,7 +1232,7 @@ describe('session', () => {
1233
1232
  const hostAck = host.request(RemoteMsg, { id: 'h1', kind: 'request', respondingTo: '', body: 'sign this' });
1234
1233
  await settle();
1235
1234
  // The reply is delivered…
1236
- expect((await hostReply)._unsafeUnwrap()).toBe('signature');
1235
+ await expect(hostReply).toBeOkWith('signature');
1237
1236
  // …while the transport ACK is still outstanding (mobile never sent it).
1238
1237
  const ackState = await Promise.race([
1239
1238
  Promise.resolve(hostAck).then(() => 'resolved'),
@@ -32,7 +32,7 @@ describe('statementProver', () => {
32
32
  const signed = (await prover.generateMessageProof(makeStatement(new Uint8Array([1, 2, 3]))))._unsafeUnwrap();
33
33
  expect(proofSigner(signed)).toBe(toHex(deriveSr25519PublicKey(secret)));
34
34
  const verified = await prover.verifyMessageProof(signed);
35
- expect(verified._unsafeUnwrap()).toBe(true);
35
+ await expect(verified).toBeOkWith(true);
36
36
  });
37
37
  });
38
38
  describe('createSlotAccountProver (mobile slot secrets)', () => {
@@ -44,7 +44,7 @@ describe('statementProver', () => {
44
44
  const signed = (await prover.generateMessageProof(makeStatement(new Uint8Array([4, 5, 6]))))._unsafeUnwrap();
45
45
  expect(proofSigner(signed)).toBe(toHex(deriveSlotAccountPublicKey(slotSecret)));
46
46
  const verified = await prover.verifyMessageProof(signed);
47
- expect(verified._unsafeUnwrap()).toBe(true);
47
+ await expect(verified).toBeOkWith(true);
48
48
  });
49
49
  it('signs under a different public key than the scure prover would for the same secret', () => {
50
50
  // Regression guard: a slot secret pushed through the scure scheme derives the WRONG
@@ -58,14 +58,14 @@ describe('statementProver', () => {
58
58
  const signed = (await prover.generateMessageProof(makeStatement(new Uint8Array([7, 8, 9]))))._unsafeUnwrap();
59
59
  const tampered = { ...signed, data: new Uint8Array([9, 9, 9]) };
60
60
  const verified = await prover.verifyMessageProof(tampered);
61
- expect(verified._unsafeUnwrap()).toBe(false);
61
+ await expect(verified).toBeOkWith(false);
62
62
  });
63
63
  });
64
64
  describe('verifyMessageProof', () => {
65
65
  it('errors when the statement carries no proof', async () => {
66
66
  const prover = createSr25519Prover(createSr25519Secret(mnemonicToEntropy(DEV_MNEMONIC)));
67
67
  const verified = await prover.verifyMessageProof(makeStatement(new Uint8Array([1])));
68
- expect(verified.isErr()).toBe(true);
68
+ await expect(verified).toBeErr();
69
69
  });
70
70
  });
71
71
  });
@@ -15,7 +15,7 @@ describe('submitWithRetry', () => {
15
15
  let calls = 0;
16
16
  const submit = vi.fn(() => ++calls <= 6 ? errAsync(new AccountFullError(0n, 1n)) : okAsync(undefined));
17
17
  const result = await submitWithRetry(submit, { ...FAST, attempts: 3, priorityAttempts: 'unbounded' });
18
- expect(result.isOk()).toBe(true);
18
+ await expect(result).toBeOk();
19
19
  expect(calls).toBe(7);
20
20
  });
21
21
  it("priorityAttempts 'unbounded': a no-longer-live priority rejection settles as success", async () => {
@@ -26,13 +26,13 @@ describe('submitWithRetry', () => {
26
26
  priorityAttempts: 'unbounded',
27
27
  shouldRetry: () => false,
28
28
  });
29
- expect(result.isOk()).toBe(true); // lost the channel race — benign
29
+ await expect(result).toBeOk(); // lost the channel race — benign
30
30
  expect(submit).toHaveBeenCalledTimes(1);
31
31
  });
32
32
  it('priorityAttempts budgeted: priority errors consume their budget then propagate', async () => {
33
33
  const submit = vi.fn(() => errAsync(new AccountFullError(0n, 1n)));
34
34
  const result = await submitWithRetry(submit, { ...FAST, attempts: 0, priorityAttempts: 3 });
35
- expect(result.isErr()).toBe(true);
35
+ await expect(result).toBeErr();
36
36
  expect(result._unsafeUnwrapErr()).toBeInstanceOf(AccountFullError);
37
37
  expect(submit).toHaveBeenCalledTimes(4); // 1 initial + 3 retries
38
38
  });
@@ -46,7 +46,7 @@ describe('submitWithRetry', () => {
46
46
  priorityAttempts: 2,
47
47
  onPriorityError: error => seen.push(error.min),
48
48
  });
49
- expect(result.isErr()).toBe(true);
49
+ await expect(result).toBeErr();
50
50
  expect(submit).toHaveBeenCalledTimes(3); // 1 initial + 2 retries
51
51
  expect(seen).toEqual([1n, 2n, 3n]); // adopted the floor on all three, including the terminal rejection
52
52
  });
@@ -59,13 +59,13 @@ describe('submitWithRetry', () => {
59
59
  it('attempts 0: a non-priority error propagates immediately', async () => {
60
60
  const submit = vi.fn(() => errAsync(new Error('store rejected')));
61
61
  const result = await submitWithRetry(submit, { ...FAST, attempts: 0, priorityAttempts: 3 });
62
- expect(result.isErr()).toBe(true);
62
+ await expect(result).toBeErr();
63
63
  expect(submit).toHaveBeenCalledTimes(1);
64
64
  });
65
65
  it('non-priority errors consume the attempts budget then propagate', async () => {
66
66
  const submit = vi.fn(() => errAsync(new Error('store rejected')));
67
67
  const result = await submitWithRetry(submit, { ...FAST, attempts: 2, priorityAttempts: 'unbounded' });
68
- expect(result.isErr()).toBe(true);
68
+ await expect(result).toBeErr();
69
69
  expect(submit).toHaveBeenCalledTimes(3); // 1 initial + 2 retries
70
70
  });
71
71
  it('per-attempt delay schedule is honored and reported via onRetry', async () => {
@@ -78,7 +78,7 @@ describe('submitWithRetry', () => {
78
78
  delaysMs: [1, 2, 3],
79
79
  onRetry: ({ attempt, delayMs }) => seen.push({ attempt, delayMs }),
80
80
  });
81
- expect(result.isOk()).toBe(true);
81
+ await expect(result).toBeOk();
82
82
  expect(seen).toEqual([
83
83
  { attempt: 0, delayMs: 1 },
84
84
  { attempt: 1, delayMs: 2 },
@@ -87,7 +87,7 @@ describe('submitWithRetry', () => {
87
87
  it('a negative budget propagates immediately instead of looping', async () => {
88
88
  const submit = vi.fn(() => errAsync(new Error('store rejected')));
89
89
  const result = await submitWithRetry(submit, { ...FAST, attempts: -1, priorityAttempts: 3 });
90
- expect(result.isErr()).toBe(true);
90
+ await expect(result).toBeErr();
91
91
  expect(submit).toHaveBeenCalledTimes(1);
92
92
  });
93
93
  it('a shouldRetry flip during the backoff settles a priority rejection as success', async () => {
@@ -104,7 +104,7 @@ describe('submitWithRetry', () => {
104
104
  priorityAttempts: 'unbounded',
105
105
  shouldRetry: () => live,
106
106
  });
107
- expect(result.isOk()).toBe(true); // settled after the delay, no second attempt
107
+ await expect(result).toBeOk(); // settled after the delay, no second attempt
108
108
  expect(submit).toHaveBeenCalledTimes(1);
109
109
  });
110
110
  it('shouldRetry is re-checked before each retry and stops the loop', async () => {
@@ -119,7 +119,7 @@ describe('submitWithRetry', () => {
119
119
  priorityAttempts: 'unbounded',
120
120
  shouldRetry: () => live,
121
121
  });
122
- expect(result.isErr()).toBe(true); // non-priority + not live → propagate, no settle
122
+ await expect(result).toBeErr(); // non-priority + not live → propagate, no settle
123
123
  expect(submit).toHaveBeenCalledTimes(1);
124
124
  });
125
125
  });
@@ -41,7 +41,7 @@ describe('submitStatementOnce', () => {
41
41
  it('submits with the pinned-high expiry layout', async () => {
42
42
  const { adapter, submitted } = makeStore();
43
43
  const result = await submitStatementOnce(baseParams(adapter));
44
- expect(result.isOk()).toBe(true);
44
+ await expect(result).toBeOk();
45
45
  expect(submitted).toHaveLength(1);
46
46
  expect((submitted[0].expiry ?? 0n) >> 32n).toBe(0xffffffffn);
47
47
  });
@@ -51,8 +51,8 @@ describe('submitStatementOnce', () => {
51
51
  const params = baseParams(adapter);
52
52
  const first = await submitStatementOnce(params);
53
53
  const second = await submitStatementOnce(params);
54
- expect(first.isErr()).toBe(true);
55
- expect(second.isOk()).toBe(true);
54
+ await expect(first).toBeErr();
55
+ await expect(second).toBeOk();
56
56
  expect(submitted[1].expiry ?? 0n).toBeGreaterThan(chainMin); // adopted min, not wall clock
57
57
  });
58
58
  });
@@ -73,7 +73,7 @@ describe('signAndSubmitStatement', () => {
73
73
  });
74
74
  await vi.advanceTimersByTimeAsync(600); // cover the 500ms first backoff
75
75
  const result = await promise;
76
- expect(result.isOk()).toBe(true);
76
+ await expect(result).toBeOk();
77
77
  expect(submitted).toHaveLength(2);
78
78
  expect(submitted[1].expiry ?? 0n).toBeGreaterThan(chainMin);
79
79
  });
@@ -92,7 +92,7 @@ describe('signAndSubmitStatement', () => {
92
92
  });
93
93
  await vi.advanceTimersByTimeAsync(50);
94
94
  const result = await promise;
95
- expect(result.isErr()).toBe(true);
95
+ await expect(result).toBeErr();
96
96
  expect(result._unsafeUnwrapErr()).toBeInstanceOf(AccountFullError);
97
97
  expect(submitted).toHaveLength(4); // 1 initial + 3 priority retries
98
98
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@novasamatech/statement-store",
3
3
  "type": "module",
4
- "version": "0.8.11",
4
+ "version": "0.8.12",
5
5
  "description": "Statement store integration",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
@@ -25,18 +25,18 @@
25
25
  "README.md"
26
26
  ],
27
27
  "dependencies": {
28
- "@novasamatech/scale": "0.8.11",
28
+ "@novasamatech/scale": "0.8.12",
29
29
  "@novasamatech/sdk-statement": "^0.6.0",
30
- "@novasamatech/substrate-slot-sr25519-wasm": "0.8.11",
30
+ "@novasamatech/substrate-slot-sr25519-wasm": "0.8.12",
31
31
  "@polkadot-api/substrate-bindings": "^0.20.3",
32
32
  "@polkadot-api/substrate-client": "^0.7.0",
33
- "@polkadot-labs/hdkd-helpers": "^0.0.30",
33
+ "@polkadot-labs/hdkd-helpers": "^0.0.31",
34
34
  "@polkadot-labs/schnorrkel-wasm": "0.0.9",
35
35
  "@noble/hashes": "2.2.0",
36
36
  "@noble/ciphers": "2.2.0",
37
37
  "@scure/sr25519": "2.2.0",
38
38
  "polkadot-api": ">=2",
39
- "nanoid": "5.1.11",
39
+ "nanoid": "6.0.0",
40
40
  "neverthrow": "^8.2.0",
41
41
  "scale-ts": "1.6.1"
42
42
  },