space-data-module-sdk 0.8.4 → 0.8.6

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.
Files changed (354) hide show
  1. package/README.md +117 -20
  2. package/bin/space-data-module.js +263 -0
  3. package/docs/.nojekyll +1 -0
  4. package/docs/AGENTS.md +34 -0
  5. package/docs/architecture.svg +141 -0
  6. package/docs/browser-wasmedge-isomorphic.md +179 -0
  7. package/docs/flatsql-streaming-standard.md +341 -0
  8. package/docs/gpu-module-abi.md +193 -0
  9. package/docs/index.html +125 -0
  10. package/docs/isomorphic-pthreads.md +188 -0
  11. package/docs/isomorphic-sdn-runtime-plan.md +167 -0
  12. package/docs/language-runtime-matrix.md +82 -0
  13. package/docs/manifest-structure.svg +114 -0
  14. package/docs/module-bundle-runtime-plan.md +19 -0
  15. package/docs/module-lifecycle.svg +70 -0
  16. package/docs/module-publication-standard.md +540 -0
  17. package/docs/node-red-default-node-parity.md +88 -0
  18. package/docs/protocol-installation.md +196 -0
  19. package/docs/secrets-capability.md +152 -0
  20. package/docs/styles.css +288 -0
  21. package/docs/testing-harness.md +408 -0
  22. package/docs/tri-runtime-parity.md +132 -0
  23. package/docs/wallet-callback.html +2 -0
  24. package/package.json +25 -6
  25. package/schemas/HttpRequestAbi.fbs +41 -0
  26. package/schemas/HttpResponseAbi.fbs +36 -0
  27. package/schemas/PluginManifest.fbs +2 -1
  28. package/src/AGENTS.md +1 -1
  29. package/src/app/codec.js +548 -0
  30. package/src/app/index.js +6 -0
  31. package/src/browser.js +5 -0
  32. package/src/bundle/constants.js +1 -0
  33. package/src/bundle/index.js +15 -0
  34. package/src/bundle/sigdomain.js +179 -0
  35. package/src/bundle/signing.js +767 -0
  36. package/src/bundle/wasm.js +3 -2
  37. package/src/capabilities.js +3 -0
  38. package/src/compat/index.js +7 -0
  39. package/src/compat/sdnLegacy.js +449 -0
  40. package/src/compiler/compileModule.js +556 -55
  41. package/src/compiler/flatcSupport.js +41 -27
  42. package/src/compiler/index.d.ts +2 -0
  43. package/src/compiler/index.js +18 -0
  44. package/src/compiler/invokeGlue.js +1212 -183
  45. package/src/compiler/pthreadArtifactGuard.js +910 -0
  46. package/src/compiler/sdnShimGenerator.js +323 -0
  47. package/src/compiler/wasiThreadsToolchain.js +150 -0
  48. package/src/compliance/index.js +11 -1
  49. package/src/compliance/legacyWildcardPorts.js +228 -0
  50. package/src/compliance/pluginCompliance.js +1000 -96
  51. package/src/field-stream/index.d.ts +31 -0
  52. package/src/field-stream/index.js +119 -0
  53. package/src/flow/dependencyStreamBridge.js +234 -0
  54. package/src/flow/flatsqlLinkShim.js +304 -0
  55. package/src/flow/flowCodec.js +107 -0
  56. package/src/flow/flowCompiler.js +2900 -0
  57. package/src/flow/flowRuntimeHost.js +877 -0
  58. package/src/flow/index.d.ts +117 -0
  59. package/src/flow/index.js +31 -0
  60. package/src/flow/isomorphicFlowHost.js +384 -0
  61. package/src/flow/jsFlowRuntime.js +275 -0
  62. package/src/flow/normalize.js +294 -0
  63. package/src/flow/runtime-src/flow_runtime.cpp +1699 -0
  64. package/src/flow/vendor/sdn-flow/MethodRegistry.js +400 -0
  65. package/src/flow/vendor/sdn-flow/constants.js +39 -0
  66. package/src/flow/vendor/sdn-flow/index.js +29 -0
  67. package/src/flow/vendor/sdn-flow/normalize.js +506 -0
  68. package/src/flow/vendor/sdn-flow/wasmCompatibility.js +189 -0
  69. package/src/generated/http/cpp/HttpRequestAbi_generated.h +285 -0
  70. package/src/generated/http/cpp/HttpResponseAbi_generated.h +192 -0
  71. package/src/generated/http/sdn/http/http-header.js +53 -0
  72. package/src/generated/http/sdn/http/http-header.ts +67 -0
  73. package/src/generated/http/sdn/http/http-request.js +132 -0
  74. package/src/generated/http/sdn/http/http-request.ts +179 -0
  75. package/src/generated/http/sdn/http/http-response.js +144 -0
  76. package/src/generated/http/sdn/http/http-response.ts +168 -0
  77. package/src/generated/http/sdn/http.js +11 -0
  78. package/src/generated/http/sdn/http.ts +4 -0
  79. package/src/generated/orbpro/flow/backpressure-policy.d.ts +12 -0
  80. package/src/generated/orbpro/flow/backpressure-policy.d.ts.map +1 -0
  81. package/src/generated/orbpro/flow/backpressure-policy.js +17 -0
  82. package/src/generated/orbpro/flow/backpressure-policy.js.map +1 -0
  83. package/src/generated/orbpro/flow/backpressure-policy.ts +15 -0
  84. package/src/generated/orbpro/flow/flow-bundle-manifest.d.ts +142 -0
  85. package/src/generated/orbpro/flow/flow-bundle-manifest.d.ts.map +1 -0
  86. package/src/generated/orbpro/flow/flow-bundle-manifest.js +304 -0
  87. package/src/generated/orbpro/flow/flow-bundle-manifest.js.map +1 -0
  88. package/src/generated/orbpro/flow/flow-bundle-manifest.ts +399 -0
  89. package/src/generated/orbpro/flow/flow-edge.d.ts +113 -0
  90. package/src/generated/orbpro/flow/flow-edge.d.ts.map +1 -0
  91. package/src/generated/orbpro/flow/flow-edge.js +221 -0
  92. package/src/generated/orbpro/flow/flow-edge.js.map +1 -0
  93. package/src/generated/orbpro/flow/flow-edge.ts +292 -0
  94. package/src/generated/orbpro/flow/flow-node.d.ts +80 -0
  95. package/src/generated/orbpro/flow/flow-node.d.ts.map +1 -0
  96. package/src/generated/orbpro/flow/flow-node.js +158 -0
  97. package/src/generated/orbpro/flow/flow-node.js.map +1 -0
  98. package/src/generated/orbpro/flow/flow-node.ts +202 -0
  99. package/src/generated/orbpro/flow/flow-program.d.ts +164 -0
  100. package/src/generated/orbpro/flow/flow-program.d.ts.map +1 -0
  101. package/src/generated/orbpro/flow/flow-program.js +350 -0
  102. package/src/generated/orbpro/flow/flow-program.js.map +1 -0
  103. package/src/generated/orbpro/flow/flow-program.ts +477 -0
  104. package/src/generated/orbpro/flow/flow-trigger.d.ts +108 -0
  105. package/src/generated/orbpro/flow/flow-trigger.d.ts.map +1 -0
  106. package/src/generated/orbpro/flow/flow-trigger.js +207 -0
  107. package/src/generated/orbpro/flow/flow-trigger.js.map +1 -0
  108. package/src/generated/orbpro/flow/flow-trigger.ts +276 -0
  109. package/src/generated/orbpro/flow/node-kind.d.ts +13 -0
  110. package/src/generated/orbpro/flow/node-kind.d.ts.map +1 -0
  111. package/src/generated/orbpro/flow/node-kind.js +16 -0
  112. package/src/generated/orbpro/flow/node-kind.js.map +1 -0
  113. package/src/generated/orbpro/{invoke.ts → flow/node-kind.ts} +12 -2
  114. package/src/generated/orbpro/flow/plugin-version-binding.d.ts +52 -0
  115. package/src/generated/orbpro/flow/plugin-version-binding.d.ts.map +1 -0
  116. package/src/generated/orbpro/flow/plugin-version-binding.js +85 -0
  117. package/src/generated/orbpro/flow/plugin-version-binding.js.map +1 -0
  118. package/src/generated/orbpro/flow/plugin-version-binding.ts +121 -0
  119. package/src/generated/orbpro/flow/schema-hash-binding.d.ts +70 -0
  120. package/src/generated/orbpro/flow/schema-hash-binding.d.ts.map +1 -0
  121. package/src/generated/orbpro/flow/schema-hash-binding.js +143 -0
  122. package/src/generated/orbpro/flow/schema-hash-binding.js.map +1 -0
  123. package/src/generated/orbpro/flow/schema-hash-binding.ts +189 -0
  124. package/src/generated/orbpro/flow/trigger-binding.d.ts +71 -0
  125. package/src/generated/orbpro/flow/trigger-binding.d.ts.map +1 -0
  126. package/src/generated/orbpro/flow/trigger-binding.js +142 -0
  127. package/src/generated/orbpro/flow/trigger-binding.js.map +1 -0
  128. package/src/generated/orbpro/flow/trigger-binding.ts +181 -0
  129. package/src/generated/orbpro/flow/trigger-kind.d.ts +14 -0
  130. package/src/generated/orbpro/flow/trigger-kind.d.ts.map +1 -0
  131. package/src/generated/orbpro/flow/trigger-kind.js +17 -0
  132. package/src/generated/orbpro/flow/trigger-kind.js.map +1 -0
  133. package/src/generated/orbpro/flow/trigger-kind.ts +17 -0
  134. package/src/generated/orbpro/flow.d.ts +21 -0
  135. package/src/generated/orbpro/flow.d.ts.map +1 -0
  136. package/src/generated/orbpro/flow.js +23 -0
  137. package/src/generated/orbpro/flow.js.map +1 -0
  138. package/src/generated/orbpro/flow.ts +24 -0
  139. package/src/generated/orbpro/manifest/capability-kind.d.ts +2 -1
  140. package/src/generated/orbpro/manifest/capability-kind.js +1 -0
  141. package/src/generated/orbpro/manifest/capability-kind.ts +1 -0
  142. package/src/generated/orbpro/plugin/stream-invoke-request.d.ts +93 -0
  143. package/src/generated/orbpro/plugin/stream-invoke-request.js +160 -0
  144. package/src/generated/orbpro/plugin/stream-invoke-request.ts +211 -0
  145. package/src/generated/orbpro/plugin/stream-invoke-response.d.ts +99 -0
  146. package/src/generated/orbpro/plugin/stream-invoke-response.js +175 -0
  147. package/src/generated/orbpro/plugin/stream-invoke-response.ts +226 -0
  148. package/src/generated/orbpro/plugin.js +8 -0
  149. package/src/generated/orbpro/stream.d.ts +12 -0
  150. package/src/generated/orbpro/stream.js +14 -0
  151. package/src/generated/orbpro/stream.ts +15 -0
  152. package/src/generated/spacedatastandards/plg/EntryFunction.d.ts +52 -0
  153. package/src/generated/spacedatastandards/plg/EntryFunction.d.ts.map +1 -0
  154. package/src/generated/spacedatastandards/plg/EntryFunction.js +106 -0
  155. package/src/generated/spacedatastandards/plg/EntryFunction.ts +162 -0
  156. package/src/generated/spacedatastandards/plg/FlatBufferTypeRef.d.ts +90 -0
  157. package/src/generated/spacedatastandards/plg/FlatBufferTypeRef.d.ts.map +1 -0
  158. package/src/generated/spacedatastandards/plg/FlatBufferTypeRef.js +189 -0
  159. package/src/generated/spacedatastandards/plg/FlatBufferTypeRef.ts +270 -0
  160. package/src/generated/spacedatastandards/plg/PLG.d.ts +492 -0
  161. package/src/generated/spacedatastandards/plg/PLG.d.ts.map +1 -0
  162. package/src/generated/spacedatastandards/plg/PLG.js +1139 -0
  163. package/src/generated/spacedatastandards/plg/PLG.ts +1600 -0
  164. package/src/generated/spacedatastandards/plg/PLGAcceptedTypeSet.d.ts +63 -0
  165. package/src/generated/spacedatastandards/plg/PLGAcceptedTypeSet.d.ts.map +1 -0
  166. package/src/generated/spacedatastandards/plg/PLGAcceptedTypeSet.js +138 -0
  167. package/src/generated/spacedatastandards/plg/PLGAcceptedTypeSet.ts +189 -0
  168. package/src/generated/spacedatastandards/plg/PLGBuildArtifact.d.ts +41 -0
  169. package/src/generated/spacedatastandards/plg/PLGBuildArtifact.d.ts.map +1 -0
  170. package/src/generated/spacedatastandards/plg/PLGBuildArtifact.js +104 -0
  171. package/src/generated/spacedatastandards/plg/PLGBuildArtifact.ts +151 -0
  172. package/src/generated/spacedatastandards/plg/PLGFlowEdge.d.ts +68 -0
  173. package/src/generated/spacedatastandards/plg/PLGFlowEdge.d.ts.map +1 -0
  174. package/src/generated/spacedatastandards/plg/PLGFlowEdge.js +124 -0
  175. package/src/generated/spacedatastandards/plg/PLGFlowEdge.ts +184 -0
  176. package/src/generated/spacedatastandards/plg/PLGFlowEdgeContract.d.ts +58 -0
  177. package/src/generated/spacedatastandards/plg/PLGFlowEdgeContract.d.ts.map +1 -0
  178. package/src/generated/spacedatastandards/plg/PLGFlowEdgeContract.js +126 -0
  179. package/src/generated/spacedatastandards/plg/PLGFlowEdgeContract.ts +161 -0
  180. package/src/generated/spacedatastandards/plg/PLGFlowNode.d.ts +82 -0
  181. package/src/generated/spacedatastandards/plg/PLGFlowNode.d.ts.map +1 -0
  182. package/src/generated/spacedatastandards/plg/PLGFlowNode.js +164 -0
  183. package/src/generated/spacedatastandards/plg/PLGFlowNode.ts +244 -0
  184. package/src/generated/spacedatastandards/plg/PLGFlowTrigger.d.ts +55 -0
  185. package/src/generated/spacedatastandards/plg/PLGFlowTrigger.d.ts.map +1 -0
  186. package/src/generated/spacedatastandards/plg/PLGFlowTrigger.js +105 -0
  187. package/src/generated/spacedatastandards/plg/PLGFlowTrigger.ts +162 -0
  188. package/src/generated/spacedatastandards/plg/PLGFlowTriggerBinding.d.ts +42 -0
  189. package/src/generated/spacedatastandards/plg/PLGFlowTriggerBinding.d.ts.map +1 -0
  190. package/src/generated/spacedatastandards/plg/PLGFlowTriggerBinding.js +83 -0
  191. package/src/generated/spacedatastandards/plg/PLGFlowTriggerBinding.ts +127 -0
  192. package/src/generated/spacedatastandards/plg/PLGHostCapability.d.ts +36 -0
  193. package/src/generated/spacedatastandards/plg/PLGHostCapability.d.ts.map +1 -0
  194. package/src/generated/spacedatastandards/plg/PLGHostCapability.js +90 -0
  195. package/src/generated/spacedatastandards/plg/PLGHostCapability.ts +127 -0
  196. package/src/generated/spacedatastandards/plg/PLGMethodManifest.d.ts +53 -0
  197. package/src/generated/spacedatastandards/plg/PLGMethodManifest.d.ts.map +1 -0
  198. package/src/generated/spacedatastandards/plg/PLGMethodManifest.js +153 -0
  199. package/src/generated/spacedatastandards/plg/PLGMethodManifest.ts +210 -0
  200. package/src/generated/spacedatastandards/plg/PLGPortManifest.d.ts +70 -0
  201. package/src/generated/spacedatastandards/plg/PLGPortManifest.d.ts.map +1 -0
  202. package/src/generated/spacedatastandards/plg/PLGPortManifest.js +149 -0
  203. package/src/generated/spacedatastandards/plg/PLGPortManifest.ts +212 -0
  204. package/src/generated/spacedatastandards/plg/PLGProtocolSpec.d.ts +73 -0
  205. package/src/generated/spacedatastandards/plg/PLGProtocolSpec.d.ts.map +1 -0
  206. package/src/generated/spacedatastandards/plg/PLGProtocolSpec.js +199 -0
  207. package/src/generated/spacedatastandards/plg/PLGProtocolSpec.ts +292 -0
  208. package/src/generated/spacedatastandards/plg/PLGTimerSpec.d.ts +40 -0
  209. package/src/generated/spacedatastandards/plg/PLGTimerSpec.d.ts.map +1 -0
  210. package/src/generated/spacedatastandards/plg/PLGTimerSpec.js +103 -0
  211. package/src/generated/spacedatastandards/plg/PLGTimerSpec.ts +148 -0
  212. package/src/generated/spacedatastandards/plg/PluginCapability.d.ts +41 -0
  213. package/src/generated/spacedatastandards/plg/PluginCapability.d.ts.map +1 -0
  214. package/src/generated/spacedatastandards/plg/PluginCapability.js +82 -0
  215. package/src/generated/spacedatastandards/plg/{plugin-capability.ts → PluginCapability.ts} +55 -18
  216. package/src/generated/spacedatastandards/plg/PluginDependency.d.ts +42 -0
  217. package/src/generated/spacedatastandards/plg/PluginDependency.d.ts.map +1 -0
  218. package/src/generated/spacedatastandards/plg/PluginDependency.js +80 -0
  219. package/src/generated/spacedatastandards/plg/PluginDependency.ts +124 -0
  220. package/src/generated/spacedatastandards/plg/TAB.d.ts +85 -0
  221. package/src/generated/spacedatastandards/plg/TAB.d.ts.map +1 -0
  222. package/src/generated/spacedatastandards/plg/TAB.js +173 -0
  223. package/src/generated/spacedatastandards/plg/TAB.ts +228 -0
  224. package/src/generated/spacedatastandards/plg/bufferMutability.d.ts +18 -0
  225. package/src/generated/spacedatastandards/plg/bufferMutability.d.ts.map +1 -0
  226. package/src/generated/spacedatastandards/plg/bufferMutability.js +20 -0
  227. package/src/generated/spacedatastandards/plg/bufferMutability.ts +23 -0
  228. package/src/generated/spacedatastandards/plg/bufferOwnership.d.ts +18 -0
  229. package/src/generated/spacedatastandards/plg/bufferOwnership.d.ts.map +1 -0
  230. package/src/generated/spacedatastandards/plg/bufferOwnership.js +20 -0
  231. package/src/generated/spacedatastandards/plg/bufferOwnership.ts +23 -0
  232. package/src/generated/spacedatastandards/plg/drainBehavior.d.ts +20 -0
  233. package/src/generated/spacedatastandards/plg/drainBehavior.d.ts.map +1 -0
  234. package/src/generated/spacedatastandards/plg/drainBehavior.js +22 -0
  235. package/src/generated/spacedatastandards/plg/drainBehavior.ts +25 -0
  236. package/src/generated/spacedatastandards/plg/flowEdgeRoutePolicy.d.ts +10 -0
  237. package/src/generated/spacedatastandards/plg/flowEdgeRoutePolicy.d.ts.map +1 -0
  238. package/src/generated/spacedatastandards/plg/flowEdgeRoutePolicy.js +12 -0
  239. package/src/generated/spacedatastandards/plg/flowEdgeRoutePolicy.ts +13 -0
  240. package/src/generated/spacedatastandards/plg/hostCapabilityKind.d.ts +51 -0
  241. package/src/generated/spacedatastandards/plg/hostCapabilityKind.d.ts.map +1 -0
  242. package/src/generated/spacedatastandards/plg/hostCapabilityKind.js +53 -0
  243. package/src/generated/spacedatastandards/plg/hostCapabilityKind.ts +55 -0
  244. package/src/generated/spacedatastandards/plg/invokeSurfaceKind.d.ts +15 -0
  245. package/src/generated/spacedatastandards/plg/invokeSurfaceKind.d.ts.map +1 -0
  246. package/src/generated/spacedatastandards/plg/invokeSurfaceKind.js +17 -0
  247. package/src/generated/spacedatastandards/plg/invokeSurfaceKind.ts +19 -0
  248. package/src/generated/spacedatastandards/plg/main.d.ts +29 -0
  249. package/src/generated/spacedatastandards/plg/main.d.ts.map +1 -0
  250. package/src/generated/spacedatastandards/plg/main.js +30 -0
  251. package/src/generated/spacedatastandards/plg/main.ts +32 -0
  252. package/src/generated/spacedatastandards/plg/payloadWireFormat.d.ts +17 -0
  253. package/src/generated/spacedatastandards/plg/payloadWireFormat.d.ts.map +1 -0
  254. package/src/generated/spacedatastandards/plg/payloadWireFormat.js +19 -0
  255. package/src/generated/spacedatastandards/plg/payloadWireFormat.ts +21 -0
  256. package/src/generated/spacedatastandards/plg/pluginCategory.d.ts +82 -0
  257. package/src/generated/spacedatastandards/plg/pluginCategory.d.ts.map +1 -0
  258. package/src/generated/spacedatastandards/plg/pluginCategory.js +84 -0
  259. package/src/generated/spacedatastandards/plg/pluginCategory.ts +103 -0
  260. package/src/generated/spacedatastandards/plg/publicationState.d.ts +18 -0
  261. package/src/generated/spacedatastandards/plg/publicationState.d.ts.map +1 -0
  262. package/src/generated/spacedatastandards/plg/publicationState.js +20 -0
  263. package/src/generated/spacedatastandards/plg/purchaseTier.d.ts +18 -0
  264. package/src/generated/spacedatastandards/plg/purchaseTier.d.ts.map +1 -0
  265. package/src/generated/spacedatastandards/plg/purchaseTier.js +20 -0
  266. package/src/host/AGENTS.md +2 -2
  267. package/src/host/abi.js +53 -66
  268. package/src/host/browserHost.js +355 -8
  269. package/src/host/cpp/keyslotClient.hpp +231 -0
  270. package/src/host/cpp/secretsClient.hpp +583 -0
  271. package/src/host/hostcallWire.js +183 -0
  272. package/src/host/index.js +2 -0
  273. package/src/host/isomorphicLoader.js +44 -7
  274. package/src/host/nodeHost.js +227 -8
  275. package/src/host/sabHostcallChannel.js +206 -0
  276. package/src/host/timerDriver.js +203 -0
  277. package/src/host/wasiShim.js +41 -1
  278. package/src/host/wasiThreadBrowserWorker.mjs +48 -0
  279. package/src/host/wasiThreadHost.js +393 -0
  280. package/src/host/wasiThreadWorker.mjs +32 -0
  281. package/src/host/wasiThreadWorkerRuntime.js +93 -0
  282. package/src/http/index.js +339 -0
  283. package/src/index.d.ts +725 -11
  284. package/src/index.js +4 -0
  285. package/src/invoke/codec.js +1202 -128
  286. package/src/invoke/index.js +5 -1
  287. package/src/licensing/index.d.ts +2 -0
  288. package/src/licensing/index.js +2 -0
  289. package/src/licensing/records.js +287 -8
  290. package/src/manifest/codec.js +62 -14
  291. package/src/manifest/index.js +2 -0
  292. package/src/manifest/legacyToPlg.js +164 -25
  293. package/src/manifest/normalize.js +1 -0
  294. package/src/manifest/plgCodec.js +1303 -62
  295. package/src/manifest/typeRefs.js +162 -24
  296. package/src/runtime/compiledRuntimeAbi.js +47 -0
  297. package/src/runtime/compiledRuntimeAbi.json +33 -0
  298. package/src/runtime/index.d.ts +32 -0
  299. package/src/runtime/index.js +1 -0
  300. package/src/runtime-host/index.js +3 -0
  301. package/src/runtime-host/methodRegistry.js +55 -0
  302. package/src/standards/index.js +200 -56
  303. package/src/standards/sharedCatalog.js +16 -0
  304. package/src/testing/browserModuleHarness.js +604 -31
  305. package/src/testing/docker/wasmedge-parity.Dockerfile +39 -0
  306. package/src/testing/index.d.ts +151 -0
  307. package/src/testing/index.js +21 -0
  308. package/src/testing/native/wasmedge_emscripten_pthread_runner.c +25 -1
  309. package/src/testing/parityBrowserRunner.js +138 -0
  310. package/src/testing/parityHarness.js +616 -0
  311. package/src/testing/parityLanes.js +537 -0
  312. package/src/testing/processInvoke.js +29 -21
  313. package/src/testing/streamInvokeCodec.js +10 -175
  314. package/src/testing/wasmedgePin.json +6 -0
  315. package/src/testing/workerModuleHarness.js +242 -0
  316. package/src/testing/workerModuleHarnessWorker.js +176 -0
  317. package/src/transport/index.js +3 -0
  318. package/src/transport/pki.js +352 -14
  319. package/src/transport/records.js +16 -7
  320. package/src/utils/ecdsaDer.js +106 -0
  321. package/src/utils/wasmCrypto.js +0 -43
  322. package/templates/gpu-module/README.md +48 -0
  323. package/templates/gpu-module/include/space_data_gpu_abi.h +122 -0
  324. package/templates/gpu-module/manifest.json +84 -0
  325. package/schemas/PluginInvokeRequest.fbs +0 -18
  326. package/schemas/PluginInvokeResponse.fbs +0 -30
  327. package/schemas/spacedatastandards/PLG.fbs +0 -191
  328. package/src/generated/orbpro/invoke/plugin-invoke-request.d.ts +0 -51
  329. package/src/generated/orbpro/invoke/plugin-invoke-request.d.ts.map +0 -1
  330. package/src/generated/orbpro/invoke/plugin-invoke-request.js +0 -131
  331. package/src/generated/orbpro/invoke/plugin-invoke-request.js.map +0 -1
  332. package/src/generated/orbpro/invoke/plugin-invoke-request.ts +0 -173
  333. package/src/generated/orbpro/invoke/plugin-invoke-response.d.ts +0 -76
  334. package/src/generated/orbpro/invoke/plugin-invoke-response.d.ts.map +0 -1
  335. package/src/generated/orbpro/invoke/plugin-invoke-response.js +0 -184
  336. package/src/generated/orbpro/invoke/plugin-invoke-response.js.map +0 -1
  337. package/src/generated/orbpro/invoke/plugin-invoke-response.ts +0 -243
  338. package/src/generated/orbpro/invoke.d.ts +0 -3
  339. package/src/generated/orbpro/invoke.js +0 -5
  340. package/src/generated/spacedatastandards/plg/entry-function.js +0 -86
  341. package/src/generated/spacedatastandards/plg/entry-function.ts +0 -119
  342. package/src/generated/spacedatastandards/plg/index.js +0 -16
  343. package/src/generated/spacedatastandards/plg/index.ts +0 -11
  344. package/src/generated/spacedatastandards/plg/plg.js +0 -657
  345. package/src/generated/spacedatastandards/plg/plg.ts +0 -924
  346. package/src/generated/spacedatastandards/plg/plugin-capability.js +0 -66
  347. package/src/generated/spacedatastandards/plg/plugin-category.js +0 -15
  348. package/src/generated/spacedatastandards/plg/plugin-category.ts +0 -53
  349. package/src/generated/spacedatastandards/plg/plugin-dependency.js +0 -63
  350. package/src/generated/spacedatastandards/plg/plugin-dependency.ts +0 -86
  351. package/src/generated/spacedatastandards/plg/publication-state.js +0 -9
  352. package/src/generated/spacedatastandards/plg/purchase-tier.js +0 -9
  353. /package/src/generated/spacedatastandards/plg/{publication-state.ts → publicationState.ts} +0 -0
  354. /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
@@ -5,3 +5,5 @@ export * from "./browserEdgeShims.js";
5
5
  export * from "./wasiShim.js";
6
6
  export * from "./isomorphicLoader.js";
7
7
  export * from "./abi.js";
8
+ export * from "./sabHostcallChannel.js";
9
+ export * from "./timerDriver.js";
@@ -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 sdn_host)
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
- const inspection = await inspectModule(wasmBytes);
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
- wasmPath,
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 === "sdn-abi") &&
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
- wasmModule = await WebAssembly.compile(bytes);
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);
@@ -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 { toUint8Array } from "../utils/encoding.js";
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.get",
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
- NodeHostSupportedCapabilities;
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
- get: async (params = {}) =>
2049
- this.#withCapability("wallet_sign", "keyslot.get", async () =>
2050
- invokeAdapterMethod(this._walletSignAdapter, "get", params, "wallet_sign"),
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.get":
2205
- return this.keyslot.get(params);
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 = {}) {