space-data-module-sdk 0.8.3 → 0.8.5
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/README.md +117 -20
- package/bin/space-data-module.js +263 -0
- package/docs/.nojekyll +1 -0
- package/docs/AGENTS.md +34 -0
- package/docs/architecture.svg +141 -0
- package/docs/browser-wasmedge-isomorphic.md +179 -0
- package/docs/flatsql-streaming-standard.md +341 -0
- package/docs/gpu-module-abi.md +193 -0
- package/docs/index.html +125 -0
- package/docs/isomorphic-pthreads.md +188 -0
- package/docs/isomorphic-sdn-runtime-plan.md +167 -0
- package/docs/language-runtime-matrix.md +82 -0
- package/docs/manifest-structure.svg +114 -0
- package/docs/module-bundle-runtime-plan.md +19 -0
- package/docs/module-lifecycle.svg +70 -0
- package/docs/module-publication-standard.md +540 -0
- package/docs/node-red-default-node-parity.md +88 -0
- package/docs/protocol-installation.md +196 -0
- package/docs/secrets-capability.md +152 -0
- package/docs/styles.css +288 -0
- package/docs/testing-harness.md +408 -0
- package/docs/tri-runtime-parity.md +132 -0
- package/docs/wallet-callback.html +2 -0
- package/package.json +26 -6
- package/schemas/HttpRequestAbi.fbs +41 -0
- package/schemas/HttpResponseAbi.fbs +36 -0
- package/schemas/PluginManifest.fbs +2 -1
- package/src/AGENTS.md +1 -1
- package/src/app/codec.js +548 -0
- package/src/app/index.js +6 -0
- package/src/browser.js +5 -0
- package/src/bundle/constants.js +1 -0
- package/src/bundle/index.js +15 -0
- package/src/bundle/sigdomain.js +179 -0
- package/src/bundle/signing.js +767 -0
- package/src/bundle/wasm.js +3 -2
- package/src/capabilities.js +3 -0
- package/src/compat/index.js +7 -0
- package/src/compat/sdnLegacy.js +449 -0
- package/src/compiler/compileModule.js +556 -55
- package/src/compiler/flatcSupport.js +41 -27
- package/src/compiler/index.d.ts +2 -0
- package/src/compiler/index.js +18 -0
- package/src/compiler/invokeGlue.js +1212 -183
- package/src/compiler/pthreadArtifactGuard.js +910 -0
- package/src/compiler/sdnShimGenerator.js +323 -0
- package/src/compiler/wasiThreadsToolchain.js +150 -0
- package/src/compliance/index.js +11 -1
- package/src/compliance/legacyWildcardPorts.js +228 -0
- package/src/compliance/pluginCompliance.js +1000 -96
- package/src/field-stream/index.d.ts +31 -0
- package/src/field-stream/index.js +119 -0
- package/src/flow/dependencyStreamBridge.js +234 -0
- package/src/flow/flatsqlLinkShim.js +304 -0
- package/src/flow/flowCodec.js +107 -0
- package/src/flow/flowCompiler.js +2900 -0
- package/src/flow/flowRuntimeHost.js +877 -0
- package/src/flow/index.d.ts +117 -0
- package/src/flow/index.js +31 -0
- package/src/flow/isomorphicFlowHost.js +384 -0
- package/src/flow/jsFlowRuntime.js +275 -0
- package/src/flow/normalize.js +294 -0
- package/src/flow/runtime-src/flow_runtime.cpp +1699 -0
- package/src/flow/vendor/sdn-flow/MethodRegistry.js +400 -0
- package/src/flow/vendor/sdn-flow/constants.js +39 -0
- package/src/flow/vendor/sdn-flow/index.js +29 -0
- package/src/flow/vendor/sdn-flow/normalize.js +506 -0
- package/src/flow/vendor/sdn-flow/wasmCompatibility.js +189 -0
- package/src/generated/http/cpp/HttpRequestAbi_generated.h +285 -0
- package/src/generated/http/cpp/HttpResponseAbi_generated.h +192 -0
- package/src/generated/http/sdn/http/http-header.js +53 -0
- package/src/generated/http/sdn/http/http-header.ts +67 -0
- package/src/generated/http/sdn/http/http-request.js +132 -0
- package/src/generated/http/sdn/http/http-request.ts +179 -0
- package/src/generated/http/sdn/http/http-response.js +144 -0
- package/src/generated/http/sdn/http/http-response.ts +168 -0
- package/src/generated/http/sdn/http.js +11 -0
- package/src/generated/http/sdn/http.ts +4 -0
- package/src/generated/orbpro/flow/backpressure-policy.d.ts +12 -0
- package/src/generated/orbpro/flow/backpressure-policy.d.ts.map +1 -0
- package/src/generated/orbpro/flow/backpressure-policy.js +17 -0
- package/src/generated/orbpro/flow/backpressure-policy.js.map +1 -0
- package/src/generated/orbpro/flow/backpressure-policy.ts +15 -0
- package/src/generated/orbpro/flow/flow-bundle-manifest.d.ts +142 -0
- package/src/generated/orbpro/flow/flow-bundle-manifest.d.ts.map +1 -0
- package/src/generated/orbpro/flow/flow-bundle-manifest.js +304 -0
- package/src/generated/orbpro/flow/flow-bundle-manifest.js.map +1 -0
- package/src/generated/orbpro/flow/flow-bundle-manifest.ts +399 -0
- package/src/generated/orbpro/flow/flow-edge.d.ts +113 -0
- package/src/generated/orbpro/flow/flow-edge.d.ts.map +1 -0
- package/src/generated/orbpro/flow/flow-edge.js +221 -0
- package/src/generated/orbpro/flow/flow-edge.js.map +1 -0
- package/src/generated/orbpro/flow/flow-edge.ts +292 -0
- package/src/generated/orbpro/flow/flow-node.d.ts +80 -0
- package/src/generated/orbpro/flow/flow-node.d.ts.map +1 -0
- package/src/generated/orbpro/flow/flow-node.js +158 -0
- package/src/generated/orbpro/flow/flow-node.js.map +1 -0
- package/src/generated/orbpro/flow/flow-node.ts +202 -0
- package/src/generated/orbpro/flow/flow-program.d.ts +164 -0
- package/src/generated/orbpro/flow/flow-program.d.ts.map +1 -0
- package/src/generated/orbpro/flow/flow-program.js +350 -0
- package/src/generated/orbpro/flow/flow-program.js.map +1 -0
- package/src/generated/orbpro/flow/flow-program.ts +477 -0
- package/src/generated/orbpro/flow/flow-trigger.d.ts +108 -0
- package/src/generated/orbpro/flow/flow-trigger.d.ts.map +1 -0
- package/src/generated/orbpro/flow/flow-trigger.js +207 -0
- package/src/generated/orbpro/flow/flow-trigger.js.map +1 -0
- package/src/generated/orbpro/flow/flow-trigger.ts +276 -0
- package/src/generated/orbpro/flow/node-kind.d.ts +13 -0
- package/src/generated/orbpro/flow/node-kind.d.ts.map +1 -0
- package/src/generated/orbpro/flow/node-kind.js +16 -0
- package/src/generated/orbpro/flow/node-kind.js.map +1 -0
- package/src/generated/orbpro/{invoke.ts → flow/node-kind.ts} +12 -2
- package/src/generated/orbpro/flow/plugin-version-binding.d.ts +52 -0
- package/src/generated/orbpro/flow/plugin-version-binding.d.ts.map +1 -0
- package/src/generated/orbpro/flow/plugin-version-binding.js +85 -0
- package/src/generated/orbpro/flow/plugin-version-binding.js.map +1 -0
- package/src/generated/orbpro/flow/plugin-version-binding.ts +121 -0
- package/src/generated/orbpro/flow/schema-hash-binding.d.ts +70 -0
- package/src/generated/orbpro/flow/schema-hash-binding.d.ts.map +1 -0
- package/src/generated/orbpro/flow/schema-hash-binding.js +143 -0
- package/src/generated/orbpro/flow/schema-hash-binding.js.map +1 -0
- package/src/generated/orbpro/flow/schema-hash-binding.ts +189 -0
- package/src/generated/orbpro/flow/trigger-binding.d.ts +71 -0
- package/src/generated/orbpro/flow/trigger-binding.d.ts.map +1 -0
- package/src/generated/orbpro/flow/trigger-binding.js +142 -0
- package/src/generated/orbpro/flow/trigger-binding.js.map +1 -0
- package/src/generated/orbpro/flow/trigger-binding.ts +181 -0
- package/src/generated/orbpro/flow/trigger-kind.d.ts +14 -0
- package/src/generated/orbpro/flow/trigger-kind.d.ts.map +1 -0
- package/src/generated/orbpro/flow/trigger-kind.js +17 -0
- package/src/generated/orbpro/flow/trigger-kind.js.map +1 -0
- package/src/generated/orbpro/flow/trigger-kind.ts +17 -0
- package/src/generated/orbpro/flow.d.ts +21 -0
- package/src/generated/orbpro/flow.d.ts.map +1 -0
- package/src/generated/orbpro/flow.js +23 -0
- package/src/generated/orbpro/flow.js.map +1 -0
- package/src/generated/orbpro/flow.ts +24 -0
- package/src/generated/orbpro/manifest/capability-kind.d.ts +2 -1
- package/src/generated/orbpro/manifest/capability-kind.js +1 -0
- package/src/generated/orbpro/manifest/capability-kind.ts +1 -0
- package/src/generated/orbpro/plugin/stream-invoke-request.d.ts +93 -0
- package/src/generated/orbpro/plugin/stream-invoke-request.js +160 -0
- package/src/generated/orbpro/plugin/stream-invoke-request.ts +211 -0
- package/src/generated/orbpro/plugin/stream-invoke-response.d.ts +99 -0
- package/src/generated/orbpro/plugin/stream-invoke-response.js +175 -0
- package/src/generated/orbpro/plugin/stream-invoke-response.ts +226 -0
- package/src/generated/orbpro/plugin.js +8 -0
- package/src/generated/orbpro/stream.d.ts +12 -0
- package/src/generated/orbpro/stream.js +14 -0
- package/src/generated/orbpro/stream.ts +15 -0
- package/src/generated/spacedatastandards/plg/EntryFunction.d.ts +52 -0
- package/src/generated/spacedatastandards/plg/EntryFunction.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/EntryFunction.js +106 -0
- package/src/generated/spacedatastandards/plg/EntryFunction.ts +162 -0
- package/src/generated/spacedatastandards/plg/FlatBufferTypeRef.d.ts +90 -0
- package/src/generated/spacedatastandards/plg/FlatBufferTypeRef.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/FlatBufferTypeRef.js +189 -0
- package/src/generated/spacedatastandards/plg/FlatBufferTypeRef.ts +270 -0
- package/src/generated/spacedatastandards/plg/PLG.d.ts +492 -0
- package/src/generated/spacedatastandards/plg/PLG.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLG.js +1139 -0
- package/src/generated/spacedatastandards/plg/PLG.ts +1600 -0
- package/src/generated/spacedatastandards/plg/PLGAcceptedTypeSet.d.ts +63 -0
- package/src/generated/spacedatastandards/plg/PLGAcceptedTypeSet.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGAcceptedTypeSet.js +138 -0
- package/src/generated/spacedatastandards/plg/PLGAcceptedTypeSet.ts +189 -0
- package/src/generated/spacedatastandards/plg/PLGBuildArtifact.d.ts +41 -0
- package/src/generated/spacedatastandards/plg/PLGBuildArtifact.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGBuildArtifact.js +104 -0
- package/src/generated/spacedatastandards/plg/PLGBuildArtifact.ts +151 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdge.d.ts +68 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdge.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdge.js +124 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdge.ts +184 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdgeContract.d.ts +58 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdgeContract.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdgeContract.js +126 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdgeContract.ts +161 -0
- package/src/generated/spacedatastandards/plg/PLGFlowNode.d.ts +82 -0
- package/src/generated/spacedatastandards/plg/PLGFlowNode.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGFlowNode.js +164 -0
- package/src/generated/spacedatastandards/plg/PLGFlowNode.ts +244 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTrigger.d.ts +55 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTrigger.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTrigger.js +105 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTrigger.ts +162 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTriggerBinding.d.ts +42 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTriggerBinding.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTriggerBinding.js +83 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTriggerBinding.ts +127 -0
- package/src/generated/spacedatastandards/plg/PLGHostCapability.d.ts +36 -0
- package/src/generated/spacedatastandards/plg/PLGHostCapability.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGHostCapability.js +90 -0
- package/src/generated/spacedatastandards/plg/PLGHostCapability.ts +127 -0
- package/src/generated/spacedatastandards/plg/PLGMethodManifest.d.ts +53 -0
- package/src/generated/spacedatastandards/plg/PLGMethodManifest.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGMethodManifest.js +153 -0
- package/src/generated/spacedatastandards/plg/PLGMethodManifest.ts +210 -0
- package/src/generated/spacedatastandards/plg/PLGPortManifest.d.ts +70 -0
- package/src/generated/spacedatastandards/plg/PLGPortManifest.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGPortManifest.js +149 -0
- package/src/generated/spacedatastandards/plg/PLGPortManifest.ts +212 -0
- package/src/generated/spacedatastandards/plg/PLGProtocolSpec.d.ts +73 -0
- package/src/generated/spacedatastandards/plg/PLGProtocolSpec.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGProtocolSpec.js +199 -0
- package/src/generated/spacedatastandards/plg/PLGProtocolSpec.ts +292 -0
- package/src/generated/spacedatastandards/plg/PLGTimerSpec.d.ts +40 -0
- package/src/generated/spacedatastandards/plg/PLGTimerSpec.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGTimerSpec.js +103 -0
- package/src/generated/spacedatastandards/plg/PLGTimerSpec.ts +148 -0
- package/src/generated/spacedatastandards/plg/PluginCapability.d.ts +41 -0
- package/src/generated/spacedatastandards/plg/PluginCapability.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PluginCapability.js +82 -0
- package/src/generated/spacedatastandards/plg/{plugin-capability.ts → PluginCapability.ts} +55 -18
- package/src/generated/spacedatastandards/plg/PluginDependency.d.ts +42 -0
- package/src/generated/spacedatastandards/plg/PluginDependency.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PluginDependency.js +80 -0
- package/src/generated/spacedatastandards/plg/PluginDependency.ts +124 -0
- package/src/generated/spacedatastandards/plg/TAB.d.ts +85 -0
- package/src/generated/spacedatastandards/plg/TAB.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/TAB.js +173 -0
- package/src/generated/spacedatastandards/plg/TAB.ts +228 -0
- package/src/generated/spacedatastandards/plg/bufferMutability.d.ts +18 -0
- package/src/generated/spacedatastandards/plg/bufferMutability.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/bufferMutability.js +20 -0
- package/src/generated/spacedatastandards/plg/bufferMutability.ts +23 -0
- package/src/generated/spacedatastandards/plg/bufferOwnership.d.ts +18 -0
- package/src/generated/spacedatastandards/plg/bufferOwnership.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/bufferOwnership.js +20 -0
- package/src/generated/spacedatastandards/plg/bufferOwnership.ts +23 -0
- package/src/generated/spacedatastandards/plg/drainBehavior.d.ts +20 -0
- package/src/generated/spacedatastandards/plg/drainBehavior.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/drainBehavior.js +22 -0
- package/src/generated/spacedatastandards/plg/drainBehavior.ts +25 -0
- package/src/generated/spacedatastandards/plg/flowEdgeRoutePolicy.d.ts +10 -0
- package/src/generated/spacedatastandards/plg/flowEdgeRoutePolicy.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/flowEdgeRoutePolicy.js +12 -0
- package/src/generated/spacedatastandards/plg/flowEdgeRoutePolicy.ts +13 -0
- package/src/generated/spacedatastandards/plg/hostCapabilityKind.d.ts +51 -0
- package/src/generated/spacedatastandards/plg/hostCapabilityKind.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/hostCapabilityKind.js +53 -0
- package/src/generated/spacedatastandards/plg/hostCapabilityKind.ts +55 -0
- package/src/generated/spacedatastandards/plg/invokeSurfaceKind.d.ts +15 -0
- package/src/generated/spacedatastandards/plg/invokeSurfaceKind.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/invokeSurfaceKind.js +17 -0
- package/src/generated/spacedatastandards/plg/invokeSurfaceKind.ts +19 -0
- package/src/generated/spacedatastandards/plg/main.d.ts +29 -0
- package/src/generated/spacedatastandards/plg/main.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/main.js +30 -0
- package/src/generated/spacedatastandards/plg/main.ts +32 -0
- package/src/generated/spacedatastandards/plg/payloadWireFormat.d.ts +17 -0
- package/src/generated/spacedatastandards/plg/payloadWireFormat.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/payloadWireFormat.js +19 -0
- package/src/generated/spacedatastandards/plg/payloadWireFormat.ts +21 -0
- package/src/generated/spacedatastandards/plg/pluginCategory.d.ts +82 -0
- package/src/generated/spacedatastandards/plg/pluginCategory.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/pluginCategory.js +84 -0
- package/src/generated/spacedatastandards/plg/pluginCategory.ts +103 -0
- package/src/generated/spacedatastandards/plg/publicationState.d.ts +18 -0
- package/src/generated/spacedatastandards/plg/publicationState.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/publicationState.js +20 -0
- package/src/generated/spacedatastandards/plg/purchaseTier.d.ts +18 -0
- package/src/generated/spacedatastandards/plg/purchaseTier.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/purchaseTier.js +20 -0
- package/src/host/AGENTS.md +2 -2
- package/src/host/abi.js +53 -66
- package/src/host/browserHost.js +355 -8
- package/src/host/cpp/keyslotClient.hpp +231 -0
- package/src/host/cpp/secretsClient.hpp +583 -0
- package/src/host/hostcallWire.js +183 -0
- package/src/host/index.js +2 -0
- package/src/host/isomorphicLoader.js +44 -7
- package/src/host/nodeHost.js +227 -8
- package/src/host/sabHostcallChannel.js +206 -0
- package/src/host/timerDriver.js +203 -0
- package/src/host/wasiShim.js +41 -1
- package/src/host/wasiThreadBrowserWorker.mjs +48 -0
- package/src/host/wasiThreadHost.js +393 -0
- package/src/host/wasiThreadWorker.mjs +32 -0
- package/src/host/wasiThreadWorkerRuntime.js +93 -0
- package/src/http/index.js +339 -0
- package/src/index.d.ts +716 -10
- package/src/index.js +4 -0
- package/src/invoke/codec.js +1202 -128
- package/src/invoke/index.js +5 -1
- package/src/licensing/index.d.ts +2 -0
- package/src/licensing/index.js +2 -0
- package/src/licensing/records.js +287 -8
- package/src/manifest/codec.js +62 -14
- package/src/manifest/index.js +2 -0
- package/src/manifest/legacyToPlg.js +164 -25
- package/src/manifest/normalize.js +1 -0
- package/src/manifest/plgCodec.js +1303 -62
- package/src/manifest/typeRefs.js +162 -24
- package/src/runtime/compiledRuntimeAbi.js +47 -0
- package/src/runtime/compiledRuntimeAbi.json +33 -0
- package/src/runtime/index.d.ts +32 -0
- package/src/runtime/index.js +1 -0
- package/src/runtime-host/index.js +3 -0
- package/src/runtime-host/methodRegistry.js +55 -0
- package/src/standards/index.js +200 -56
- package/src/standards/sharedCatalog.js +16 -0
- package/src/testing/browserModuleHarness.js +604 -31
- package/src/testing/docker/wasmedge-parity.Dockerfile +39 -0
- package/src/testing/index.d.ts +151 -0
- package/src/testing/index.js +21 -0
- package/src/testing/native/wasmedge_emscripten_pthread_runner.c +25 -1
- package/src/testing/parityBrowserRunner.js +138 -0
- package/src/testing/parityHarness.js +616 -0
- package/src/testing/parityLanes.js +537 -0
- package/src/testing/processInvoke.js +29 -21
- package/src/testing/streamInvokeCodec.js +10 -175
- package/src/testing/wasmedgePin.json +6 -0
- package/src/testing/workerModuleHarness.js +242 -0
- package/src/testing/workerModuleHarnessWorker.js +176 -0
- package/src/transport/index.js +3 -0
- package/src/transport/pki.js +299 -11
- package/src/transport/records.js +16 -7
- package/src/utils/ecdsaDer.js +106 -0
- package/src/utils/wasmCrypto.js +0 -43
- package/templates/gpu-module/README.md +48 -0
- package/templates/gpu-module/include/space_data_gpu_abi.h +122 -0
- package/templates/gpu-module/manifest.json +84 -0
- package/schemas/PluginInvokeRequest.fbs +0 -18
- package/schemas/PluginInvokeResponse.fbs +0 -30
- package/schemas/spacedatastandards/PLG.fbs +0 -191
- package/src/generated/orbpro/invoke/plugin-invoke-request.d.ts +0 -51
- package/src/generated/orbpro/invoke/plugin-invoke-request.d.ts.map +0 -1
- package/src/generated/orbpro/invoke/plugin-invoke-request.js +0 -131
- package/src/generated/orbpro/invoke/plugin-invoke-request.js.map +0 -1
- package/src/generated/orbpro/invoke/plugin-invoke-request.ts +0 -173
- package/src/generated/orbpro/invoke/plugin-invoke-response.d.ts +0 -76
- package/src/generated/orbpro/invoke/plugin-invoke-response.d.ts.map +0 -1
- package/src/generated/orbpro/invoke/plugin-invoke-response.js +0 -184
- package/src/generated/orbpro/invoke/plugin-invoke-response.js.map +0 -1
- package/src/generated/orbpro/invoke/plugin-invoke-response.ts +0 -243
- package/src/generated/orbpro/invoke.d.ts +0 -3
- package/src/generated/orbpro/invoke.js +0 -5
- package/src/generated/spacedatastandards/plg/entry-function.js +0 -86
- package/src/generated/spacedatastandards/plg/entry-function.ts +0 -119
- package/src/generated/spacedatastandards/plg/index.js +0 -16
- package/src/generated/spacedatastandards/plg/index.ts +0 -11
- package/src/generated/spacedatastandards/plg/plg.js +0 -657
- package/src/generated/spacedatastandards/plg/plg.ts +0 -924
- package/src/generated/spacedatastandards/plg/plugin-capability.js +0 -66
- package/src/generated/spacedatastandards/plg/plugin-category.js +0 -15
- package/src/generated/spacedatastandards/plg/plugin-category.ts +0 -53
- package/src/generated/spacedatastandards/plg/plugin-dependency.js +0 -63
- package/src/generated/spacedatastandards/plg/plugin-dependency.ts +0 -86
- package/src/generated/spacedatastandards/plg/publication-state.js +0 -9
- package/src/generated/spacedatastandards/plg/purchase-tier.js +0 -9
- /package/src/generated/spacedatastandards/plg/{publication-state.ts → publicationState.ts} +0 -0
- /package/src/generated/spacedatastandards/plg/{purchase-tier.ts → purchaseTier.ts} +0 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binary hostcall wire format.
|
|
3
|
+
*
|
|
4
|
+
* Replaces the JSON+base64 hostcall round-trip: binary payloads cross the
|
|
5
|
+
* host<->module boundary as raw length-prefixed segments, with a small JSON
|
|
6
|
+
* "meta" document carrying only control metadata. Byte values inside the
|
|
7
|
+
* meta document are represented as `{ "$bin": <segmentIndex> }` references.
|
|
8
|
+
*
|
|
9
|
+
* Envelope layout (little-endian):
|
|
10
|
+
* u32 metaLength
|
|
11
|
+
* u8[metaLength] meta JSON (UTF-8)
|
|
12
|
+
* u32 segmentCount
|
|
13
|
+
* repeat segmentCount times:
|
|
14
|
+
* u32 segmentLength
|
|
15
|
+
* u8[segmentLength] segment bytes
|
|
16
|
+
*
|
|
17
|
+
* The same envelope is used for hostcall requests (meta = params) and
|
|
18
|
+
* responses (meta = { ok, result } | { ok, error }).
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const textDecoder = new TextDecoder();
|
|
22
|
+
const textEncoder = new TextEncoder();
|
|
23
|
+
|
|
24
|
+
export const HOSTCALL_BINARY_REF_KEY = "$bin";
|
|
25
|
+
|
|
26
|
+
function isByteValue(value) {
|
|
27
|
+
return (
|
|
28
|
+
value instanceof Uint8Array ||
|
|
29
|
+
value instanceof ArrayBuffer ||
|
|
30
|
+
ArrayBuffer.isView(value)
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function toBytes(value) {
|
|
35
|
+
if (value instanceof Uint8Array) {
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
if (value instanceof ArrayBuffer) {
|
|
39
|
+
return new Uint8Array(value);
|
|
40
|
+
}
|
|
41
|
+
return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Walk a structured value, detaching binary leaves into `segments` and
|
|
46
|
+
* replacing them with `{ "$bin": index }` references. Dates become ISO
|
|
47
|
+
* strings and bigints become decimal strings (JSON-safe control metadata).
|
|
48
|
+
*/
|
|
49
|
+
export function detachBinaryValues(value, segments) {
|
|
50
|
+
if (value === undefined || value === null) {
|
|
51
|
+
return value ?? null;
|
|
52
|
+
}
|
|
53
|
+
if (isByteValue(value)) {
|
|
54
|
+
const index = segments.length;
|
|
55
|
+
segments.push(toBytes(value));
|
|
56
|
+
return { [HOSTCALL_BINARY_REF_KEY]: index };
|
|
57
|
+
}
|
|
58
|
+
if (value instanceof Date) {
|
|
59
|
+
return value.toISOString();
|
|
60
|
+
}
|
|
61
|
+
if (typeof value === "bigint") {
|
|
62
|
+
return value.toString();
|
|
63
|
+
}
|
|
64
|
+
if (Array.isArray(value)) {
|
|
65
|
+
return value.map((entry) => detachBinaryValues(entry, segments));
|
|
66
|
+
}
|
|
67
|
+
if (typeof value === "object") {
|
|
68
|
+
return Object.fromEntries(
|
|
69
|
+
Object.entries(value)
|
|
70
|
+
.filter(([, entry]) => entry !== undefined)
|
|
71
|
+
.map(([key, entry]) => [key, detachBinaryValues(entry, segments)]),
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
return value;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Inverse of detachBinaryValues: re-attach segment bytes wherever the meta
|
|
79
|
+
* document references them.
|
|
80
|
+
*/
|
|
81
|
+
export function attachBinaryValues(value, segments) {
|
|
82
|
+
if (value === null || value === undefined) {
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
if (Array.isArray(value)) {
|
|
86
|
+
return value.map((entry) => attachBinaryValues(entry, segments));
|
|
87
|
+
}
|
|
88
|
+
if (typeof value === "object") {
|
|
89
|
+
const keys = Object.keys(value);
|
|
90
|
+
if (keys.length === 1 && keys[0] === HOSTCALL_BINARY_REF_KEY) {
|
|
91
|
+
const index = value[HOSTCALL_BINARY_REF_KEY];
|
|
92
|
+
if (!Number.isInteger(index) || index < 0 || index >= segments.length) {
|
|
93
|
+
throw new RangeError(
|
|
94
|
+
`Hostcall envelope references missing binary segment ${index}.`,
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
return segments[index];
|
|
98
|
+
}
|
|
99
|
+
return Object.fromEntries(
|
|
100
|
+
keys.map((key) => [key, attachBinaryValues(value[key], segments)]),
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
return value;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function encodeHostcallEnvelope(meta, segments = []) {
|
|
107
|
+
const metaBytes = textEncoder.encode(JSON.stringify(meta ?? null));
|
|
108
|
+
let total = 4 + metaBytes.length + 4;
|
|
109
|
+
for (const segment of segments) {
|
|
110
|
+
total += 4 + segment.length;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const bytes = new Uint8Array(total);
|
|
114
|
+
const view = new DataView(bytes.buffer);
|
|
115
|
+
let offset = 0;
|
|
116
|
+
view.setUint32(offset, metaBytes.length, true);
|
|
117
|
+
offset += 4;
|
|
118
|
+
bytes.set(metaBytes, offset);
|
|
119
|
+
offset += metaBytes.length;
|
|
120
|
+
view.setUint32(offset, segments.length, true);
|
|
121
|
+
offset += 4;
|
|
122
|
+
for (const segment of segments) {
|
|
123
|
+
view.setUint32(offset, segment.length, true);
|
|
124
|
+
offset += 4;
|
|
125
|
+
bytes.set(segment, offset);
|
|
126
|
+
offset += segment.length;
|
|
127
|
+
}
|
|
128
|
+
return bytes;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function decodeHostcallEnvelope(bytes) {
|
|
132
|
+
if (!(bytes instanceof Uint8Array)) {
|
|
133
|
+
throw new TypeError("Hostcall envelope must be a Uint8Array.");
|
|
134
|
+
}
|
|
135
|
+
if (bytes.length < 8) {
|
|
136
|
+
throw new RangeError("Hostcall envelope is truncated.");
|
|
137
|
+
}
|
|
138
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
139
|
+
let offset = 0;
|
|
140
|
+
const metaLength = view.getUint32(offset, true);
|
|
141
|
+
offset += 4;
|
|
142
|
+
if (offset + metaLength + 4 > bytes.length) {
|
|
143
|
+
throw new RangeError("Hostcall envelope meta exceeds envelope bounds.");
|
|
144
|
+
}
|
|
145
|
+
const meta = JSON.parse(
|
|
146
|
+
textDecoder.decode(bytes.subarray(offset, offset + metaLength)),
|
|
147
|
+
);
|
|
148
|
+
offset += metaLength;
|
|
149
|
+
const segmentCount = view.getUint32(offset, true);
|
|
150
|
+
offset += 4;
|
|
151
|
+
const segments = [];
|
|
152
|
+
for (let index = 0; index < segmentCount; index += 1) {
|
|
153
|
+
if (offset + 4 > bytes.length) {
|
|
154
|
+
throw new RangeError("Hostcall envelope segment table is truncated.");
|
|
155
|
+
}
|
|
156
|
+
const segmentLength = view.getUint32(offset, true);
|
|
157
|
+
offset += 4;
|
|
158
|
+
if (offset + segmentLength > bytes.length) {
|
|
159
|
+
throw new RangeError("Hostcall envelope segment exceeds envelope bounds.");
|
|
160
|
+
}
|
|
161
|
+
segments.push(bytes.subarray(offset, offset + segmentLength));
|
|
162
|
+
offset += segmentLength;
|
|
163
|
+
}
|
|
164
|
+
return { meta, segments };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Encode a structured value (params or result) into an envelope, detaching
|
|
169
|
+
* binary leaves into segments.
|
|
170
|
+
*/
|
|
171
|
+
export function encodeHostcallValueEnvelope(value) {
|
|
172
|
+
const segments = [];
|
|
173
|
+
const meta = detachBinaryValues(value, segments);
|
|
174
|
+
return encodeHostcallEnvelope(meta, segments);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Decode an envelope back into a structured value with bytes re-attached.
|
|
179
|
+
*/
|
|
180
|
+
export function decodeHostcallValueEnvelope(bytes) {
|
|
181
|
+
const { meta, segments } = decodeHostcallEnvelope(bytes);
|
|
182
|
+
return attachBinaryValues(meta, segments);
|
|
183
|
+
}
|
package/src/host/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Unified entry point that detects the runtime environment and artifact
|
|
5
5
|
* profile, then loads the module through the appropriate path:
|
|
6
|
-
* - Browser: createBrowserModuleHarness (WASI shim + optional
|
|
6
|
+
* - Browser: createBrowserModuleHarness (WASI shim + optional space_data_module_host)
|
|
7
7
|
* - Node/WasmEdge: createModuleHarness (subprocess)
|
|
8
8
|
*
|
|
9
9
|
* The same compiled .wasm artifact works in both environments.
|
|
@@ -12,8 +12,13 @@
|
|
|
12
12
|
import {
|
|
13
13
|
createBrowserModuleHarness,
|
|
14
14
|
detectArtifactProfile,
|
|
15
|
+
toLoadableWasmBytes,
|
|
15
16
|
} from "../testing/browserModuleHarness.js";
|
|
16
17
|
import { createAsyncHostDispatcher } from "./abi.js";
|
|
18
|
+
import {
|
|
19
|
+
resolveModuleSignaturePolicy,
|
|
20
|
+
verifyModuleArtifact,
|
|
21
|
+
} from "../bundle/signing.js";
|
|
17
22
|
|
|
18
23
|
const isBrowser =
|
|
19
24
|
typeof globalThis.window !== "undefined" &&
|
|
@@ -54,7 +59,13 @@ async function createWasmEdgeCommandHarness(options = {}) {
|
|
|
54
59
|
const path = pathModule.default ?? pathModule;
|
|
55
60
|
const wasmPath = path.resolve(String(options.wasmSource));
|
|
56
61
|
const wasmBytes = await readFile(wasmPath);
|
|
57
|
-
|
|
62
|
+
// Signed/published artifacts carry an appended publication record
|
|
63
|
+
// collection that WasmEdge rejects ("malformed section id"). Strip to the
|
|
64
|
+
// canonical module payload; if anything was stripped, launch WasmEdge from
|
|
65
|
+
// a temp copy of the stripped bytes (signature verification, when
|
|
66
|
+
// requested, already ran against the full artifact in loadModule()).
|
|
67
|
+
const loadableBytes = toLoadableWasmBytes(wasmBytes);
|
|
68
|
+
const inspection = await inspectModule(loadableBytes);
|
|
58
69
|
|
|
59
70
|
if (!inspection.exports.includes(DefaultInvokeExports.commandSymbol)) {
|
|
60
71
|
throw new Error(
|
|
@@ -62,10 +73,23 @@ async function createWasmEdgeCommandHarness(options = {}) {
|
|
|
62
73
|
);
|
|
63
74
|
}
|
|
64
75
|
|
|
76
|
+
let launchWasmPath = wasmPath;
|
|
77
|
+
let tempArtifactDir = null;
|
|
78
|
+
if (loadableBytes.byteLength !== wasmBytes.byteLength) {
|
|
79
|
+
const [{ mkdtemp, writeFile }, osModule] = await Promise.all([
|
|
80
|
+
import("node:fs/promises"),
|
|
81
|
+
import("node:os"),
|
|
82
|
+
]);
|
|
83
|
+
const os = osModule.default ?? osModule;
|
|
84
|
+
tempArtifactDir = await mkdtemp(path.join(os.tmpdir(), "sdm-module-"));
|
|
85
|
+
launchWasmPath = path.join(tempArtifactDir, "module.wasm");
|
|
86
|
+
await writeFile(launchWasmPath, loadableBytes);
|
|
87
|
+
}
|
|
88
|
+
|
|
65
89
|
const command = options.wasmEdgeBinary ?? "wasmedge";
|
|
66
90
|
const args = [
|
|
67
91
|
...(options.enableThreads === false ? [] : ["--enable-threads"]),
|
|
68
|
-
|
|
92
|
+
launchWasmPath,
|
|
69
93
|
...(Array.isArray(options.args) ? options.args : []),
|
|
70
94
|
];
|
|
71
95
|
const launchPlan = {
|
|
@@ -73,7 +97,7 @@ async function createWasmEdgeCommandHarness(options = {}) {
|
|
|
73
97
|
args,
|
|
74
98
|
env: buildWasmEdgeSpawnEnv(options.env),
|
|
75
99
|
cwd: options.cwd ?? process.cwd(),
|
|
76
|
-
wasmPath,
|
|
100
|
+
wasmPath: launchWasmPath,
|
|
77
101
|
};
|
|
78
102
|
|
|
79
103
|
async function invokeRaw(requestBytes) {
|
|
@@ -146,7 +170,13 @@ async function createWasmEdgeCommandHarness(options = {}) {
|
|
|
146
170
|
readManifest() {
|
|
147
171
|
return null;
|
|
148
172
|
},
|
|
149
|
-
async destroy() {
|
|
173
|
+
async destroy() {
|
|
174
|
+
if (tempArtifactDir) {
|
|
175
|
+
const { rm } = await import("node:fs/promises");
|
|
176
|
+
await rm(tempArtifactDir, { recursive: true, force: true });
|
|
177
|
+
tempArtifactDir = null;
|
|
178
|
+
}
|
|
179
|
+
},
|
|
150
180
|
};
|
|
151
181
|
}
|
|
152
182
|
|
|
@@ -164,6 +194,7 @@ async function createWasmEdgeCommandHarness(options = {}) {
|
|
|
164
194
|
* @returns {Promise<Object>} Harness with invoke(), readManifest(), destroy().
|
|
165
195
|
*/
|
|
166
196
|
export async function loadModule(options = {}) {
|
|
197
|
+
const signaturePolicy = resolveModuleSignaturePolicy(options);
|
|
167
198
|
if (isBrowser) {
|
|
168
199
|
return createBrowserModuleHarness(options);
|
|
169
200
|
}
|
|
@@ -176,6 +207,11 @@ export async function loadModule(options = {}) {
|
|
|
176
207
|
);
|
|
177
208
|
}
|
|
178
209
|
|
|
210
|
+
if (signaturePolicy) {
|
|
211
|
+
const { readFile } = await import("node:fs/promises");
|
|
212
|
+
await verifyModuleArtifact(await readFile(source), signaturePolicy);
|
|
213
|
+
}
|
|
214
|
+
|
|
179
215
|
const runtimeKind = options.runtimeKind ?? "wasmedge";
|
|
180
216
|
if (runtimeKind === "wasmedge") {
|
|
181
217
|
const runtimeHostRequested =
|
|
@@ -187,7 +223,7 @@ export async function loadModule(options = {}) {
|
|
|
187
223
|
const { readFile } = await import("node:fs/promises");
|
|
188
224
|
const inspection = await inspectModule(await readFile(source));
|
|
189
225
|
if (
|
|
190
|
-
(inspection.profile === "standalone" || inspection.profile === "
|
|
226
|
+
(inspection.profile === "standalone" || inspection.profile === "module-host-abi") &&
|
|
191
227
|
inspection.exports.includes("_start")
|
|
192
228
|
) {
|
|
193
229
|
return attachHostDispatch(
|
|
@@ -247,7 +283,8 @@ export async function inspectModule(source) {
|
|
|
247
283
|
} else {
|
|
248
284
|
const bytes =
|
|
249
285
|
source instanceof ArrayBuffer ? new Uint8Array(source) : source;
|
|
250
|
-
|
|
286
|
+
// Tolerate signed/published artifacts (appended publication records).
|
|
287
|
+
wasmModule = await WebAssembly.compile(toLoadableWasmBytes(bytes));
|
|
251
288
|
}
|
|
252
289
|
|
|
253
290
|
const profile = detectArtifactProfile(wasmModule);
|
package/src/host/nodeHost.js
CHANGED
|
@@ -14,7 +14,12 @@ import {
|
|
|
14
14
|
} from "../transport/pki.js";
|
|
15
15
|
import { RuntimeTarget } from "../runtime/constants.js";
|
|
16
16
|
import { sha256Bytes } from "../utils/crypto.js";
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
base64ToBytes,
|
|
19
|
+
bytesToBase64,
|
|
20
|
+
hexToBytes,
|
|
21
|
+
toUint8Array,
|
|
22
|
+
} from "../utils/encoding.js";
|
|
18
23
|
import {
|
|
19
24
|
aesGcmDecrypt,
|
|
20
25
|
aesGcmEncrypt,
|
|
@@ -29,6 +34,7 @@ import {
|
|
|
29
34
|
x25519PublicKey,
|
|
30
35
|
x25519SharedSecret,
|
|
31
36
|
} from "../utils/wasmCrypto.js";
|
|
37
|
+
import { derSignatureToRaw, rawSignatureToDer } from "../utils/ecdsaDer.js";
|
|
32
38
|
import {
|
|
33
39
|
matchesCronExpression,
|
|
34
40
|
nextCronOccurrence,
|
|
@@ -100,7 +106,8 @@ export const NodeHostSupportedOperations = Object.freeze([
|
|
|
100
106
|
"protocol_handle.unregister",
|
|
101
107
|
"protocol_dial.dial",
|
|
102
108
|
"protocol.request",
|
|
103
|
-
"keyslot.
|
|
109
|
+
"keyslot.sign",
|
|
110
|
+
"keyslot.unwrap",
|
|
104
111
|
"exec.execFile",
|
|
105
112
|
"context.get",
|
|
106
113
|
"context.set",
|
|
@@ -120,6 +127,8 @@ export const NodeHostSupportedOperations = Object.freeze([
|
|
|
120
127
|
"crypto.secp256k1.publicKeyFromPrivate",
|
|
121
128
|
"crypto.secp256k1.signDigest",
|
|
122
129
|
"crypto.secp256k1.verifyDigest",
|
|
130
|
+
"crypto.secp256k1.sign",
|
|
131
|
+
"crypto.secp256k1.verify",
|
|
123
132
|
"crypto.ed25519.publicKeyFromSeed",
|
|
124
133
|
"crypto.ed25519.sign",
|
|
125
134
|
"crypto.ed25519.verify",
|
|
@@ -146,11 +155,15 @@ function assertNonNegativeInteger(value, label) {
|
|
|
146
155
|
}
|
|
147
156
|
|
|
148
157
|
function normalizeGrantedCapabilities(options) {
|
|
158
|
+
// Default-deny: a NodeHost constructed without an explicit grant exposes no
|
|
159
|
+
// capabilities. Every capability must be granted via grantedCapabilities,
|
|
160
|
+
// capabilities, or manifest.capabilities; requests then fail closed through
|
|
161
|
+
// assertCapability().
|
|
149
162
|
const source =
|
|
150
163
|
options.grantedCapabilities ??
|
|
151
164
|
options.capabilities ??
|
|
152
165
|
options.manifest?.capabilities ??
|
|
153
|
-
|
|
166
|
+
[];
|
|
154
167
|
if (!Array.isArray(source)) {
|
|
155
168
|
throw new TypeError(
|
|
156
169
|
"Node host capabilities must be an array when provided.",
|
|
@@ -310,6 +323,52 @@ async function invokeAdapterMethod(adapter, methodName, params, label) {
|
|
|
310
323
|
);
|
|
311
324
|
}
|
|
312
325
|
|
|
326
|
+
// keyslotUnwrapHKDFInfo domain-separates the HKDF step of keyslot.unwrap from
|
|
327
|
+
// every other HKDF use in this host (e.g. crypto.hkdf). Must match the Go
|
|
328
|
+
// reference implementation's keyslotUnwrapHKDFInfo constant
|
|
329
|
+
// (sdn-server/internal/modulert/caps/keyslot.go) exactly, or wrapped
|
|
330
|
+
// payloads produced against one host will fail to unwrap on the other.
|
|
331
|
+
const KEYSLOT_UNWRAP_HKDF_INFO = "sdn-server/keyslot.unwrap/v1";
|
|
332
|
+
|
|
333
|
+
// normalizeKeySlotMaterial accepts the raw key-slot secret returned by a
|
|
334
|
+
// host-supplied walletSign adapter's internal "get" resolver and coerces it
|
|
335
|
+
// to a Uint8Array. This resolver is never exposed to the guest directly
|
|
336
|
+
// (there is no "keyslot.get" hostcall) — it only feeds the host-side
|
|
337
|
+
// keyslot.sign / keyslot.unwrap crypto oracle implemented below, mirroring
|
|
338
|
+
// Go's resolveKeySlot() in keyslot.go. Callers MUST NOT return the result of
|
|
339
|
+
// this function, or any encoding of it, to the guest.
|
|
340
|
+
function normalizeKeySlotMaterial(raw) {
|
|
341
|
+
if (raw instanceof Uint8Array) {
|
|
342
|
+
return raw;
|
|
343
|
+
}
|
|
344
|
+
if (raw instanceof ArrayBuffer) {
|
|
345
|
+
return new Uint8Array(raw);
|
|
346
|
+
}
|
|
347
|
+
if (ArrayBuffer.isView(raw)) {
|
|
348
|
+
return toUint8Array(raw);
|
|
349
|
+
}
|
|
350
|
+
if (typeof raw === "string") {
|
|
351
|
+
return base64ToBytes(raw);
|
|
352
|
+
}
|
|
353
|
+
if (raw && typeof raw === "object") {
|
|
354
|
+
if (raw.base64 !== undefined) {
|
|
355
|
+
return base64ToBytes(raw.base64);
|
|
356
|
+
}
|
|
357
|
+
if (raw.hex !== undefined) {
|
|
358
|
+
return hexToBytes(raw.hex);
|
|
359
|
+
}
|
|
360
|
+
if (raw.value !== undefined) {
|
|
361
|
+
return normalizeKeySlotMaterial(raw.value);
|
|
362
|
+
}
|
|
363
|
+
if (raw.bytes !== undefined) {
|
|
364
|
+
return normalizeKeySlotMaterial(raw.bytes);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
throw new Error(
|
|
368
|
+
"wallet_sign adapter returned an unrecognized key-slot material shape.",
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
|
|
313
372
|
function normalizeFilesystemRoot(rootPath) {
|
|
314
373
|
return path.resolve(String(rootPath ?? process.cwd()));
|
|
315
374
|
}
|
|
@@ -2044,10 +2103,21 @@ export class NodeHost {
|
|
|
2044
2103
|
),
|
|
2045
2104
|
});
|
|
2046
2105
|
|
|
2106
|
+
// keyslot is a host-side crypto oracle (parity with the Go node's
|
|
2107
|
+
// internal/modulert/caps/keyslot.go): it never returns a slot's private
|
|
2108
|
+
// key material to the guest. Guests get the *outputs* of private-key
|
|
2109
|
+
// operations (a signature, or the plaintext that was wrapped to a
|
|
2110
|
+
// slot's public key) — never the key itself. There is no "keyslot.get"
|
|
2111
|
+
// raw-export operation; unknown keyslot operations fail closed via the
|
|
2112
|
+
// default branch of invoke()'s switch below.
|
|
2047
2113
|
this.keyslot = Object.freeze({
|
|
2048
|
-
|
|
2049
|
-
this.#withCapability("wallet_sign", "keyslot.
|
|
2050
|
-
|
|
2114
|
+
sign: async (params = {}) =>
|
|
2115
|
+
this.#withCapability("wallet_sign", "keyslot.sign", async () =>
|
|
2116
|
+
this.#keyslotSign(params),
|
|
2117
|
+
),
|
|
2118
|
+
unwrap: async (params = {}) =>
|
|
2119
|
+
this.#withCapability("wallet_sign", "keyslot.unwrap", async () =>
|
|
2120
|
+
this.#keyslotUnwrap(params),
|
|
2051
2121
|
),
|
|
2052
2122
|
});
|
|
2053
2123
|
}
|
|
@@ -2201,8 +2271,10 @@ export class NodeHost {
|
|
|
2201
2271
|
return this.protocolDial.dial(params);
|
|
2202
2272
|
case "protocol.request":
|
|
2203
2273
|
return this.protocolDial.request(params);
|
|
2204
|
-
case "keyslot.
|
|
2205
|
-
return this.keyslot.
|
|
2274
|
+
case "keyslot.sign":
|
|
2275
|
+
return this.keyslot.sign(params);
|
|
2276
|
+
case "keyslot.unwrap":
|
|
2277
|
+
return this.keyslot.unwrap(params);
|
|
2206
2278
|
case "exec.execFile":
|
|
2207
2279
|
return this.exec.execFile(params);
|
|
2208
2280
|
case "context.get":
|
|
@@ -2251,6 +2323,14 @@ export class NodeHost {
|
|
|
2251
2323
|
params.signature,
|
|
2252
2324
|
params.publicKey,
|
|
2253
2325
|
);
|
|
2326
|
+
case "crypto.secp256k1.sign":
|
|
2327
|
+
return this.crypto.secp256k1.sign(params.message, params.privateKey);
|
|
2328
|
+
case "crypto.secp256k1.verify":
|
|
2329
|
+
return this.crypto.secp256k1.verify(
|
|
2330
|
+
params.message,
|
|
2331
|
+
params.signature,
|
|
2332
|
+
params.publicKey,
|
|
2333
|
+
);
|
|
2254
2334
|
case "crypto.ed25519.publicKeyFromSeed":
|
|
2255
2335
|
return this.crypto.ed25519.publicKeyFromSeed(params.seed);
|
|
2256
2336
|
case "crypto.ed25519.sign":
|
|
@@ -2379,6 +2459,32 @@ export class NodeHost {
|
|
|
2379
2459
|
toUint8Array(publicKey),
|
|
2380
2460
|
),
|
|
2381
2461
|
),
|
|
2462
|
+
// Message-based ECDSA-DER contract (parity with the Go/C++ hosts and the
|
|
2463
|
+
// synchronous host-crypto ABI): sha256 the message internally, then use
|
|
2464
|
+
// the digest-based primitives with DER <-> raw conversion.
|
|
2465
|
+
sign: async (message, privateKey) =>
|
|
2466
|
+
this.#withCapability("crypto_sign", "crypto.secp256k1.sign", async () => {
|
|
2467
|
+
const digest = await sha256Bytes(toUint8Array(message));
|
|
2468
|
+
const rawSignature = await secp256k1SignDigest(
|
|
2469
|
+
toUint8Array(digest),
|
|
2470
|
+
toUint8Array(privateKey),
|
|
2471
|
+
);
|
|
2472
|
+
return rawSignatureToDer(rawSignature);
|
|
2473
|
+
}),
|
|
2474
|
+
verify: async (message, signature, publicKey) =>
|
|
2475
|
+
this.#withCapability(
|
|
2476
|
+
"crypto_verify",
|
|
2477
|
+
"crypto.secp256k1.verify",
|
|
2478
|
+
async () => {
|
|
2479
|
+
const digest = await sha256Bytes(toUint8Array(message));
|
|
2480
|
+
const result = await secp256k1VerifyDigest(
|
|
2481
|
+
toUint8Array(digest),
|
|
2482
|
+
derSignatureToRaw(signature),
|
|
2483
|
+
toUint8Array(publicKey),
|
|
2484
|
+
);
|
|
2485
|
+
return { result: Boolean(result) };
|
|
2486
|
+
},
|
|
2487
|
+
),
|
|
2382
2488
|
}),
|
|
2383
2489
|
ed25519: Object.freeze({
|
|
2384
2490
|
publicKeyFromSeed: async (seed) =>
|
|
@@ -2432,6 +2538,119 @@ export class NodeHost {
|
|
|
2432
2538
|
this.assertCapability(capability, operation);
|
|
2433
2539
|
return callback();
|
|
2434
2540
|
}
|
|
2541
|
+
|
|
2542
|
+
// resolveKeySlotMaterial looks up a slot's private key material via the
|
|
2543
|
+
// host-supplied walletSign adapter. The returned Uint8Array MUST NOT be
|
|
2544
|
+
// mutated (it may alias the adapter's live key store) and MUST NOT be
|
|
2545
|
+
// returned, or any encoding of it, to the guest. Only derived outputs
|
|
2546
|
+
// (signatures, decrypted plaintext of a wrapped payload) may cross the
|
|
2547
|
+
// host/guest boundary. Mirrors resolveKeySlot() in keyslot.go.
|
|
2548
|
+
async #resolveKeySlotMaterial(slotId) {
|
|
2549
|
+
const normalizedSlotId = assertNonEmptyString(slotId, "slotId");
|
|
2550
|
+
const record = await invokeAdapterMethod(
|
|
2551
|
+
this._walletSignAdapter,
|
|
2552
|
+
"get",
|
|
2553
|
+
{ slotId: normalizedSlotId },
|
|
2554
|
+
"wallet_sign",
|
|
2555
|
+
);
|
|
2556
|
+
const material = normalizeKeySlotMaterial(record);
|
|
2557
|
+
if (material.length === 0) {
|
|
2558
|
+
throw new Error(`keyslot "${normalizedSlotId}" not found`);
|
|
2559
|
+
}
|
|
2560
|
+
return material;
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2563
|
+
// keyslot.sign performs a host-side signature over a guest-supplied
|
|
2564
|
+
// payload using the named slot's private key. Request:
|
|
2565
|
+
// {slotId, payload: base64, algorithm?: "ed25519" | "secp256k1"}
|
|
2566
|
+
// algorithm defaults to "ed25519". Response:
|
|
2567
|
+
// {signature: base64, algorithm}
|
|
2568
|
+
// The slot's key material never appears in the response. Mirrors
|
|
2569
|
+
// handleKeyslotSign() in keyslot.go.
|
|
2570
|
+
async #keyslotSign(params = {}) {
|
|
2571
|
+
const slotId = assertNonEmptyString(params.slotId, "slotId");
|
|
2572
|
+
const keyMaterial = await this.#resolveKeySlotMaterial(slotId);
|
|
2573
|
+
const payload =
|
|
2574
|
+
params.payload === undefined || params.payload === null
|
|
2575
|
+
? new Uint8Array()
|
|
2576
|
+
: base64ToBytes(String(params.payload));
|
|
2577
|
+
const algorithm = String(params.algorithm ?? "").trim() || "ed25519";
|
|
2578
|
+
|
|
2579
|
+
if (algorithm === "ed25519") {
|
|
2580
|
+
if (keyMaterial.length !== 32) {
|
|
2581
|
+
throw new Error(`keyslot "${slotId}" is not a 32-byte ed25519 seed`);
|
|
2582
|
+
}
|
|
2583
|
+
const signature = await ed25519Sign(payload, keyMaterial);
|
|
2584
|
+
return { signature: bytesToBase64(signature), algorithm: "ed25519" };
|
|
2585
|
+
}
|
|
2586
|
+
|
|
2587
|
+
if (algorithm === "secp256k1") {
|
|
2588
|
+
if (keyMaterial.length !== 32) {
|
|
2589
|
+
throw new Error(
|
|
2590
|
+
`keyslot "${slotId}" is not a 32-byte secp256k1 private key`,
|
|
2591
|
+
);
|
|
2592
|
+
}
|
|
2593
|
+
const digest = await sha256Bytes(payload);
|
|
2594
|
+
const rawSignature = await secp256k1SignDigest(digest, keyMaterial);
|
|
2595
|
+
return {
|
|
2596
|
+
signature: bytesToBase64(rawSignatureToDer(rawSignature)),
|
|
2597
|
+
algorithm: "secp256k1",
|
|
2598
|
+
};
|
|
2599
|
+
}
|
|
2600
|
+
|
|
2601
|
+
throw new Error(`unsupported keyslot.sign algorithm: ${algorithm}`);
|
|
2602
|
+
}
|
|
2603
|
+
|
|
2604
|
+
// keyslot.unwrap decrypts a payload that was sealed to a slot's X25519
|
|
2605
|
+
// public key, returning only the decrypted plaintext (e.g. a licensing
|
|
2606
|
+
// content key) — never the slot's private key. Wrap scheme is
|
|
2607
|
+
// ephemeral-sender ECIES: X25519(slotPrivateKey, ephemeralPublicKey) ->
|
|
2608
|
+
// HKDF-SHA256 -> AES-256-GCM. Request:
|
|
2609
|
+
// {slotId, ephemeralPublicKey: base64, nonce: base64, ciphertext: base64}
|
|
2610
|
+
// Response: {plaintext: base64}. Mirrors handleKeyslotUnwrap() in
|
|
2611
|
+
// keyslot.go, including the wire format where `ciphertext` is
|
|
2612
|
+
// (ciphertext || 16-byte GCM tag), per Go's crypto/cipher.GCM convention.
|
|
2613
|
+
async #keyslotUnwrap(params = {}) {
|
|
2614
|
+
const slotId = assertNonEmptyString(params.slotId, "slotId");
|
|
2615
|
+
const keyMaterial = await this.#resolveKeySlotMaterial(slotId);
|
|
2616
|
+
if (keyMaterial.length !== 32) {
|
|
2617
|
+
throw new Error(
|
|
2618
|
+
`keyslot "${slotId}" is not a 32-byte x25519 private key`,
|
|
2619
|
+
);
|
|
2620
|
+
}
|
|
2621
|
+
|
|
2622
|
+
const ephemeralPublicKey = base64ToBytes(
|
|
2623
|
+
String(params.ephemeralPublicKey ?? ""),
|
|
2624
|
+
);
|
|
2625
|
+
const nonce = base64ToBytes(String(params.nonce ?? ""));
|
|
2626
|
+
const wireCiphertext = base64ToBytes(String(params.ciphertext ?? ""));
|
|
2627
|
+
if (ephemeralPublicKey.length === 0 || wireCiphertext.length === 0) {
|
|
2628
|
+
throw new Error(
|
|
2629
|
+
"keyslot.unwrap requires ephemeralPublicKey and ciphertext",
|
|
2630
|
+
);
|
|
2631
|
+
}
|
|
2632
|
+
if (wireCiphertext.length < 16) {
|
|
2633
|
+
throw new Error(
|
|
2634
|
+
"keyslot.unwrap ciphertext is too short to contain a GCM tag",
|
|
2635
|
+
);
|
|
2636
|
+
}
|
|
2637
|
+
const tagStart = wireCiphertext.length - 16;
|
|
2638
|
+
const ciphertext = wireCiphertext.subarray(0, tagStart);
|
|
2639
|
+
const tag = wireCiphertext.subarray(tagStart);
|
|
2640
|
+
|
|
2641
|
+
const sharedSecret = await x25519SharedSecret(
|
|
2642
|
+
keyMaterial,
|
|
2643
|
+
ephemeralPublicKey,
|
|
2644
|
+
);
|
|
2645
|
+
const aesKey = await hkdfBytes(
|
|
2646
|
+
sharedSecret,
|
|
2647
|
+
new Uint8Array(),
|
|
2648
|
+
textEncoder.encode(KEYSLOT_UNWRAP_HKDF_INFO),
|
|
2649
|
+
32,
|
|
2650
|
+
);
|
|
2651
|
+
const plaintext = await aesGcmDecrypt(aesKey, ciphertext, tag, nonce);
|
|
2652
|
+
return { plaintext: bytesToBase64(plaintext) };
|
|
2653
|
+
}
|
|
2435
2654
|
}
|
|
2436
2655
|
|
|
2437
2656
|
export function createNodeHost(options = {}) {
|