@novasamatech/host-substrate-chain-connection 0.7.6 → 0.7.7
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/connectionPool.js
CHANGED
|
@@ -106,15 +106,31 @@ export const createChainConnection = ({ resolve, clientOptions, createProvider,
|
|
|
106
106
|
},
|
|
107
107
|
getProvider(chain) {
|
|
108
108
|
return getSyncProvider(onResult => {
|
|
109
|
+
let teardownCalled = false;
|
|
110
|
+
let pendingUnlock = null;
|
|
111
|
+
// Idempotent: subsequent calls (e.g. teardown after disconnect) are no-ops.
|
|
112
|
+
const releaseUnlock = () => {
|
|
113
|
+
const unlock = pendingUnlock;
|
|
114
|
+
pendingUnlock = null;
|
|
115
|
+
unlock?.();
|
|
116
|
+
};
|
|
109
117
|
rawAcquire(chain)
|
|
110
118
|
.then(({ pooled, unlock }) => {
|
|
111
|
-
|
|
119
|
+
if (teardownCalled) {
|
|
120
|
+
unlock();
|
|
121
|
+
onResult(null);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
pendingUnlock = unlock;
|
|
125
|
+
onResult((onMessage, _onHalt) => pooled.provider.branch(releaseUnlock)(onMessage));
|
|
112
126
|
})
|
|
113
127
|
.catch(() => {
|
|
114
128
|
onResult(null);
|
|
115
129
|
});
|
|
130
|
+
// Covers teardown without disconnect, and teardown before acquire resolves.
|
|
116
131
|
return () => {
|
|
117
|
-
|
|
132
|
+
teardownCalled = true;
|
|
133
|
+
releaseUnlock();
|
|
118
134
|
};
|
|
119
135
|
});
|
|
120
136
|
},
|
package/dist/metadataCache.js
CHANGED
|
@@ -39,7 +39,10 @@ export const createMetadataCache = (options) => {
|
|
|
39
39
|
setMetadata(key, metadata) {
|
|
40
40
|
const k = cacheKey(chainId, key);
|
|
41
41
|
memory.set(k, metadata);
|
|
42
|
-
|
|
42
|
+
// setMetadata is fire-and-forget by contract; log persist failures.
|
|
43
|
+
storage?.write(k, bytesToBase64(metadata)).orTee(error => {
|
|
44
|
+
console.error(`[metadataCache] failed to persist metadata for ${k}:`, error);
|
|
45
|
+
});
|
|
43
46
|
},
|
|
44
47
|
};
|
|
45
48
|
},
|
|
@@ -3,8 +3,8 @@ import { describe, expect, it, vi } from 'vitest';
|
|
|
3
3
|
import { createMetadataCache } from './metadataCache.js';
|
|
4
4
|
const createMockStorage = () => ({
|
|
5
5
|
read: vi.fn(),
|
|
6
|
-
write: vi.fn(),
|
|
7
|
-
clear: vi.fn(),
|
|
6
|
+
write: vi.fn(() => okAsync(undefined)),
|
|
7
|
+
clear: vi.fn(() => okAsync(undefined)),
|
|
8
8
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
9
9
|
subscribe: vi.fn(() => () => { }),
|
|
10
10
|
});
|
|
@@ -69,6 +69,15 @@ export const withSubscriptionReplay = (provider, onReconnect) => onMessage => {
|
|
|
69
69
|
onMessage(message);
|
|
70
70
|
});
|
|
71
71
|
const unsubReconnect = onReconnect(() => {
|
|
72
|
+
// Replay unconfirmed subscribes first: their `reconnectFor === null`, so
|
|
73
|
+
// they're disjoint from the entries inserted by the active-replay loop
|
|
74
|
+
// below (which all carry a non-null `reconnectFor`).
|
|
75
|
+
for (const [, pending] of pendingSubscriptions) {
|
|
76
|
+
if (pending.reconnectFor === null)
|
|
77
|
+
conn.send(pending.payload);
|
|
78
|
+
}
|
|
79
|
+
// Replay confirmed subscriptions: the server returns a fresh subId, which
|
|
80
|
+
// we map back to the consumer's stable subId.
|
|
72
81
|
for (const [consumerSubId, sub] of activeSubscriptions) {
|
|
73
82
|
pendingSubscriptions.set(sub.id, { payload: sub.payload, reconnectFor: consumerSubId });
|
|
74
83
|
conn.send(sub.payload);
|
|
@@ -61,15 +61,16 @@ describe('withSubscriptionReplay', () => {
|
|
|
61
61
|
control.triggerReconnect();
|
|
62
62
|
expect(mock.send).not.toHaveBeenCalled();
|
|
63
63
|
});
|
|
64
|
-
it('
|
|
64
|
+
it('replays pending subscriptions (no server response yet) on reconnect', () => {
|
|
65
65
|
const mock = createMockProvider();
|
|
66
66
|
const control = createReconnectControl();
|
|
67
67
|
const conn = withSubscriptionReplay(mock.provider, control.onReconnect)(vi.fn());
|
|
68
|
-
|
|
68
|
+
const subscribeMsg = req(1, 'statement_subscribeStatement');
|
|
69
|
+
conn.send(subscribeMsg);
|
|
69
70
|
// intentionally no simulateMessage — subscription not confirmed by server
|
|
70
71
|
mock.send.mockClear();
|
|
71
72
|
control.triggerReconnect();
|
|
72
|
-
expect(mock.send).
|
|
73
|
+
expect(mock.send).toHaveBeenCalledWith(subscribeMsg);
|
|
73
74
|
});
|
|
74
75
|
it('replays active subscriptions on reconnect', () => {
|
|
75
76
|
const mock = createMockProvider();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@novasamatech/host-substrate-chain-connection",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.7",
|
|
5
5
|
"description": "Chain connection pool with ref counting and provider branching for Polkadot API",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"repository": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"README.md"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@novasamatech/storage-adapter": "0.7.
|
|
28
|
+
"@novasamatech/storage-adapter": "0.7.7",
|
|
29
29
|
"@polkadot-api/ws-provider": "^0.9.0",
|
|
30
30
|
"@polkadot-api/json-rpc-provider": "^0.2.0",
|
|
31
31
|
"@polkadot-api/json-rpc-provider-proxy": "^0.4.0",
|