diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c59ac5a..5834361d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## 0.8.9 (2026-06-15) + +### 🩹 Fixes + +- **host-container:** a TruApi-routed transaction broadcast no longer abandons itself — the chain connection is now held for the lifetime of the broadcast (until a matching `transaction_v1_stop`) instead of being torn down immediately, so transactions are actually included. Duplicate/unknown stops are idempotent no-ops. + +### ❤️ Thank You + +- Sergey Zhuravlev @johnthecat + ## 0.8.8 (2026-06-15) ### 🚀 Features diff --git a/__tests__/hostApi/chainInteraction.spec.ts b/__tests__/hostApi/chainInteraction.spec.ts index 1e4bb04f..95c59fcb 100644 --- a/__tests__/hostApi/chainInteraction.spec.ts +++ b/__tests__/hostApi/chainInteraction.spec.ts @@ -686,13 +686,16 @@ describe('Host API: Chain Interaction', () => { const { container, hostApi } = setupDirect(); const stopFn = vi.fn(); + container.handlePermission((_params, { ok }) => ok(true)); container.handleChainConnection(chain => { if (chain !== WellKnownChain.polkadotRelay) return null; return onMessage => { return { send(message) { - if (message.method === 'transaction_v1_stop') { + if (message.method === 'transaction_v1_broadcast') { + onMessage({ jsonrpc: '2.0', id: message.id ?? null, result: 'tx_op_1' }); + } else if (message.method === 'transaction_v1_stop') { stopFn(message.params[0]); onMessage({ jsonrpc: '2.0', id: message.id ?? null, result: null }); @@ -707,6 +710,11 @@ describe('Host API: Chain Interaction', () => { }; }); + // A stop pairs with a prior broadcast, which keeps the connection alive. + await hostApi.chainTransactionBroadcast( + enumValue('v1', { genesisHash: WellKnownChain.polkadotRelay, transaction: '0xdeadbeef' as HexString }), + ); + const result = await hostApi.chainTransactionStop( enumValue('v1', { genesisHash: WellKnownChain.polkadotRelay, operationId: 'tx_op_1' }), ); @@ -722,6 +730,145 @@ describe('Host API: Chain Interaction', () => { expect(stopFn).toHaveBeenCalledWith('tx_op_1'); }); + it('should keep the chain connection alive after broadcast until stop', async () => { + const { container, hostApi } = setupDirect(); + const disconnectFn = vi.fn(); + + container.handlePermission((_params, { ok }) => ok(true)); + container.handleChainConnection(chain => { + if (chain !== WellKnownChain.polkadotRelay) return null; + + return onMessage => { + return { + send(message) { + if (message.method === 'transaction_v1_broadcast') { + onMessage({ jsonrpc: '2.0', id: message.id ?? null, result: 'tx_op_1' }); + } else { + onMessage({ jsonrpc: '2.0', id: message.id ?? null, result: null }); + } + }, + disconnect: disconnectFn, + }; + }; + }); + + const broadcast = await hostApi.chainTransactionBroadcast( + enumValue('v1', { genesisHash: WellKnownChain.polkadotRelay, transaction: '0xdeadbeef' as HexString }), + ); + broadcast.match( + ok => expect(ok.value).toBe('tx_op_1'), + () => { + throw new Error('Expected success'); + }, + ); + + // The node keeps re-broadcasting only while the connection lives. Tearing + // it down here would abandon the broadcast (the reported bug). + expect(disconnectFn).not.toHaveBeenCalled(); + + const stop = await hostApi.chainTransactionStop( + enumValue('v1', { genesisHash: WellKnownChain.polkadotRelay, operationId: 'tx_op_1' }), + ); + stop.match( + () => { + /* success */ + }, + () => { + throw new Error('Expected success'); + }, + ); + + // Once stopped and nothing else holds the chain, it is torn down. + expect(disconnectFn).toHaveBeenCalled(); + }); + + it('should treat a duplicate stop as a no-op and tear down only once', async () => { + const { container, hostApi } = setupDirect(); + const disconnectFn = vi.fn(); + const stopFn = vi.fn(); + + container.handlePermission((_params, { ok }) => ok(true)); + container.handleChainConnection(chain => { + if (chain !== WellKnownChain.polkadotRelay) return null; + + return onMessage => { + return { + send(message) { + if (message.method === 'transaction_v1_broadcast') { + onMessage({ jsonrpc: '2.0', id: message.id ?? null, result: 'tx_op_1' }); + } else if (message.method === 'transaction_v1_stop') { + stopFn(message.params[0]); + onMessage({ jsonrpc: '2.0', id: message.id ?? null, result: null }); + } else { + onMessage({ jsonrpc: '2.0', id: message.id ?? null, result: null }); + } + }, + disconnect: disconnectFn, + }; + }; + }); + + await hostApi.chainTransactionBroadcast( + enumValue('v1', { genesisHash: WellKnownChain.polkadotRelay, transaction: '0xdeadbeef' as HexString }), + ); + + const first = await hostApi.chainTransactionStop( + enumValue('v1', { genesisHash: WellKnownChain.polkadotRelay, operationId: 'tx_op_1' }), + ); + const second = await hostApi.chainTransactionStop( + enumValue('v1', { genesisHash: WellKnownChain.polkadotRelay, operationId: 'tx_op_1' }), + ); + + for (const result of [first, second]) { + result.match( + () => { + /* both report success */ + }, + () => { + throw new Error('Expected success'); + }, + ); + } + + // The node-facing stop fires once; the duplicate neither re-sends nor + // releases a ref, so teardown happens exactly once. + expect(stopFn).toHaveBeenCalledTimes(1); + expect(disconnectFn).toHaveBeenCalledTimes(1); + }); + + it('should tear down the connection when broadcast returns null', async () => { + const { container, hostApi } = setupDirect(); + const disconnectFn = vi.fn(); + + container.handlePermission((_params, { ok }) => ok(true)); + container.handleChainConnection(chain => { + if (chain !== WellKnownChain.polkadotRelay) return null; + + return onMessage => { + return { + send(message) { + onMessage({ jsonrpc: '2.0', id: message.id ?? null, result: null }); + }, + disconnect: disconnectFn, + }; + }; + }); + + const broadcast = await hostApi.chainTransactionBroadcast( + enumValue('v1', { genesisHash: WellKnownChain.polkadotRelay, transaction: '0xdeadbeef' as HexString }), + ); + broadcast.match( + ok => expect(ok.value).toBe(null), + () => { + throw new Error('Expected success'); + }, + ); + + // No operation id means no stop will ever come, so the ref must be + // released immediately rather than leaking the connection. + expect(disconnectFn).toHaveBeenCalled(); + }); + it('should return permission denied when submitPermission returns false', async () => { const { container, hostApi } = setupDirect(); diff --git a/package-lock.json b/package-lock.json index 27ed1ab8..cd125906 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17329,7 +17329,7 @@ }, "packages/handoff-service": { "name": "@novasamatech/handoff-service", - "version": "0.8.8", + "version": "0.8.9", "license": "Apache-2.0", "dependencies": { "@noble/ciphers": "2.2.0", @@ -17342,10 +17342,10 @@ }, "packages/host-api": { "name": "@novasamatech/host-api", - "version": "0.8.8", + "version": "0.8.9", "license": "Apache-2.0", "dependencies": { - "@novasamatech/scale": "0.8.8", + "@novasamatech/scale": "0.8.9", "nanoevents": "9.1.0", "nanoid": "5.1.11", "neverthrow": "^8.2.0", @@ -17354,10 +17354,10 @@ }, "packages/host-api-wrapper": { "name": "@novasamatech/host-api-wrapper", - "version": "0.8.8", + "version": "0.8.9", "license": "Apache-2.0", "dependencies": { - "@novasamatech/host-api": "0.8.8", + "@novasamatech/host-api": "0.8.9", "@polkadot-api/json-rpc-provider-proxy": "^0.4.0", "@polkadot-api/substrate-bindings": "^0.20.3", "@polkadot/extension-inject": "^0.63.1", @@ -17397,12 +17397,12 @@ }, "packages/host-chat": { "name": "@novasamatech/host-chat", - "version": "0.8.8", + "version": "0.8.9", "license": "Apache-2.0", "dependencies": { - "@novasamatech/scale": "0.8.8", - "@novasamatech/statement-store": "0.8.8", - "@novasamatech/storage-adapter": "0.8.8", + "@novasamatech/scale": "0.8.9", + "@novasamatech/statement-store": "0.8.9", + "@novasamatech/storage-adapter": "0.8.9", "nanoid": "5.1.11", "neverthrow": "^8.2.0" } @@ -17427,11 +17427,11 @@ }, "packages/host-container": { "name": "@novasamatech/host-container", - "version": "0.8.8", + "version": "0.8.9", "license": "Apache-2.0", "dependencies": { "@noble/hashes": "2.2.0", - "@novasamatech/host-api": "0.8.8", + "@novasamatech/host-api": "0.8.9", "@polkadot-api/substrate-client": "^0.7.0", "nanoevents": "9.1.0", "nanoid": "5.1.11", @@ -17462,16 +17462,16 @@ }, "packages/host-papp": { "name": "@novasamatech/host-papp", - "version": "0.8.8", + "version": "0.8.9", "license": "Apache-2.0", "dependencies": { "@noble/ciphers": "2.2.0", "@noble/curves": "2.2.0", "@noble/hashes": "2.2.0", - "@novasamatech/host-api": "0.8.8", - "@novasamatech/scale": "0.8.8", - "@novasamatech/statement-store": "0.8.8", - "@novasamatech/storage-adapter": "0.8.8", + "@novasamatech/host-api": "0.8.9", + "@novasamatech/scale": "0.8.9", + "@novasamatech/statement-store": "0.8.9", + "@novasamatech/storage-adapter": "0.8.9", "@polkadot-api/utils": "^0.4.0", "@polkadot-labs/hdkd-helpers": "^0.0.30", "nanoevents": "9.1.0", @@ -17484,11 +17484,11 @@ }, "packages/host-papp-react-ui": { "name": "@novasamatech/host-papp-react-ui", - "version": "0.8.8", + "version": "0.8.9", "license": "Apache-2.0", "dependencies": { - "@novasamatech/host-papp": "0.8.8", - "@novasamatech/statement-store": "0.8.8", + "@novasamatech/host-papp": "0.8.9", + "@novasamatech/statement-store": "0.8.9", "@novasamatech/tr-ui": "^0.2.11", "@polkadot-api/utils": "^0.4.0", "@radix-ui/react-dialog": "1.1.16", @@ -18007,10 +18007,10 @@ }, "packages/host-substrate-chain-connection": { "name": "@novasamatech/host-substrate-chain-connection", - "version": "0.8.8", + "version": "0.8.9", "license": "Apache-2.0", "dependencies": { - "@novasamatech/storage-adapter": "0.8.8", + "@novasamatech/storage-adapter": "0.8.9", "@polkadot-api/json-rpc-provider": "^0.2.0", "@polkadot-api/json-rpc-provider-proxy": "^0.4.0", "@polkadot-api/ws-provider": "^0.9.0", @@ -18020,31 +18020,31 @@ }, "packages/host-worker-sandbox": { "name": "@novasamatech/host-worker-sandbox", - "version": "0.8.8", + "version": "0.8.9", "license": "Apache-2.0", "dependencies": { - "@novasamatech/host-api": "0.8.8", - "@novasamatech/host-container": "0.8.8", + "@novasamatech/host-api": "0.8.9", + "@novasamatech/host-container": "0.8.9", "quickjs-emscripten": "0.32.0" } }, "packages/product-bulletin": { "name": "@novasamatech/product-bulletin", - "version": "0.8.8", + "version": "0.8.9", "license": "Apache-2.0", "dependencies": { - "@novasamatech/host-api-wrapper": "0.8.8", + "@novasamatech/host-api-wrapper": "0.8.9", "@parity/bulletin-sdk": "^0.3.0", "polkadot-api": ">=2" } }, "packages/product-react-renderer": { "name": "@novasamatech/product-react-renderer", - "version": "0.8.8", + "version": "0.8.9", "license": "Apache-2.0", "dependencies": { - "@novasamatech/host-api": "0.8.8", - "@novasamatech/host-api-wrapper": "0.8.8", + "@novasamatech/host-api": "0.8.9", + "@novasamatech/host-api-wrapper": "0.8.9", "react-reconciler": "0.33.0", "scale-ts": "1.6.1" }, @@ -18071,7 +18071,7 @@ }, "packages/scale": { "name": "@novasamatech/scale", - "version": "0.8.8", + "version": "0.8.9", "license": "Apache-2.0", "dependencies": { "@polkadot-api/utils": "^0.4.0", @@ -18080,14 +18080,14 @@ }, "packages/statement-store": { "name": "@novasamatech/statement-store", - "version": "0.8.8", + "version": "0.8.9", "license": "Apache-2.0", "dependencies": { "@noble/ciphers": "2.2.0", "@noble/hashes": "2.2.0", - "@novasamatech/scale": "0.8.8", + "@novasamatech/scale": "0.8.9", "@novasamatech/sdk-statement": "^0.6.0", - "@novasamatech/substrate-slot-sr25519-wasm": "0.8.8", + "@novasamatech/substrate-slot-sr25519-wasm": "0.8.9", "@polkadot-api/substrate-bindings": "^0.20.3", "@polkadot-api/substrate-client": "^0.7.0", "@polkadot-labs/hdkd-helpers": "^0.0.30", @@ -18131,7 +18131,7 @@ }, "packages/storage-adapter": { "name": "@novasamatech/storage-adapter", - "version": "0.8.8", + "version": "0.8.9", "license": "Apache-2.0", "dependencies": { "nanoevents": "^9.1.0", @@ -18140,7 +18140,7 @@ }, "packages/substrate-slot-sr25519-wasm": { "name": "@novasamatech/substrate-slot-sr25519-wasm", - "version": "0.8.8", + "version": "0.8.9", "license": "Apache-2.0" } } diff --git a/packages/handoff-service/package.json b/packages/handoff-service/package.json index 2fb071a0..55a6d9f8 100644 --- a/packages/handoff-service/package.json +++ b/packages/handoff-service/package.json @@ -1,7 +1,7 @@ { "name": "@novasamatech/handoff-service", "type": "module", - "version": "0.8.8", + "version": "0.8.9", "description": "HOP (Handoff Pool) file transfer service for P2P chat", "license": "Apache-2.0", "repository": { diff --git a/packages/host-api-wrapper/package.json b/packages/host-api-wrapper/package.json index 1be17ee7..9c288480 100644 --- a/packages/host-api-wrapper/package.json +++ b/packages/host-api-wrapper/package.json @@ -1,7 +1,7 @@ { "name": "@novasamatech/host-api-wrapper", "type": "module", - "version": "0.8.8", + "version": "0.8.9", "description": "Host API wrapper: integrate and run your product inside Polkadot browser.", "license": "Apache-2.0", "repository": { @@ -28,7 +28,7 @@ "@polkadot/extension-inject": "^0.63.1", "@polkadot-api/json-rpc-provider-proxy": "^0.4.0", "@polkadot-api/substrate-bindings": "^0.20.3", - "@novasamatech/host-api": "0.8.8", + "@novasamatech/host-api": "0.8.9", "polkadot-api": ">=2", "neverthrow": "^8.2.0" }, diff --git a/packages/host-api/package.json b/packages/host-api/package.json index e71ee23c..67445c24 100644 --- a/packages/host-api/package.json +++ b/packages/host-api/package.json @@ -1,7 +1,7 @@ { "name": "@novasamatech/host-api", "type": "module", - "version": "0.8.8", + "version": "0.8.9", "description": "Host API: transport implementation for host - product integration.", "license": "Apache-2.0", "repository": { @@ -22,7 +22,7 @@ "README.md" ], "dependencies": { - "@novasamatech/scale": "0.8.8", + "@novasamatech/scale": "0.8.9", "nanoevents": "9.1.0", "nanoid": "5.1.11", "neverthrow": "^8.2.0", diff --git a/packages/host-chat/package.json b/packages/host-chat/package.json index 244a16e8..198b9f87 100644 --- a/packages/host-chat/package.json +++ b/packages/host-chat/package.json @@ -1,7 +1,7 @@ { "name": "@novasamatech/host-chat", "type": "module", - "version": "0.8.8", + "version": "0.8.9", "description": "Host statement store chat integration", "license": "Apache-2.0", "repository": { @@ -40,9 +40,9 @@ "README.md" ], "dependencies": { - "@novasamatech/scale": "0.8.8", - "@novasamatech/statement-store": "0.8.8", - "@novasamatech/storage-adapter": "0.8.8", + "@novasamatech/scale": "0.8.9", + "@novasamatech/statement-store": "0.8.9", + "@novasamatech/storage-adapter": "0.8.9", "nanoid": "5.1.11", "neverthrow": "^8.2.0" }, diff --git a/packages/host-container/package.json b/packages/host-container/package.json index faf60630..c091c972 100644 --- a/packages/host-container/package.json +++ b/packages/host-container/package.json @@ -1,7 +1,7 @@ { "name": "@novasamatech/host-container", "type": "module", - "version": "0.8.8", + "version": "0.8.9", "description": "Host container for hosting and managing products within the Polkadot ecosystem.", "license": "Apache-2.0", "repository": { @@ -28,7 +28,7 @@ "@noble/hashes": "2.2.0", "polkadot-api": ">=2", "@polkadot-api/substrate-client": "^0.7.0", - "@novasamatech/host-api": "0.8.8", + "@novasamatech/host-api": "0.8.9", "nanoevents": "9.1.0", "nanoid": "5.1.11", "neverthrow": "^8.2.0" diff --git a/packages/host-container/src/chainConnectionManager.ts b/packages/host-container/src/chainConnectionManager.ts index 24a488ba..eb2eb7d8 100644 --- a/packages/host-container/src/chainConnectionManager.ts +++ b/packages/host-container/src/chainConnectionManager.ts @@ -219,10 +219,10 @@ export function createChainConnectionManager( }); }, - sendRequest(genesisHash: HexString, method: string, params: unknown[]): Promise { + sendRequest(genesisHash: HexString, method: string, params: unknown[]): Promise { const entry = chains.get(genesisHash); if (!entry) return Promise.reject(new Error(`No connection for chain ${genesisHash}`)); - return entry.client.request(method, params); + return entry.client.request(method, params); }, releaseChain(genesisHash: HexString) { diff --git a/packages/host-container/src/createContainer.ts b/packages/host-container/src/createContainer.ts index ded6ab27..0c53e195 100644 --- a/packages/host-container/src/createContainer.ts +++ b/packages/host-container/src/createContainer.ts @@ -795,6 +795,8 @@ export function createContainer(provider: Provider, options: CreateContainerOpti init(); const manager = createChainConnectionManager(factory); const cleanups: VoidFunction[] = []; + // `${genesisHash}:${operationId}` for each broadcast holding a chain ref. + const liveBroadcasts = new Set(); // Follow subscription cleanups.push( @@ -1085,12 +1087,23 @@ export function createContainer(provider: Provider, options: CreateContainerOpti } try { - const result = await manager.sendRequest(genesisHash, 'transaction_v1_broadcast', [transaction]); - return enumValue('v1', resultOk((result as string) ?? null)); + const operationId = await manager.sendRequest(genesisHash, 'transaction_v1_broadcast', [ + transaction, + ]); + // `transaction_v1_broadcast` is not one-shot: the node re-broadcasts + // only while the connection lives, until a matching + // `transaction_v1_stop`. Keep the chain ref acquired above by + // recording the live operation; the stop handler releases it. + // A null operationId means nothing to stop, so release now. + if (operationId) { + liveBroadcasts.add(`${genesisHash}:${operationId}`); + } else { + manager.releaseChain(genesisHash); + } + return enumValue('v1', resultOk(operationId)); } catch (e) { - return enumValue('v1', resultErr(new GenericError({ reason: String(e) }))); - } finally { manager.releaseChain(genesisHash); + return enumValue('v1', resultErr(new GenericError({ reason: String(e) }))); } }), ); @@ -1103,18 +1116,21 @@ export function createContainer(provider: Provider, options: CreateContainerOpti } const { genesisHash, operationId } = message.value; - const entry = manager.getOrCreateChain(genesisHash); - if (!entry) { - return enumValue('v1', resultErr(new GenericError({ reason: 'Chain not supported' }))); + // Only a stop matching a live broadcast releases the ref that broadcast + // holds (over its still-open connection). Duplicate or unknown stops + // are no-op successes, so refCount can't be driven below what the live + // broadcasts justify. + if (!liveBroadcasts.delete(`${genesisHash}:${operationId}`)) { + return enumValue('v1', resultOk(undefined)); } try { await manager.sendRequest(genesisHash, 'transaction_v1_stop', [operationId]); - manager.releaseChain(genesisHash); return enumValue('v1', resultOk(undefined)); } catch (e) { - manager.releaseChain(genesisHash); return enumValue('v1', resultErr(new GenericError({ reason: String(e) }))); + } finally { + manager.releaseChain(genesisHash); } }), ); diff --git a/packages/host-papp-react-ui/package.json b/packages/host-papp-react-ui/package.json index fbffee6b..91225646 100644 --- a/packages/host-papp-react-ui/package.json +++ b/packages/host-papp-react-ui/package.json @@ -1,7 +1,7 @@ { "name": "@novasamatech/host-papp-react-ui", "type": "module", - "version": "0.8.8", + "version": "0.8.9", "description": "Polkadot app UI Flow", "license": "Apache-2.0", "repository": { @@ -33,8 +33,8 @@ "react-dom": ">=18" }, "dependencies": { - "@novasamatech/host-papp": "0.8.8", - "@novasamatech/statement-store": "0.8.8", + "@novasamatech/host-papp": "0.8.9", + "@novasamatech/statement-store": "0.8.9", "@polkadot-api/utils": "^0.4.0", "@radix-ui/react-dialog": "1.1.16", "@radix-ui/react-popover": "1.1.16", diff --git a/packages/host-papp/package.json b/packages/host-papp/package.json index 333204a4..99944dc3 100644 --- a/packages/host-papp/package.json +++ b/packages/host-papp/package.json @@ -1,7 +1,7 @@ { "name": "@novasamatech/host-papp", "type": "module", - "version": "0.8.8", + "version": "0.8.9", "description": "Polkadot app integration", "license": "Apache-2.0", "repository": { @@ -34,10 +34,10 @@ "@noble/ciphers": "2.2.0", "@noble/curves": "2.2.0", "@noble/hashes": "2.2.0", - "@novasamatech/host-api": "0.8.8", - "@novasamatech/scale": "0.8.8", - "@novasamatech/statement-store": "0.8.8", - "@novasamatech/storage-adapter": "0.8.8", + "@novasamatech/host-api": "0.8.9", + "@novasamatech/scale": "0.8.9", + "@novasamatech/statement-store": "0.8.9", + "@novasamatech/storage-adapter": "0.8.9", "@polkadot-api/utils": "^0.4.0", "@polkadot-labs/hdkd-helpers": "^0.0.30", "nanoevents": "9.1.0", diff --git a/packages/host-papp/src/sso/sessionManager/userSession.ts b/packages/host-papp/src/sso/sessionManager/userSession.ts index 3db1872c..e4d71952 100644 --- a/packages/host-papp/src/sso/sessionManager/userSession.ts +++ b/packages/host-papp/src/sso/sessionManager/userSession.ts @@ -30,7 +30,7 @@ import type { // the remote signer doesn't respond — e.g. the request // payload is for an SDK version the mobile app doesn't support yet. After // this timeout the queue task fails, freeing the pool for the next request. -const QUEUE_TASK_TIMEOUT_MS = 180_000; +const QUEUE_TASK_TIMEOUT_MS = 240_000; // Mobile SSO statements allow 500 KiB total; keep headroom for statement/session overhead. const MAX_SSO_REQUEST_SIZE = 498 * 1024; @@ -273,6 +273,7 @@ export function createUserSession({ return enqueue(() => { const messageId = nanoid(); const data = enumValue('v1', enumValue('CreateTransactionRequest', payload)); + emitHostAction(messageId, actionKindFromMessageData(data), userSession.id); const responseFilter = (message: RemoteMessage) => { if ( @@ -295,7 +296,7 @@ export function createUserSession({ } }); - return withQueueTimeout(inner, 'createTransaction'); + return withHostActionTrace(withQueueTimeout(inner, 'createTransaction'), messageId, userSession.id); }); }, @@ -303,6 +304,7 @@ export function createUserSession({ return enqueue(() => { const messageId = nanoid(); const data = enumValue('v1', enumValue('CreateTransactionLegacyRequest', payload)); + emitHostAction(messageId, actionKindFromMessageData(data), userSession.id); const responseFilter = (message: RemoteMessage) => { if ( @@ -325,7 +327,7 @@ export function createUserSession({ } }); - return withQueueTimeout(inner, 'createTransactionLegacy'); + return withHostActionTrace(withQueueTimeout(inner, 'createTransactionLegacy'), messageId, userSession.id); }); }, @@ -368,6 +370,7 @@ export function createUserSession({ return enqueue(() => { const messageId = nanoid(); const data = enumValue('v1', enumValue('ResourceAllocationRequest', payload)); + emitHostAction(messageId, actionKindFromMessageData(data), userSession.id); const responseFilter = (message: RemoteMessage) => { if ( @@ -386,7 +389,7 @@ export function createUserSession({ result.success ? ok(result.value) : err(new Error(result.value)), ); - return withQueueTimeout(inner, 'requestResourceAllocation'); + return withHostActionTrace(withQueueTimeout(inner, 'requestResourceAllocation'), messageId, userSession.id); }); }, @@ -470,7 +473,7 @@ export function createUserSession({ abortPendingRequests() { // Drop the whole request queue: aborting the shared signal rejects the // in-flight task and every request queued behind it, freeing the single - // slot immediately instead of waiting out the per-task 180s timeout. Swap + // slot immediately instead of waiting out the per-task timeout. Swap // in a fresh controller so subsequent requests aren't pre-aborted. requestAbort.abort(new Error('Session request aborted')); requestAbort = new AbortController(); diff --git a/packages/host-substrate-chain-connection/package.json b/packages/host-substrate-chain-connection/package.json index b5659a19..03ef418d 100644 --- a/packages/host-substrate-chain-connection/package.json +++ b/packages/host-substrate-chain-connection/package.json @@ -1,7 +1,7 @@ { "name": "@novasamatech/host-substrate-chain-connection", "type": "module", - "version": "0.8.8", + "version": "0.8.9", "description": "Chain connection pool with ref counting and provider branching for Polkadot API", "license": "Apache-2.0", "repository": { @@ -25,7 +25,7 @@ "README.md" ], "dependencies": { - "@novasamatech/storage-adapter": "0.8.8", + "@novasamatech/storage-adapter": "0.8.9", "@polkadot-api/ws-provider": "^0.9.0", "@polkadot-api/json-rpc-provider": "^0.2.0", "@polkadot-api/json-rpc-provider-proxy": "^0.4.0", diff --git a/packages/host-worker-sandbox/package.json b/packages/host-worker-sandbox/package.json index 5eb8476e..335d25e4 100644 --- a/packages/host-worker-sandbox/package.json +++ b/packages/host-worker-sandbox/package.json @@ -1,7 +1,7 @@ { "name": "@novasamatech/host-worker-sandbox", "type": "module", - "version": "0.8.8", + "version": "0.8.9", "description": "QuickJS-based sandbox for running product worker code with Triangle Host API.", "license": "Apache-2.0", "repository": { @@ -25,8 +25,8 @@ "README.md" ], "dependencies": { - "@novasamatech/host-api": "0.8.8", - "@novasamatech/host-container": "0.8.8", + "@novasamatech/host-api": "0.8.9", + "@novasamatech/host-container": "0.8.9", "quickjs-emscripten": "0.32.0" }, "publishConfig": { diff --git a/packages/product-bulletin/package.json b/packages/product-bulletin/package.json index 38cb5c7f..9df74ad6 100644 --- a/packages/product-bulletin/package.json +++ b/packages/product-bulletin/package.json @@ -1,7 +1,7 @@ { "name": "@novasamatech/product-bulletin", "type": "module", - "version": "0.8.8", + "version": "0.8.9", "description": "Bulletin Chain client adapter for Polkadot product applications", "license": "Apache-2.0", "repository": { @@ -27,7 +27,7 @@ "README.md" ], "dependencies": { - "@novasamatech/host-api-wrapper": "0.8.8", + "@novasamatech/host-api-wrapper": "0.8.9", "@parity/bulletin-sdk": "^0.3.0", "polkadot-api": ">=2" }, diff --git a/packages/product-react-renderer/package.json b/packages/product-react-renderer/package.json index e8168b76..a4f5bc2b 100644 --- a/packages/product-react-renderer/package.json +++ b/packages/product-react-renderer/package.json @@ -1,7 +1,7 @@ { "name": "@novasamatech/product-react-renderer", "type": "module", - "version": "0.8.8", + "version": "0.8.9", "description": "React wrapper for custom renderer format from host-api-wrapper", "license": "Apache-2.0", "repository": { @@ -24,8 +24,8 @@ "README.md" ], "dependencies": { - "@novasamatech/host-api": "0.8.8", - "@novasamatech/host-api-wrapper": "0.8.8", + "@novasamatech/host-api": "0.8.9", + "@novasamatech/host-api-wrapper": "0.8.9", "scale-ts": "1.6.1", "react-reconciler": "0.33.0" }, diff --git a/packages/scale/package.json b/packages/scale/package.json index 0b51d1d1..1e65dbba 100644 --- a/packages/scale/package.json +++ b/packages/scale/package.json @@ -1,7 +1,7 @@ { "name": "@novasamatech/scale", "type": "module", - "version": "0.8.8", + "version": "0.8.9", "description": "additional scale-ts bindings", "license": "Apache-2.0", "repository": { diff --git a/packages/statement-store/package.json b/packages/statement-store/package.json index cf61693c..085c299b 100644 --- a/packages/statement-store/package.json +++ b/packages/statement-store/package.json @@ -1,7 +1,7 @@ { "name": "@novasamatech/statement-store", "type": "module", - "version": "0.8.8", + "version": "0.8.9", "description": "Statement store integration", "license": "Apache-2.0", "repository": { @@ -25,9 +25,9 @@ "README.md" ], "dependencies": { - "@novasamatech/scale": "0.8.8", + "@novasamatech/scale": "0.8.9", "@novasamatech/sdk-statement": "^0.6.0", - "@novasamatech/substrate-slot-sr25519-wasm": "0.8.8", + "@novasamatech/substrate-slot-sr25519-wasm": "0.8.9", "@polkadot-api/substrate-bindings": "^0.20.3", "@polkadot-api/substrate-client": "^0.7.0", "@polkadot-labs/hdkd-helpers": "^0.0.30", diff --git a/packages/storage-adapter/package.json b/packages/storage-adapter/package.json index 32398dec..e480d75e 100644 --- a/packages/storage-adapter/package.json +++ b/packages/storage-adapter/package.json @@ -1,7 +1,7 @@ { "name": "@novasamatech/storage-adapter", "type": "module", - "version": "0.8.8", + "version": "0.8.9", "description": "Statement store integration", "license": "Apache-2.0", "repository": { diff --git a/packages/substrate-slot-sr25519-wasm/package.json b/packages/substrate-slot-sr25519-wasm/package.json index dd08a3f3..4205279d 100644 --- a/packages/substrate-slot-sr25519-wasm/package.json +++ b/packages/substrate-slot-sr25519-wasm/package.json @@ -1,7 +1,7 @@ { "name": "@novasamatech/substrate-slot-sr25519-wasm", "type": "module", - "version": "0.8.8", + "version": "0.8.9", "description": "Substrate sr25519 slot-account crypto (SecretKey::from_bytes) for mobile SlotAccountKey", "license": "Apache-2.0", "repository": {