@useragent-kit/sdk 0.0.0 → 0.0.1
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/LICENSE +661 -0
- package/README.md +61 -3
- package/dist/adapters.d.ts +94 -0
- package/dist/adapters.d.ts.map +1 -0
- package/dist/adapters.js +188 -0
- package/dist/adapters.js.map +1 -0
- package/dist/api-protocol.d.ts +9 -0
- package/dist/api-protocol.d.ts.map +1 -0
- package/dist/api-protocol.js +9 -0
- package/dist/api-protocol.js.map +1 -0
- package/dist/bridge/contract.d.ts +66 -0
- package/dist/bridge/contract.d.ts.map +1 -0
- package/dist/bridge/contract.js +160 -0
- package/dist/bridge/contract.js.map +1 -0
- package/dist/bridge/index.d.ts +53 -0
- package/dist/bridge/index.d.ts.map +1 -0
- package/dist/bridge/index.js +302 -0
- package/dist/bridge/index.js.map +1 -0
- package/dist/bridge/types.d.ts +93 -0
- package/dist/bridge/types.d.ts.map +1 -0
- package/dist/bridge/types.js +9 -0
- package/dist/bridge/types.js.map +1 -0
- package/dist/chain.d.ts +198 -0
- package/dist/chain.d.ts.map +1 -0
- package/dist/chain.js +424 -0
- package/dist/chain.js.map +1 -0
- package/dist/errors.d.ts +22 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +41 -0
- package/dist/errors.js.map +1 -0
- package/dist/events.d.ts +252 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +54 -0
- package/dist/events.js.map +1 -0
- package/dist/experimental/file-transfer.d.ts +97 -0
- package/dist/experimental/file-transfer.d.ts.map +1 -0
- package/dist/experimental/file-transfer.js +1377 -0
- package/dist/experimental/file-transfer.js.map +1 -0
- package/dist/experimental/index.d.ts +7 -0
- package/dist/experimental/index.d.ts.map +1 -0
- package/dist/experimental/index.js +4 -0
- package/dist/experimental/index.js.map +1 -0
- package/dist/experimental/logger.d.ts +5 -0
- package/dist/experimental/logger.d.ts.map +1 -0
- package/dist/experimental/logger.js +74 -0
- package/dist/experimental/logger.js.map +1 -0
- package/dist/experimental/transport.d.ts +34 -0
- package/dist/experimental/transport.d.ts.map +1 -0
- package/dist/experimental/transport.js +43 -0
- package/dist/experimental/transport.js.map +1 -0
- package/dist/guest/claw.d.ts +10 -0
- package/dist/guest/claw.d.ts.map +1 -0
- package/dist/guest/claw.js +21 -0
- package/dist/guest/claw.js.map +1 -0
- package/dist/guest/crdt.d.ts +19 -0
- package/dist/guest/crdt.d.ts.map +1 -0
- package/dist/guest/crdt.js +64 -0
- package/dist/guest/crdt.js.map +1 -0
- package/dist/guest/data.d.ts +27 -0
- package/dist/guest/data.d.ts.map +1 -0
- package/dist/guest/data.js +61 -0
- package/dist/guest/data.js.map +1 -0
- package/dist/guest/files.d.ts +15 -0
- package/dist/guest/files.d.ts.map +1 -0
- package/dist/guest/files.js +24 -0
- package/dist/guest/files.js.map +1 -0
- package/dist/guest/index.d.ts +43 -0
- package/dist/guest/index.d.ts.map +1 -0
- package/dist/guest/index.js +44 -0
- package/dist/guest/index.js.map +1 -0
- package/dist/guest/media.d.ts +44 -0
- package/dist/guest/media.d.ts.map +1 -0
- package/dist/guest/media.js +97 -0
- package/dist/guest/media.js.map +1 -0
- package/dist/guest/mesh.d.ts +79 -0
- package/dist/guest/mesh.d.ts.map +1 -0
- package/dist/guest/mesh.js +153 -0
- package/dist/guest/mesh.js.map +1 -0
- package/dist/guest/navigate.d.ts +17 -0
- package/dist/guest/navigate.d.ts.map +1 -0
- package/dist/guest/navigate.js +169 -0
- package/dist/guest/navigate.js.map +1 -0
- package/dist/guest/statements.d.ts +18 -0
- package/dist/guest/statements.d.ts.map +1 -0
- package/dist/guest/statements.js +26 -0
- package/dist/guest/statements.js.map +1 -0
- package/dist/guest/telemetry.d.ts +88 -0
- package/dist/guest/telemetry.d.ts.map +1 -0
- package/dist/guest/telemetry.js +184 -0
- package/dist/guest/telemetry.js.map +1 -0
- package/dist/guest/types.d.ts +255 -0
- package/dist/guest/types.d.ts.map +1 -0
- package/dist/guest/types.js +9 -0
- package/dist/guest/types.js.map +1 -0
- package/dist/host-runtime-contract.d.ts +19 -0
- package/dist/host-runtime-contract.d.ts.map +1 -0
- package/dist/host-runtime-contract.js +80 -0
- package/dist/host-runtime-contract.js.map +1 -0
- package/dist/host-runtime-frame.d.ts +128 -0
- package/dist/host-runtime-frame.d.ts.map +1 -0
- package/dist/host-runtime-frame.js +881 -0
- package/dist/host-runtime-frame.js.map +1 -0
- package/dist/host-runtime-registry.d.ts +16 -0
- package/dist/host-runtime-registry.d.ts.map +1 -0
- package/dist/host-runtime-registry.js +53 -0
- package/dist/host-runtime-registry.js.map +1 -0
- package/dist/host-runtime.d.ts +106 -0
- package/dist/host-runtime.d.ts.map +1 -0
- package/dist/host-runtime.js +290 -0
- package/dist/host-runtime.js.map +1 -0
- package/dist/identity-adapter.d.ts +42 -0
- package/dist/identity-adapter.d.ts.map +1 -0
- package/dist/identity-adapter.js +43 -0
- package/dist/identity-adapter.js.map +1 -0
- package/dist/identity.d.ts +86 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +223 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +91 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +356 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/api-protocol/api/protocol.d.ts +1402 -0
- package/dist/internal/api-protocol/api/protocol.d.ts.map +1 -0
- package/dist/internal/api-protocol/api/protocol.js +311 -0
- package/dist/internal/api-protocol/api/protocol.js.map +1 -0
- package/dist/internal/api-protocol/api/types.d.ts +24 -0
- package/dist/internal/api-protocol/api/types.d.ts.map +1 -0
- package/dist/internal/api-protocol/api/types.js +9 -0
- package/dist/internal/api-protocol/api/types.js.map +1 -0
- package/dist/internal/api-protocol/host-facade/connectionManager.d.ts +44 -0
- package/dist/internal/api-protocol/host-facade/connectionManager.d.ts.map +1 -0
- package/dist/internal/api-protocol/host-facade/connectionManager.js +349 -0
- package/dist/internal/api-protocol/host-facade/connectionManager.js.map +1 -0
- package/dist/internal/api-protocol/host-facade/protocolHandler.d.ts +24 -0
- package/dist/internal/api-protocol/host-facade/protocolHandler.d.ts.map +1 -0
- package/dist/internal/api-protocol/host-facade/protocolHandler.js +505 -0
- package/dist/internal/api-protocol/host-facade/protocolHandler.js.map +1 -0
- package/dist/internal/api-protocol/host-facade/types.d.ts +82 -0
- package/dist/internal/api-protocol/host-facade/types.d.ts.map +1 -0
- package/dist/internal/api-protocol/host-facade/types.js +14 -0
- package/dist/internal/api-protocol/host-facade/types.js.map +1 -0
- package/dist/internal/api-protocol/index.d.ts +39 -0
- package/dist/internal/api-protocol/index.d.ts.map +1 -0
- package/dist/internal/api-protocol/index.js +41 -0
- package/dist/internal/api-protocol/index.js.map +1 -0
- package/dist/internal/api-protocol/product-facade/hostApi.d.ts +392 -0
- package/dist/internal/api-protocol/product-facade/hostApi.d.ts.map +1 -0
- package/dist/internal/api-protocol/product-facade/hostApi.js +241 -0
- package/dist/internal/api-protocol/product-facade/hostApi.js.map +1 -0
- package/dist/internal/api-protocol/shared/codec/adapter.d.ts +41 -0
- package/dist/internal/api-protocol/shared/codec/adapter.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/codec/adapter.js +10 -0
- package/dist/internal/api-protocol/shared/codec/adapter.js.map +1 -0
- package/dist/internal/api-protocol/shared/codec/negotiation.d.ts +80 -0
- package/dist/internal/api-protocol/shared/codec/negotiation.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/codec/negotiation.js +129 -0
- package/dist/internal/api-protocol/shared/codec/negotiation.js.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/adapter.d.ts +18 -0
- package/dist/internal/api-protocol/shared/codec/scale/adapter.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/adapter.js +23 -0
- package/dist/internal/api-protocol/shared/codec/scale/adapter.js.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/primitives.d.ts +35 -0
- package/dist/internal/api-protocol/shared/codec/scale/primitives.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/primitives.js +96 -0
- package/dist/internal/api-protocol/shared/codec/scale/primitives.js.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/accounts.d.ts +65 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/accounts.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/accounts.js +43 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/accounts.js.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/chainInteraction.d.ts +162 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/chainInteraction.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/chainInteraction.js +81 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/chainInteraction.js.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/chat.d.ts +307 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/chat.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/chat.js +105 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/chat.js.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/commonCodecs.d.ts +5 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/commonCodecs.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/commonCodecs.js +6 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/commonCodecs.js.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/createTransaction.d.ts +71 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/createTransaction.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/createTransaction.js +34 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/createTransaction.js.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/customRenderer.d.ts +106 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/customRenderer.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/customRenderer.js +84 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/customRenderer.js.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/devicePermission.d.ts +4 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/devicePermission.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/devicePermission.js +4 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/devicePermission.js.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/feature.d.ts +7 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/feature.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/feature.js +7 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/feature.js.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/handshake.d.ts +13 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/handshake.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/handshake.js +10 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/handshake.js.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/localStorage.d.ts +15 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/localStorage.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/localStorage.js +12 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/localStorage.js.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/navigation.d.ts +10 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/navigation.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/navigation.js +10 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/navigation.js.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/notification.d.ts +7 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/notification.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/notification.js +7 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/notification.js.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/payment.d.ts +74 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/payment.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/payment.js +38 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/payment.js.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/preimage.d.ts +12 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/preimage.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/preimage.js +11 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/preimage.js.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/remotePermission.d.ts +10 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/remotePermission.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/remotePermission.js +8 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/remotePermission.js.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/sign.d.ts +61 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/sign.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/sign.js +42 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/sign.js.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/statementStore.d.ts +137 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/statementStore.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/statementStore.js +55 -0
- package/dist/internal/api-protocol/shared/codec/scale/v1/statementStore.js.map +1 -0
- package/dist/internal/api-protocol/shared/codec/structured/index.d.ts +10 -0
- package/dist/internal/api-protocol/shared/codec/structured/index.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/codec/structured/index.js +19 -0
- package/dist/internal/api-protocol/shared/codec/structured/index.js.map +1 -0
- package/dist/internal/api-protocol/shared/transport/messagePortProvider.d.ts +18 -0
- package/dist/internal/api-protocol/shared/transport/messagePortProvider.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/transport/messagePortProvider.js +98 -0
- package/dist/internal/api-protocol/shared/transport/messagePortProvider.js.map +1 -0
- package/dist/internal/api-protocol/shared/transport/provider.d.ts +42 -0
- package/dist/internal/api-protocol/shared/transport/provider.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/transport/provider.js +13 -0
- package/dist/internal/api-protocol/shared/transport/provider.js.map +1 -0
- package/dist/internal/api-protocol/shared/transport/transport.d.ts +72 -0
- package/dist/internal/api-protocol/shared/transport/transport.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/transport/transport.js +420 -0
- package/dist/internal/api-protocol/shared/transport/transport.js.map +1 -0
- package/dist/internal/api-protocol/shared/transport/windowProvider.d.ts +13 -0
- package/dist/internal/api-protocol/shared/transport/windowProvider.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/transport/windowProvider.js +85 -0
- package/dist/internal/api-protocol/shared/transport/windowProvider.js.map +1 -0
- package/dist/internal/api-protocol/shared/util/helpers.d.ts +27 -0
- package/dist/internal/api-protocol/shared/util/helpers.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/util/helpers.js +43 -0
- package/dist/internal/api-protocol/shared/util/helpers.js.map +1 -0
- package/dist/internal/api-protocol/shared/util/idFactory.d.ts +9 -0
- package/dist/internal/api-protocol/shared/util/idFactory.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/util/idFactory.js +12 -0
- package/dist/internal/api-protocol/shared/util/idFactory.js.map +1 -0
- package/dist/internal/api-protocol/shared/util/logger.d.ts +15 -0
- package/dist/internal/api-protocol/shared/util/logger.d.ts.map +1 -0
- package/dist/internal/api-protocol/shared/util/logger.js +20 -0
- package/dist/internal/api-protocol/shared/util/logger.js.map +1 -0
- package/dist/mesh-attachment.d.ts +19 -0
- package/dist/mesh-attachment.d.ts.map +1 -0
- package/dist/mesh-attachment.js +43 -0
- package/dist/mesh-attachment.js.map +1 -0
- package/dist/mesh-chat.d.ts +48 -0
- package/dist/mesh-chat.d.ts.map +1 -0
- package/dist/mesh-chat.js +84 -0
- package/dist/mesh-chat.js.map +1 -0
- package/dist/mesh-delivery-diagnostics.d.ts +12 -0
- package/dist/mesh-delivery-diagnostics.d.ts.map +1 -0
- package/dist/mesh-delivery-diagnostics.js +45 -0
- package/dist/mesh-delivery-diagnostics.js.map +1 -0
- package/dist/mesh-notification.d.ts +29 -0
- package/dist/mesh-notification.d.ts.map +1 -0
- package/dist/mesh-notification.js +52 -0
- package/dist/mesh-notification.js.map +1 -0
- package/dist/mesh-pairing.d.ts +40 -0
- package/dist/mesh-pairing.d.ts.map +1 -0
- package/dist/mesh-pairing.js +78 -0
- package/dist/mesh-pairing.js.map +1 -0
- package/dist/product-host-runtime.d.ts +59 -0
- package/dist/product-host-runtime.d.ts.map +1 -0
- package/dist/product-host-runtime.js +150 -0
- package/dist/product-host-runtime.js.map +1 -0
- package/dist/product-protocol.d.ts +49 -0
- package/dist/product-protocol.d.ts.map +1 -0
- package/dist/product-protocol.js +389 -0
- package/dist/product-protocol.js.map +1 -0
- package/dist/product-view-hosted.d.ts +63 -0
- package/dist/product-view-hosted.d.ts.map +1 -0
- package/dist/product-view-hosted.js +272 -0
- package/dist/product-view-hosted.js.map +1 -0
- package/dist/product-view-service-worker.d.ts +6 -0
- package/dist/product-view-service-worker.d.ts.map +1 -0
- package/dist/product-view-service-worker.js +57 -0
- package/dist/product-view-service-worker.js.map +1 -0
- package/dist/product-view.d.ts +459 -0
- package/dist/product-view.d.ts.map +1 -0
- package/dist/product-view.js +2671 -0
- package/dist/product-view.js.map +1 -0
- package/dist/protocol.d.ts +39 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +25 -0
- package/dist/protocol.js.map +1 -0
- package/dist/remote-runtime-provider.d.ts +9 -0
- package/dist/remote-runtime-provider.d.ts.map +1 -0
- package/dist/remote-runtime-provider.js +1002 -0
- package/dist/remote-runtime-provider.js.map +1 -0
- package/dist/runtime-chain-service.d.ts +109 -0
- package/dist/runtime-chain-service.d.ts.map +1 -0
- package/dist/runtime-chain-service.js +846 -0
- package/dist/runtime-chain-service.js.map +1 -0
- package/dist/runtime-chain.d.ts +8 -0
- package/dist/runtime-chain.d.ts.map +1 -0
- package/dist/runtime-chain.js +4 -0
- package/dist/runtime-chain.js.map +1 -0
- package/dist/runtime-storage-access.d.ts +39 -0
- package/dist/runtime-storage-access.d.ts.map +1 -0
- package/dist/runtime-storage-access.js +209 -0
- package/dist/runtime-storage-access.js.map +1 -0
- package/dist/scoped-frame.d.ts +55 -0
- package/dist/scoped-frame.d.ts.map +1 -0
- package/dist/scoped-frame.js +234 -0
- package/dist/scoped-frame.js.map +1 -0
- package/dist/sdk-interfaces.d.ts +159 -0
- package/dist/sdk-interfaces.d.ts.map +1 -0
- package/dist/sdk-interfaces.js +2 -0
- package/dist/sdk-interfaces.js.map +1 -0
- package/dist/statement-store.d.ts +166 -0
- package/dist/statement-store.d.ts.map +1 -0
- package/dist/statement-store.js +627 -0
- package/dist/statement-store.js.map +1 -0
- package/dist/telemetry.d.ts +218 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +162 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/types.d.ts +255 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +77 -0
- package/dist/types.js.map +1 -0
- package/dist/wallet-session.d.ts +89 -0
- package/dist/wallet-session.d.ts.map +1 -0
- package/dist/wallet-session.js +135 -0
- package/dist/wallet-session.js.map +1 -0
- package/package.json +86 -5
- package/index.js +0 -1
|
@@ -0,0 +1,846 @@
|
|
|
1
|
+
import { ChainReadinessTimeoutError, SmoldotDriver, } from "./chain.js";
|
|
2
|
+
export const STALE_PENDING_SUBSCRIPTION_TTL_MS = 60000;
|
|
3
|
+
const PARA_DB_SAVE_RESPONSE_ID = "18446744073709551614";
|
|
4
|
+
const RELAY_DB_SAVE_RESPONSE_ID = "18446744073709551615";
|
|
5
|
+
export const AUDITED_SUBSCRIPTION_STOP_METHODS = Object.freeze({
|
|
6
|
+
chainHead_v1_follow: "chainHead_v1_unfollow",
|
|
7
|
+
chain_subscribeAllHeads: "chain_unsubscribeAllHeads",
|
|
8
|
+
chain_subscribeFinalizedHeads: "chain_unsubscribeFinalizedHeads",
|
|
9
|
+
chain_subscribeNewHeads: "chain_unsubscribeNewHeads",
|
|
10
|
+
state_subscribeRuntimeVersion: "state_unsubscribeRuntimeVersion",
|
|
11
|
+
state_subscribeStorage: "state_unsubscribeStorage",
|
|
12
|
+
statement_subscribeStatement: "statement_unsubscribeStatement",
|
|
13
|
+
transactionWatch_v1_submitAndWatch: "transactionWatch_v1_unwatch",
|
|
14
|
+
});
|
|
15
|
+
function summarizeBridgePayload(text) {
|
|
16
|
+
try {
|
|
17
|
+
const parsed = JSON.parse(text);
|
|
18
|
+
const id = typeof parsed.id === "number" ? parsed.id : "?";
|
|
19
|
+
if (typeof parsed.method === "string") {
|
|
20
|
+
return `${parsed.method}#${id}`;
|
|
21
|
+
}
|
|
22
|
+
if (typeof parsed.result === "string") {
|
|
23
|
+
return `result(${parsed.result})#${id}`;
|
|
24
|
+
}
|
|
25
|
+
const params = parsed.params;
|
|
26
|
+
if (typeof params === "object" && params != null) {
|
|
27
|
+
const result = params.result;
|
|
28
|
+
if (typeof result === "object" &&
|
|
29
|
+
result != null &&
|
|
30
|
+
typeof result.event === "string") {
|
|
31
|
+
return `event(${String(result.event)})`;
|
|
32
|
+
}
|
|
33
|
+
const subscription = params.subscription;
|
|
34
|
+
if (typeof subscription === "string") {
|
|
35
|
+
return `subscription(${subscription})`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// Best-effort debug logging only.
|
|
41
|
+
}
|
|
42
|
+
return "unknown";
|
|
43
|
+
}
|
|
44
|
+
function normalizeRuntimeSpec(spec) {
|
|
45
|
+
if (!isJsonRecord(spec)) {
|
|
46
|
+
return spec;
|
|
47
|
+
}
|
|
48
|
+
const apis = spec.apis;
|
|
49
|
+
if (Array.isArray(apis) || !isJsonRecord(apis)) {
|
|
50
|
+
return spec;
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
...spec,
|
|
54
|
+
apis: Object.entries(apis)
|
|
55
|
+
.filter((entry) => typeof entry[1] === "number")
|
|
56
|
+
.map(([name, version]) => [name, version]),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function normalizeChainHeadFollowEvent(message) {
|
|
60
|
+
const parsed = safeParseJson(message);
|
|
61
|
+
if (!isJsonRecord(parsed) ||
|
|
62
|
+
parsed.method !== "chainHead_v1_followEvent" ||
|
|
63
|
+
!isJsonRecord(parsed.params) ||
|
|
64
|
+
!isJsonRecord(parsed.params.result)) {
|
|
65
|
+
return message;
|
|
66
|
+
}
|
|
67
|
+
const result = parsed.params.result;
|
|
68
|
+
const event = result.event;
|
|
69
|
+
if (event === "initialized" && isJsonRecord(result.finalizedBlockRuntime)) {
|
|
70
|
+
const runtime = result.finalizedBlockRuntime;
|
|
71
|
+
if (!isJsonRecord(runtime.spec)) {
|
|
72
|
+
return message;
|
|
73
|
+
}
|
|
74
|
+
return JSON.stringify({
|
|
75
|
+
...parsed,
|
|
76
|
+
params: {
|
|
77
|
+
...parsed.params,
|
|
78
|
+
result: {
|
|
79
|
+
...result,
|
|
80
|
+
finalizedBlockRuntime: {
|
|
81
|
+
...runtime,
|
|
82
|
+
spec: normalizeRuntimeSpec(runtime.spec),
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
if (event === "newBlock" && isJsonRecord(result.newRuntime)) {
|
|
89
|
+
const runtime = result.newRuntime;
|
|
90
|
+
if (!isJsonRecord(runtime.spec)) {
|
|
91
|
+
return message;
|
|
92
|
+
}
|
|
93
|
+
return JSON.stringify({
|
|
94
|
+
...parsed,
|
|
95
|
+
params: {
|
|
96
|
+
...parsed.params,
|
|
97
|
+
result: {
|
|
98
|
+
...result,
|
|
99
|
+
newRuntime: {
|
|
100
|
+
...runtime,
|
|
101
|
+
spec: normalizeRuntimeSpec(runtime.spec),
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return message;
|
|
108
|
+
}
|
|
109
|
+
function normalizeJsonRpcMessage(message) {
|
|
110
|
+
return normalizeChainHeadFollowEvent(message);
|
|
111
|
+
}
|
|
112
|
+
function createResponseMultiplexer(driver, chainName) {
|
|
113
|
+
const consumers = new Set();
|
|
114
|
+
driver.registerResponseInterceptor(chainName, (text) => {
|
|
115
|
+
for (const handler of consumers) {
|
|
116
|
+
if (handler(text)) {
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return false;
|
|
121
|
+
});
|
|
122
|
+
return {
|
|
123
|
+
addConsumer(handler) {
|
|
124
|
+
consumers.add(handler);
|
|
125
|
+
return () => {
|
|
126
|
+
consumers.delete(handler);
|
|
127
|
+
};
|
|
128
|
+
},
|
|
129
|
+
dispose() {
|
|
130
|
+
consumers.clear();
|
|
131
|
+
driver.unregisterResponseInterceptor(chainName);
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function createBridgedConnection(multiplexer, chain, onMessage) {
|
|
136
|
+
const pendingRequests = new Set();
|
|
137
|
+
const activeSubscriptions = new Set();
|
|
138
|
+
const pendingSubscriptionMessages = new Map();
|
|
139
|
+
const pendingUnsubscribes = new Map();
|
|
140
|
+
const unregister = multiplexer.addConsumer((text) => {
|
|
141
|
+
const normalizedText = normalizeJsonRpcMessage(text);
|
|
142
|
+
const parsed = safeParseJson(normalizedText);
|
|
143
|
+
if (!isJsonRecord(parsed)) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
if ((typeof parsed.id === "string" && parsed.id.startsWith("host-sdk-")) ||
|
|
147
|
+
parsed.method === "chainHead_v1_followEvent") {
|
|
148
|
+
console.info(`[runtime-chain] mux recv ${summarizeBridgePayload(normalizedText)}`);
|
|
149
|
+
}
|
|
150
|
+
if ("id" in parsed && typeof parsed.id === "string" && pendingRequests.has(parsed.id)) {
|
|
151
|
+
pendingRequests.delete(parsed.id);
|
|
152
|
+
if (typeof parsed.result === "string" && parsed.result !== "") {
|
|
153
|
+
activeSubscriptions.add(parsed.result);
|
|
154
|
+
const bufferedMessages = pendingSubscriptionMessages.get(parsed.result);
|
|
155
|
+
if (bufferedMessages !== undefined) {
|
|
156
|
+
pendingSubscriptionMessages.delete(parsed.result);
|
|
157
|
+
for (const bufferedMessage of bufferedMessages) {
|
|
158
|
+
onMessage(bufferedMessage);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const unsubId = pendingUnsubscribes.get(parsed.id);
|
|
163
|
+
if (unsubId !== undefined) {
|
|
164
|
+
activeSubscriptions.delete(unsubId);
|
|
165
|
+
pendingUnsubscribes.delete(parsed.id);
|
|
166
|
+
}
|
|
167
|
+
onMessage(normalizedText);
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
const params = parsed.params;
|
|
171
|
+
if (isJsonRecord(params) && typeof params.subscription === "string") {
|
|
172
|
+
if (activeSubscriptions.has(params.subscription)) {
|
|
173
|
+
onMessage(normalizedText);
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
const buffered = pendingSubscriptionMessages.get(params.subscription) ?? [];
|
|
177
|
+
buffered.push(normalizedText);
|
|
178
|
+
if (buffered.length > 32) {
|
|
179
|
+
buffered.splice(0, buffered.length - 32);
|
|
180
|
+
}
|
|
181
|
+
pendingSubscriptionMessages.set(params.subscription, buffered);
|
|
182
|
+
}
|
|
183
|
+
return false;
|
|
184
|
+
});
|
|
185
|
+
return {
|
|
186
|
+
send(message) {
|
|
187
|
+
const parsed = safeParseJson(message);
|
|
188
|
+
if (isJsonRecord(parsed) && typeof parsed.id === "string") {
|
|
189
|
+
pendingRequests.add(parsed.id);
|
|
190
|
+
if (typeof parsed.method === "string" &&
|
|
191
|
+
parsed.method.includes("unfollow") &&
|
|
192
|
+
Array.isArray(parsed.params) &&
|
|
193
|
+
typeof parsed.params[0] === "string") {
|
|
194
|
+
pendingUnsubscribes.set(parsed.id, parsed.params[0]);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (isJsonRecord(parsed) &&
|
|
198
|
+
typeof parsed.id === "string" &&
|
|
199
|
+
typeof parsed.method === "string") {
|
|
200
|
+
console.info(`[runtime-chain] mux send ${parsed.method}#${parsed.id}`);
|
|
201
|
+
}
|
|
202
|
+
chain.sendJsonRpc(message);
|
|
203
|
+
},
|
|
204
|
+
disconnect() {
|
|
205
|
+
unregister();
|
|
206
|
+
pendingRequests.clear();
|
|
207
|
+
activeSubscriptions.clear();
|
|
208
|
+
pendingSubscriptionMessages.clear();
|
|
209
|
+
pendingUnsubscribes.clear();
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
export class RuntimeChainBridge {
|
|
214
|
+
constructor(driver) {
|
|
215
|
+
this.driver = driver;
|
|
216
|
+
// Start above IDs used by internal WASM subscriptions (1=newHeads, 2=finalizedHeads).
|
|
217
|
+
this.nextRequestId = 100;
|
|
218
|
+
this.pendingRequests = new Map();
|
|
219
|
+
this.pendingSubscriptions = new Map();
|
|
220
|
+
this.activeSubscriptions = new Map();
|
|
221
|
+
}
|
|
222
|
+
registerInterceptor(chainName) {
|
|
223
|
+
this.driver.registerResponseInterceptor(chainName, (text) => this.handleResponse(chainName, text));
|
|
224
|
+
}
|
|
225
|
+
unregisterInterceptor(chainName) {
|
|
226
|
+
this.pruneStalePendingSubscriptions();
|
|
227
|
+
this.driver.unregisterResponseInterceptor(chainName);
|
|
228
|
+
const reason = `chain disconnected: ${chainName}`;
|
|
229
|
+
for (const [requestId, pending] of this.pendingRequests) {
|
|
230
|
+
if (pending.chainName === chainName) {
|
|
231
|
+
pending.reject(new Error(reason));
|
|
232
|
+
this.pendingRequests.delete(requestId);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
for (const pending of this.pendingSubscriptions.values()) {
|
|
236
|
+
if (pending.chainName === chainName && !pending.cancelled) {
|
|
237
|
+
pending.cancelled = true;
|
|
238
|
+
pending.cancelledAt = Date.now();
|
|
239
|
+
pending.onAbort(reason);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
for (const [subscriptionId, active] of this.activeSubscriptions) {
|
|
243
|
+
if (active.chainName === chainName) {
|
|
244
|
+
this.sendStopRequest(chainName, active.stopMethod, subscriptionId);
|
|
245
|
+
active.onAbort(reason);
|
|
246
|
+
this.activeSubscriptions.delete(subscriptionId);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
async sendRpc(chainName, method, paramsJson, options) {
|
|
251
|
+
const chain = this.requireChain(chainName);
|
|
252
|
+
const requestId = this.nextJsonRpcId();
|
|
253
|
+
const payload = buildJsonRpcRequest(requestId, method, paramsJson);
|
|
254
|
+
this.pruneStalePendingSubscriptions();
|
|
255
|
+
return await new Promise((resolve, reject) => {
|
|
256
|
+
const timeoutMs = options?.timeoutMs ?? null;
|
|
257
|
+
const timeoutHandle = timeoutMs != null
|
|
258
|
+
? setTimeout(() => {
|
|
259
|
+
this.pendingRequests.delete(requestId);
|
|
260
|
+
reject(new Error(`RPC timeout for ${method} on ${chainName} after ${timeoutMs}ms`));
|
|
261
|
+
}, timeoutMs)
|
|
262
|
+
: null;
|
|
263
|
+
const settleResolve = (jsonRpc) => {
|
|
264
|
+
if (timeoutHandle != null) {
|
|
265
|
+
clearTimeout(timeoutHandle);
|
|
266
|
+
}
|
|
267
|
+
resolve(jsonRpc);
|
|
268
|
+
};
|
|
269
|
+
const settleReject = (error) => {
|
|
270
|
+
if (timeoutHandle != null) {
|
|
271
|
+
clearTimeout(timeoutHandle);
|
|
272
|
+
}
|
|
273
|
+
reject(error);
|
|
274
|
+
};
|
|
275
|
+
this.pendingRequests.set(requestId, {
|
|
276
|
+
chainName,
|
|
277
|
+
resolve: settleResolve,
|
|
278
|
+
reject: settleReject,
|
|
279
|
+
});
|
|
280
|
+
try {
|
|
281
|
+
chain.sendJsonRpc(payload);
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
this.pendingRequests.delete(requestId);
|
|
285
|
+
settleReject(error instanceof Error ? error : new Error(String(error)));
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
startSubscription(chainName, method, paramsJson, onMessage, onAbort) {
|
|
290
|
+
const chain = this.requireChain(chainName);
|
|
291
|
+
const requestId = this.nextJsonRpcId();
|
|
292
|
+
const payload = buildJsonRpcRequest(requestId, method, paramsJson);
|
|
293
|
+
const token = Symbol(`${chainName}:${requestId}`);
|
|
294
|
+
const stopMethod = deriveAuditedStopMethod(method);
|
|
295
|
+
this.pruneStalePendingSubscriptions();
|
|
296
|
+
this.pendingSubscriptions.set(requestId, {
|
|
297
|
+
token,
|
|
298
|
+
chainName,
|
|
299
|
+
stopMethod,
|
|
300
|
+
cancelled: false,
|
|
301
|
+
cancelledAt: null,
|
|
302
|
+
onMessage,
|
|
303
|
+
onAbort,
|
|
304
|
+
});
|
|
305
|
+
console.info(`[runtime-chain] start subscription ${String(chainName)} ${method} request=${requestId}`);
|
|
306
|
+
try {
|
|
307
|
+
chain.sendJsonRpc(payload);
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
this.pendingSubscriptions.delete(requestId);
|
|
311
|
+
throw new Error(`failed to start subscription on ${chainName}`);
|
|
312
|
+
}
|
|
313
|
+
return () => {
|
|
314
|
+
const pending = this.pendingSubscriptions.get(requestId);
|
|
315
|
+
if (pending?.token === token) {
|
|
316
|
+
pending.cancelled = true;
|
|
317
|
+
pending.cancelledAt = Date.now();
|
|
318
|
+
}
|
|
319
|
+
for (const [subscriptionId, active] of this.activeSubscriptions) {
|
|
320
|
+
if (active.token === token) {
|
|
321
|
+
this.sendStopRequest(active.chainName, active.stopMethod, subscriptionId);
|
|
322
|
+
this.activeSubscriptions.delete(subscriptionId);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
handleResponse(chainName, text) {
|
|
328
|
+
this.pruneStalePendingSubscriptions();
|
|
329
|
+
const parsed = safeParseJson(text);
|
|
330
|
+
if (!isJsonRecord(parsed)) {
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
const requestId = parseJsonRpcId(parsed);
|
|
334
|
+
if (requestId !== null) {
|
|
335
|
+
const pending = this.pendingRequests.get(requestId);
|
|
336
|
+
if (pending) {
|
|
337
|
+
this.pendingRequests.delete(requestId);
|
|
338
|
+
console.info(`[runtime-chain] rpc response ${String(chainName)} request=${requestId} ${summarizeBridgePayload(text)}`);
|
|
339
|
+
pending.resolve(text);
|
|
340
|
+
return true;
|
|
341
|
+
}
|
|
342
|
+
const pendingSubscription = this.pendingSubscriptions.get(requestId);
|
|
343
|
+
if (pendingSubscription) {
|
|
344
|
+
this.pendingSubscriptions.delete(requestId);
|
|
345
|
+
const subscriptionId = parseSubscriptionStartResult(parsed);
|
|
346
|
+
console.info(`[runtime-chain] subscription ack ${String(chainName)} request=${requestId} subscription=${subscriptionId ?? "null"} ${summarizeBridgePayload(text)}`);
|
|
347
|
+
if (subscriptionId !== null) {
|
|
348
|
+
if (pendingSubscription.cancelled) {
|
|
349
|
+
this.sendStopRequest(chainName, pendingSubscription.stopMethod, subscriptionId);
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
this.activeSubscriptions.set(subscriptionId, {
|
|
353
|
+
token: pendingSubscription.token,
|
|
354
|
+
chainName,
|
|
355
|
+
stopMethod: pendingSubscription.stopMethod,
|
|
356
|
+
onMessage: pendingSubscription.onMessage,
|
|
357
|
+
onAbort: pendingSubscription.onAbort,
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
if (!pendingSubscription.cancelled) {
|
|
362
|
+
pendingSubscription.onMessage(text);
|
|
363
|
+
}
|
|
364
|
+
return true;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
const subscriptionId = parseSubscriptionNotificationId(parsed);
|
|
368
|
+
if (subscriptionId !== null) {
|
|
369
|
+
const active = this.activeSubscriptions.get(subscriptionId);
|
|
370
|
+
if (active) {
|
|
371
|
+
console.info(`[runtime-chain] subscription event ${String(chainName)} subscription=${subscriptionId} ${summarizeBridgePayload(text)}`);
|
|
372
|
+
active.onMessage(text);
|
|
373
|
+
return true;
|
|
374
|
+
}
|
|
375
|
+
console.warn(`[runtime-chain] dropped subscription event ${String(chainName)} subscription=${subscriptionId} ${summarizeBridgePayload(text)}`);
|
|
376
|
+
}
|
|
377
|
+
return false;
|
|
378
|
+
}
|
|
379
|
+
requireChain(chainName) {
|
|
380
|
+
const chain = this.driver.getParaChain(chainName);
|
|
381
|
+
if (chain === null) {
|
|
382
|
+
throw new Error(`chain not connected: ${chainName}`);
|
|
383
|
+
}
|
|
384
|
+
return chain;
|
|
385
|
+
}
|
|
386
|
+
nextJsonRpcId() {
|
|
387
|
+
const requestId = this.nextRequestId;
|
|
388
|
+
this.nextRequestId += 1;
|
|
389
|
+
return `host-sdk-${requestId}`;
|
|
390
|
+
}
|
|
391
|
+
pruneStalePendingSubscriptions(now = Date.now()) {
|
|
392
|
+
for (const [requestId, pending] of this.pendingSubscriptions) {
|
|
393
|
+
if (pending.cancelled &&
|
|
394
|
+
pending.cancelledAt !== null &&
|
|
395
|
+
now - pending.cancelledAt >= STALE_PENDING_SUBSCRIPTION_TTL_MS) {
|
|
396
|
+
this.pendingSubscriptions.delete(requestId);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
sendStopRequest(chainName, stopMethod, subscriptionId) {
|
|
401
|
+
if (stopMethod === null) {
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
const chain = this.driver.getParaChain(chainName);
|
|
405
|
+
if (chain === null) {
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
try {
|
|
409
|
+
chain.sendJsonRpc(buildJsonRpcRequest(this.nextJsonRpcId(), stopMethod, JSON.stringify([subscriptionId])));
|
|
410
|
+
}
|
|
411
|
+
catch {
|
|
412
|
+
// Best-effort cleanup only.
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
export class SmoldotRuntimeChainService {
|
|
417
|
+
constructor(driver, chainNames, hexEncode, hexDecode) {
|
|
418
|
+
this.driver = driver;
|
|
419
|
+
this.chainNames = chainNames;
|
|
420
|
+
this.hexEncode = hexEncode;
|
|
421
|
+
this.hexDecode = hexDecode;
|
|
422
|
+
this.routing = new Map();
|
|
423
|
+
this.multiplexers = new Map();
|
|
424
|
+
this.pendingConnect = new Map();
|
|
425
|
+
this.pendingReady = new Map();
|
|
426
|
+
this.nextRelayRequestId = 10000;
|
|
427
|
+
}
|
|
428
|
+
async connect(chainName) {
|
|
429
|
+
const existing = this.pendingConnect.get(chainName);
|
|
430
|
+
if (existing != null) {
|
|
431
|
+
await existing;
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
const connectPromise = (async () => {
|
|
435
|
+
this.multiplexers.get(chainName)?.dispose();
|
|
436
|
+
this.multiplexers.delete(chainName);
|
|
437
|
+
await this.driver.connect(chainName);
|
|
438
|
+
this.multiplexers.set(chainName, createResponseMultiplexer(this.driver, chainName));
|
|
439
|
+
// Fast-path: skip genesis hash RPC if known at compile time.
|
|
440
|
+
const knownHash = typeof this.driver.chainHandle.knownGenesisHash === "function"
|
|
441
|
+
? (this.driver.chainHandle.knownGenesisHash(chainName) ?? null)
|
|
442
|
+
: null;
|
|
443
|
+
if (knownHash !== null) {
|
|
444
|
+
for (const [existingHash, existingChain] of this.routing) {
|
|
445
|
+
if (existingChain === chainName) {
|
|
446
|
+
this.routing.delete(existingHash);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
this.routing.set(knownHash, chainName);
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
await this.refreshRouting([chainName]);
|
|
453
|
+
}
|
|
454
|
+
})().finally(() => {
|
|
455
|
+
this.pendingConnect.delete(chainName);
|
|
456
|
+
});
|
|
457
|
+
this.pendingConnect.set(chainName, connectPromise);
|
|
458
|
+
await connectPromise;
|
|
459
|
+
}
|
|
460
|
+
waitUntilReady(chainName, options) {
|
|
461
|
+
const existing = this.pendingReady.get(chainName);
|
|
462
|
+
if (existing != null) {
|
|
463
|
+
return existing;
|
|
464
|
+
}
|
|
465
|
+
const readyPromise = this.waitUntilReadyInternal(chainName, options).finally(() => {
|
|
466
|
+
this.pendingReady.delete(chainName);
|
|
467
|
+
});
|
|
468
|
+
this.pendingReady.set(chainName, readyPromise);
|
|
469
|
+
return readyPromise;
|
|
470
|
+
}
|
|
471
|
+
async waitUntilReadyInternal(chainName, options) {
|
|
472
|
+
const timeoutMs = options?.timeoutMs ?? 120000;
|
|
473
|
+
const pollIntervalMs = options?.pollIntervalMs ?? 500;
|
|
474
|
+
const deadline = Date.now() + timeoutMs;
|
|
475
|
+
this.driver.persistState(chainName);
|
|
476
|
+
let relaySnapshotSaved = false;
|
|
477
|
+
while (Date.now() < deadline) {
|
|
478
|
+
const status = this.driver.chainHandle.status(chainName);
|
|
479
|
+
if (status.state === "Error") {
|
|
480
|
+
throw new Error(`chain ${chainName} entered error state: ${status.error ?? "unknown"}`);
|
|
481
|
+
}
|
|
482
|
+
if (status.state === "Disconnected") {
|
|
483
|
+
throw new Error(`chain ${chainName} is disconnected`);
|
|
484
|
+
}
|
|
485
|
+
const remainingMs = deadline - Date.now();
|
|
486
|
+
const rpcTimeoutMs = Math.max(1000, Math.min(remainingMs, pollIntervalMs * 8));
|
|
487
|
+
if (status.finalizedBlock !== null && status.finalizedBlock !== undefined) {
|
|
488
|
+
try {
|
|
489
|
+
await this.sendRpc(chainName, "chain_getFinalizedHead", "[]", {
|
|
490
|
+
timeoutMs: rpcTimeoutMs,
|
|
491
|
+
});
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
catch {
|
|
495
|
+
// The chain reports a finalized head, but the consumer-visible RPC path is still
|
|
496
|
+
// not usable. Keep polling until that path succeeds or the outer timeout expires.
|
|
497
|
+
}
|
|
498
|
+
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
499
|
+
continue;
|
|
500
|
+
}
|
|
501
|
+
if (!relaySnapshotSaved) {
|
|
502
|
+
try {
|
|
503
|
+
const relayResponse = await this.sendRelayRpc(chainName, "chainHead_unstable_finalizedDatabase", "[]", rpcTimeoutMs);
|
|
504
|
+
const relayDatabase = extractJsonRpcStringResult(relayResponse);
|
|
505
|
+
if (relayDatabase !== null) {
|
|
506
|
+
this.driver.chainHandle.processRelayResponse(chainName, buildStringResultResponse(RELAY_DB_SAVE_RESPONSE_ID, relayDatabase));
|
|
507
|
+
relaySnapshotSaved = true;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
catch {
|
|
511
|
+
// Keep polling until the relay finalized database is ready.
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
try {
|
|
515
|
+
const response = await this.sendRpc(chainName, "chainHead_unstable_finalizedDatabase", "[]", { timeoutMs: rpcTimeoutMs });
|
|
516
|
+
const databaseContent = extractJsonRpcStringResult(response);
|
|
517
|
+
if (databaseContent !== null && relaySnapshotSaved) {
|
|
518
|
+
this.driver.chainHandle.processResponse(chainName, buildStringResultResponse(PARA_DB_SAVE_RESPONSE_ID, databaseContent));
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
catch {
|
|
522
|
+
// Keep polling until the chain becomes query-ready or the outer timeout expires.
|
|
523
|
+
}
|
|
524
|
+
const refreshedStatus = this.driver.chainHandle.status(chainName);
|
|
525
|
+
if (refreshedStatus.finalizedBlock !== null && refreshedStatus.finalizedBlock !== undefined) {
|
|
526
|
+
try {
|
|
527
|
+
await this.sendRpc(chainName, "chain_getFinalizedHead", "[]", {
|
|
528
|
+
timeoutMs: rpcTimeoutMs,
|
|
529
|
+
});
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
catch {
|
|
533
|
+
// Readiness must prove that ordinary bridged RPCs are usable, not just that the
|
|
534
|
+
// finalized snapshot path or status field has advanced.
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
538
|
+
}
|
|
539
|
+
throw new ChainReadinessTimeoutError(chainName, timeoutMs);
|
|
540
|
+
}
|
|
541
|
+
async sendRelayRpc(chainName, method, paramsJson, timeoutMs) {
|
|
542
|
+
const relay = this.driver.getRelayChain(chainName);
|
|
543
|
+
if (relay === null) {
|
|
544
|
+
throw new Error(`relay chain not connected: ${chainName}`);
|
|
545
|
+
}
|
|
546
|
+
const requestId = String(this.nextRelayRequestId);
|
|
547
|
+
this.nextRelayRequestId += 1;
|
|
548
|
+
const payload = buildJsonRpcRequest(requestId, method, paramsJson);
|
|
549
|
+
return await new Promise((resolve, reject) => {
|
|
550
|
+
const cleanup = () => {
|
|
551
|
+
this.driver.unregisterRelayResponseInterceptor(chainName);
|
|
552
|
+
clearTimeout(timer);
|
|
553
|
+
};
|
|
554
|
+
const timer = setTimeout(() => {
|
|
555
|
+
cleanup();
|
|
556
|
+
reject(new Error(`RPC timeout for ${method} on relay ${chainName} after ${timeoutMs}ms`));
|
|
557
|
+
}, timeoutMs);
|
|
558
|
+
this.driver.registerRelayResponseInterceptor(chainName, (text) => {
|
|
559
|
+
const parsed = safeParseJson(text);
|
|
560
|
+
if (!isJsonRecord(parsed) || parseJsonRpcId(parsed) !== requestId) {
|
|
561
|
+
return false;
|
|
562
|
+
}
|
|
563
|
+
cleanup();
|
|
564
|
+
resolve(text);
|
|
565
|
+
return true;
|
|
566
|
+
});
|
|
567
|
+
try {
|
|
568
|
+
relay.sendJsonRpc(payload);
|
|
569
|
+
}
|
|
570
|
+
catch (error) {
|
|
571
|
+
cleanup();
|
|
572
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
setBootDiagnostics(chainName, callback) {
|
|
577
|
+
this.driver.setBootDiagnostics(chainName, callback);
|
|
578
|
+
}
|
|
579
|
+
persistState(chainNames = this.chainNames) {
|
|
580
|
+
for (const chainName of chainNames) {
|
|
581
|
+
this.driver.persistState(chainName);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
disconnect(chainName) {
|
|
585
|
+
this.multiplexers.get(chainName)?.dispose();
|
|
586
|
+
this.multiplexers.delete(chainName);
|
|
587
|
+
this.driver.disconnect(chainName);
|
|
588
|
+
for (const [genesisHash, currentChain] of this.routing) {
|
|
589
|
+
if (currentChain === chainName) {
|
|
590
|
+
this.routing.delete(genesisHash);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
statuses() {
|
|
595
|
+
return this.driver.allStatuses();
|
|
596
|
+
}
|
|
597
|
+
async refreshRouting(chainNames = this.chainNames) {
|
|
598
|
+
for (const chainName of chainNames) {
|
|
599
|
+
let nextHash = null;
|
|
600
|
+
try {
|
|
601
|
+
const response = await this.sendRpc(chainName, "chainSpec_v1_genesisHash", "[]");
|
|
602
|
+
const genesisHash = parseGenesisHashResult(response, this.hexDecode);
|
|
603
|
+
if (genesisHash !== null) {
|
|
604
|
+
nextHash = this.hexEncode(genesisHash);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
catch {
|
|
608
|
+
// Ignore disconnected or not-yet-live chains.
|
|
609
|
+
}
|
|
610
|
+
for (const [existingHash, existingChain] of this.routing) {
|
|
611
|
+
if (existingChain === chainName && existingHash !== nextHash) {
|
|
612
|
+
this.routing.delete(existingHash);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
if (nextHash !== null) {
|
|
616
|
+
this.routing.set(nextHash, chainName);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
return new Map(this.routing);
|
|
620
|
+
}
|
|
621
|
+
routingTable() {
|
|
622
|
+
return new Map(this.routing);
|
|
623
|
+
}
|
|
624
|
+
supportedGenesisHashes() {
|
|
625
|
+
return [...this.routing.keys()].map((genesisHash) => this.hexDecode(genesisHash));
|
|
626
|
+
}
|
|
627
|
+
routeChainByGenesisHash(genesisHash) {
|
|
628
|
+
return this.routing.get(this.hexEncode(genesisHash)) ?? null;
|
|
629
|
+
}
|
|
630
|
+
sendRpc(chainName, method, paramsJson, options) {
|
|
631
|
+
const requestId = `host-sdk-rpc-${crypto.randomUUID()}`;
|
|
632
|
+
return new Promise((resolve, reject) => {
|
|
633
|
+
let settled = false;
|
|
634
|
+
const timeoutHandle = options?.timeoutMs != null
|
|
635
|
+
? setTimeout(() => {
|
|
636
|
+
if (settled) {
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
settled = true;
|
|
640
|
+
rpcConnection.disconnect();
|
|
641
|
+
reject(new Error(`RPC timeout for ${method} on ${chainName} after ${options.timeoutMs}ms`));
|
|
642
|
+
}, options.timeoutMs)
|
|
643
|
+
: null;
|
|
644
|
+
const onMessage = (message) => {
|
|
645
|
+
const parsed = safeParseJson(message);
|
|
646
|
+
if (!isJsonRecord(parsed) || parsed.id !== requestId || settled) {
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
settled = true;
|
|
650
|
+
if (timeoutHandle != null) {
|
|
651
|
+
clearTimeout(timeoutHandle);
|
|
652
|
+
}
|
|
653
|
+
rpcConnection.disconnect();
|
|
654
|
+
console.info(`[runtime-chain] rpc response ${String(chainName)} request=${requestId} ${summarizeBridgePayload(message)}`);
|
|
655
|
+
if (isJsonRecord(parsed.error)) {
|
|
656
|
+
reject(new Error(typeof parsed.error.message === "string"
|
|
657
|
+
? parsed.error.message
|
|
658
|
+
: "unknown json-rpc error"));
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
resolve(message);
|
|
662
|
+
};
|
|
663
|
+
const rpcConnection = this.openConnection(chainName, onMessage);
|
|
664
|
+
try {
|
|
665
|
+
console.info(`[runtime-chain] rpc send ${String(chainName)} request=${requestId} method=${method}`);
|
|
666
|
+
rpcConnection.send(JSON.stringify({
|
|
667
|
+
jsonrpc: "2.0",
|
|
668
|
+
id: requestId,
|
|
669
|
+
method,
|
|
670
|
+
params: JSON.parse(paramsJson),
|
|
671
|
+
}));
|
|
672
|
+
}
|
|
673
|
+
catch (error) {
|
|
674
|
+
settled = true;
|
|
675
|
+
if (timeoutHandle != null) {
|
|
676
|
+
clearTimeout(timeoutHandle);
|
|
677
|
+
}
|
|
678
|
+
rpcConnection.disconnect();
|
|
679
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
680
|
+
}
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
startSubscription(chainName, method, paramsJson, onMessage, onAbort) {
|
|
684
|
+
const requestId = `host-sdk-sub-${crypto.randomUUID()}`;
|
|
685
|
+
let stopped = false;
|
|
686
|
+
let subscriptionId = null;
|
|
687
|
+
console.info(`[runtime-chain] start subscription ${String(chainName)} ${method} request=${requestId}`);
|
|
688
|
+
const connection = this.openConnection(chainName, (message) => {
|
|
689
|
+
const parsed = safeParseJson(message);
|
|
690
|
+
if (!isJsonRecord(parsed)) {
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
if (parsed.id === requestId) {
|
|
694
|
+
if (typeof parsed.result === "string" && parsed.result !== "") {
|
|
695
|
+
subscriptionId = parsed.result;
|
|
696
|
+
console.info(`[runtime-chain] subscription ack ${String(chainName)} request=${requestId} subscription=${subscriptionId} ${summarizeBridgePayload(message)}`);
|
|
697
|
+
onMessage(message);
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
connection.disconnect();
|
|
701
|
+
onAbort(isJsonRecord(parsed.error) && typeof parsed.error.message === "string"
|
|
702
|
+
? parsed.error.message
|
|
703
|
+
: "subscription start failed");
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
if (subscriptionId !== null &&
|
|
707
|
+
isJsonRecord(parsed.params) &&
|
|
708
|
+
parsed.params.subscription === subscriptionId) {
|
|
709
|
+
console.info(`[runtime-chain] subscription event ${String(chainName)} subscription=${subscriptionId} ${summarizeBridgePayload(message)}`);
|
|
710
|
+
onMessage(message);
|
|
711
|
+
}
|
|
712
|
+
});
|
|
713
|
+
try {
|
|
714
|
+
connection.send(JSON.stringify({
|
|
715
|
+
jsonrpc: "2.0",
|
|
716
|
+
id: requestId,
|
|
717
|
+
method,
|
|
718
|
+
params: JSON.parse(paramsJson),
|
|
719
|
+
}));
|
|
720
|
+
}
|
|
721
|
+
catch (error) {
|
|
722
|
+
connection.disconnect();
|
|
723
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
724
|
+
}
|
|
725
|
+
return () => {
|
|
726
|
+
if (stopped) {
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
stopped = true;
|
|
730
|
+
if (subscriptionId !== null) {
|
|
731
|
+
const stopMethod = deriveAuditedStopMethod(method);
|
|
732
|
+
if (stopMethod !== null) {
|
|
733
|
+
try {
|
|
734
|
+
connection.send(JSON.stringify({
|
|
735
|
+
jsonrpc: "2.0",
|
|
736
|
+
id: `host-sdk-unsub-${crypto.randomUUID()}`,
|
|
737
|
+
method: stopMethod,
|
|
738
|
+
params: [subscriptionId],
|
|
739
|
+
}));
|
|
740
|
+
}
|
|
741
|
+
catch {
|
|
742
|
+
// Best-effort cleanup only.
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
connection.disconnect();
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
destroy() {
|
|
750
|
+
for (const multiplexer of this.multiplexers.values()) {
|
|
751
|
+
multiplexer.dispose();
|
|
752
|
+
}
|
|
753
|
+
this.multiplexers.clear();
|
|
754
|
+
return this.driver.destroy();
|
|
755
|
+
}
|
|
756
|
+
openConnection(chainName, onMessage) {
|
|
757
|
+
const multiplexer = this.multiplexers.get(chainName);
|
|
758
|
+
if (multiplexer == null) {
|
|
759
|
+
throw new Error(`chain not connected: ${chainName}`);
|
|
760
|
+
}
|
|
761
|
+
const chain = this.driver.getParaChain(chainName);
|
|
762
|
+
if (chain == null) {
|
|
763
|
+
throw new Error(`chain not connected: ${chainName}`);
|
|
764
|
+
}
|
|
765
|
+
return createBridgedConnection(multiplexer, chain, onMessage);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
export function createSmoldotRuntimeChainService(options) {
|
|
769
|
+
const driver = new SmoldotDriver(options.sdk.chainClient, options.smoldotClient);
|
|
770
|
+
return new SmoldotRuntimeChainService(driver, options.chainNames, options.sdk.hexEncode.bind(options.sdk), options.sdk.hexDecode.bind(options.sdk));
|
|
771
|
+
}
|
|
772
|
+
function deriveAuditedStopMethod(method) {
|
|
773
|
+
return AUDITED_SUBSCRIPTION_STOP_METHODS[method] ?? null;
|
|
774
|
+
}
|
|
775
|
+
function buildJsonRpcRequest(id, method, paramsJson) {
|
|
776
|
+
const params = safeParseJson(paramsJson);
|
|
777
|
+
if (params === null) {
|
|
778
|
+
throw new Error("invalid params JSON");
|
|
779
|
+
}
|
|
780
|
+
return JSON.stringify({
|
|
781
|
+
jsonrpc: "2.0",
|
|
782
|
+
id,
|
|
783
|
+
method,
|
|
784
|
+
params,
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
function safeParseJson(text) {
|
|
788
|
+
try {
|
|
789
|
+
return JSON.parse(text);
|
|
790
|
+
}
|
|
791
|
+
catch {
|
|
792
|
+
return null;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
function isJsonRecord(value) {
|
|
796
|
+
return typeof value === "object" && value !== null;
|
|
797
|
+
}
|
|
798
|
+
function parseJsonRpcId(value) {
|
|
799
|
+
const id = value.id;
|
|
800
|
+
if (typeof id === "number") {
|
|
801
|
+
return String(id);
|
|
802
|
+
}
|
|
803
|
+
if (typeof id === "string" && id !== "") {
|
|
804
|
+
return id;
|
|
805
|
+
}
|
|
806
|
+
return null;
|
|
807
|
+
}
|
|
808
|
+
function parseSubscriptionStartResult(value) {
|
|
809
|
+
const result = value.result;
|
|
810
|
+
return typeof result === "string" ? result : null;
|
|
811
|
+
}
|
|
812
|
+
function parseSubscriptionNotificationId(value) {
|
|
813
|
+
const params = value.params;
|
|
814
|
+
if (!isJsonRecord(params)) {
|
|
815
|
+
return null;
|
|
816
|
+
}
|
|
817
|
+
const subscription = params.subscription;
|
|
818
|
+
return typeof subscription === "string" ? subscription : null;
|
|
819
|
+
}
|
|
820
|
+
function parseGenesisHashResult(response, hexDecode) {
|
|
821
|
+
const parsed = safeParseJson(response);
|
|
822
|
+
if (!isJsonRecord(parsed)) {
|
|
823
|
+
return null;
|
|
824
|
+
}
|
|
825
|
+
const result = parsed.result;
|
|
826
|
+
if (typeof result !== "string") {
|
|
827
|
+
return null;
|
|
828
|
+
}
|
|
829
|
+
try {
|
|
830
|
+
return hexDecode(result);
|
|
831
|
+
}
|
|
832
|
+
catch {
|
|
833
|
+
return null;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
function extractJsonRpcStringResult(response) {
|
|
837
|
+
const parsed = safeParseJson(response);
|
|
838
|
+
if (!isJsonRecord(parsed)) {
|
|
839
|
+
return null;
|
|
840
|
+
}
|
|
841
|
+
return typeof parsed.result === "string" && parsed.result.length > 0 ? parsed.result : null;
|
|
842
|
+
}
|
|
843
|
+
function buildStringResultResponse(id, result) {
|
|
844
|
+
return `{"jsonrpc":"2.0","id":${id},"result":${JSON.stringify(result)}}`;
|
|
845
|
+
}
|
|
846
|
+
//# sourceMappingURL=runtime-chain-service.js.map
|