space-data-module-sdk 0.8.4 → 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.
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 +716 -10
  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 +299 -11
  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
@@ -2,7 +2,7 @@
2
2
  * Browser-side module harness.
3
3
  *
4
4
  * Loads the same standalone WASI .wasm artifact that WasmEdge runs,
5
- * instantiating it in the browser with the WASI shim + optional sdn_host
5
+ * instantiating it in the browser with the WASI shim + optional space_data_module_host
6
6
  * bridge. Matches the createModuleHarness() API surface.
7
7
  *
8
8
  * Supports two invoke paths:
@@ -13,10 +13,14 @@
13
13
  */
14
14
 
15
15
  import { createBrowserWasiShim, WasiExitError } from "../host/wasiShim.js";
16
+ import {
17
+ createWasiThreadSpawn,
18
+ isWasiThreadsModule,
19
+ } from "../host/wasiThreadHost.js";
16
20
  import { createBrowserHost } from "../host/browserHost.js";
17
21
  import { getWasmWallet } from "../utils/wasmCrypto.js";
18
22
  import {
19
- createJsonHostcallBridge,
23
+ createHostcallBridge,
20
24
  createAsyncHostDispatcher,
21
25
  createHostSyncDispatcher,
22
26
  DEFAULT_HOSTCALL_IMPORT_MODULE,
@@ -26,38 +30,142 @@ import {
26
30
  DefaultManifestExports,
27
31
  } from "../runtime/constants.js";
28
32
  import {
33
+ INVOKE_ARENA_ALIGNMENT,
29
34
  encodePluginInvokeRequest,
30
35
  decodePluginInvokeResponse,
36
+ writePluginInvokeRequestToArena,
31
37
  } from "../invoke/codec.js";
38
+ import { toUint8Array } from "../runtime/bufferLike.js";
39
+ import {
40
+ ModuleSignatureError,
41
+ resolveModuleSignaturePolicy,
42
+ verifyModuleArtifact,
43
+ } from "../bundle/signing.js";
44
+ import { extractPublicationRecordCollection } from "../transport/records.js";
45
+
46
+ /**
47
+ * Reduce a module artifact to the bytes a wasm engine can compile.
48
+ *
49
+ * Signed/published artifacts carry an appended publication record collection
50
+ * (MBL bundle with the sds.signature entry, PNM/REC trailers). Wasm engines
51
+ * reject those trailing bytes ("unknown section code"), so the canonical
52
+ * module payload must be extracted before compile. ENC-protected payloads
53
+ * cannot be loaded here — decryption is a host concern.
54
+ *
55
+ * @param {Uint8Array} bytes - raw artifact bytes
56
+ * @returns {Uint8Array} compilable wasm bytes
57
+ */
58
+ export function toLoadableWasmBytes(bytes) {
59
+ const publication = extractPublicationRecordCollection(bytes);
60
+ if (!publication) {
61
+ return bytes;
62
+ }
63
+ if (publication.enc) {
64
+ throw new ModuleSignatureError(
65
+ "encrypted_artifact",
66
+ "Module artifact payload is ENC-protected; decrypt it before loading.",
67
+ );
68
+ }
69
+ return publication.payloadBytes;
70
+ }
71
+
72
+ const STANDALONE_SHARED_MEMORY_ENV_STUBS = Object.freeze({
73
+ _emscripten_init_main_thread_js: () => 0,
74
+ _emscripten_notify_mailbox_postmessage: () => 0,
75
+ _emscripten_receive_on_main_thread_js: () => 0,
76
+ _emscripten_thread_cleanup: () => 0,
77
+ _emscripten_thread_mailbox_await: () => 0,
78
+ _emscripten_thread_set_strongref: () => 0,
79
+ emscripten_check_blocking_allowed: () => 0,
80
+ emscripten_exit_with_live_runtime: () => 0,
81
+ pthread_mutex_lock: () => 0,
82
+ pthread_mutex_unlock: () => 0,
83
+ pthread_cond_broadcast: () => 0,
84
+ pthread_cond_wait: () => 0,
85
+ emscripten_thread_sleep: () => {},
86
+ __do_set_thread_state: () => {},
87
+ __get_tp: () => 0,
88
+ });
89
+ const STANDALONE_SHARED_MEMORY_ENV_IMPORTS = new Set([
90
+ "memory",
91
+ ...Object.keys(STANDALONE_SHARED_MEMORY_ENV_STUBS),
92
+ ]);
93
+
94
+ function isStandaloneSharedMemoryEnvImport(entry) {
95
+ return (
96
+ entry.module === "env" &&
97
+ STANDALONE_SHARED_MEMORY_ENV_IMPORTS.has(entry.name) &&
98
+ (entry.name === "memory"
99
+ ? entry.kind === "memory"
100
+ : entry.kind === "function")
101
+ );
102
+ }
103
+
104
+ function usesOnlyStandaloneSharedMemoryEnvImports(envImports) {
105
+ return (
106
+ envImports.length > 0 &&
107
+ envImports.every((entry) => isStandaloneSharedMemoryEnvImport(entry))
108
+ );
109
+ }
110
+
111
+ function addStandaloneSharedMemoryEnvStubs(importObject, moduleImports) {
112
+ const envImports = moduleImports.filter((entry) => entry.module === "env");
113
+ if (!usesOnlyStandaloneSharedMemoryEnvImports(envImports)) {
114
+ return;
115
+ }
116
+
117
+ const envNamespace = {
118
+ ...(importObject.env ?? {}),
119
+ };
120
+ for (const entry of envImports) {
121
+ if (entry.kind !== "function") {
122
+ continue;
123
+ }
124
+ if (typeof envNamespace[entry.name] !== "function") {
125
+ envNamespace[entry.name] = STANDALONE_SHARED_MEMORY_ENV_STUBS[entry.name];
126
+ }
127
+ }
128
+ importObject.env = envNamespace;
129
+ }
32
130
 
33
131
  /**
34
132
  * Detect artifact profile from WebAssembly.Module imports.
35
- * Returns "standalone" (WASI-only), "sdn-abi" (WASI + sdn_host),
133
+ * Returns "standalone" (WASI-only), "module-host-abi" (WASI + space_data_module_host),
36
134
  * or "emscripten" (env.* with invoke trampolines).
37
135
  */
38
136
  export function detectArtifactProfile(wasmModule) {
39
137
  const imports = WebAssembly.Module.imports(wasmModule);
40
138
  const moduleNames = new Set(imports.map((i) => i.module));
139
+ const envImports = imports.filter((i) => i.module === "env");
140
+ const usesStandaloneSharedMemoryEnv =
141
+ usesOnlyStandaloneSharedMemoryEnvImports(envImports);
41
142
 
42
143
  if (moduleNames.has("env")) {
43
- const envImports = imports.filter((i) => i.module === "env");
44
- const hasInvokeTrampolines = envImports.some((i) => i.name.startsWith("invoke_"));
45
- const hasPthreads = envImports.some(
46
- (i) => i.name.includes("pthread") || i.name.includes("thread"),
47
- );
48
- if (hasInvokeTrampolines || hasPthreads) {
49
- return "emscripten";
144
+ if (!usesStandaloneSharedMemoryEnv) {
145
+ const hasInvokeTrampolines = envImports.some((i) =>
146
+ i.name.startsWith("invoke_"),
147
+ );
148
+ const hasPthreads = envImports.some(
149
+ (i) => i.name.includes("pthread") || i.name.includes("thread"),
150
+ );
151
+ if (hasInvokeTrampolines || hasPthreads) {
152
+ return "emscripten";
153
+ }
50
154
  }
51
155
  }
52
156
 
53
157
  if (moduleNames.has(DEFAULT_HOSTCALL_IMPORT_MODULE)) {
54
- return "sdn-abi";
158
+ return "module-host-abi";
55
159
  }
56
160
 
57
161
  if (moduleNames.has("wasi_snapshot_preview1") || moduleNames.has("wasi_unstable")) {
58
162
  return "standalone";
59
163
  }
60
164
 
165
+ if (usesStandaloneSharedMemoryEnv) {
166
+ return "standalone";
167
+ }
168
+
61
169
  return "unknown";
62
170
  }
63
171
 
@@ -65,17 +173,97 @@ async function compileWasmModule(source) {
65
173
  if (source instanceof WebAssembly.Module) {
66
174
  return source;
67
175
  }
176
+ let bytes;
68
177
  if (source instanceof Response) {
69
- return WebAssembly.compileStreaming(source);
178
+ bytes = new Uint8Array(await source.arrayBuffer());
179
+ } else if (typeof source === "string") {
180
+ const response = await fetch(source);
181
+ if (!response.ok) {
182
+ throw new Error(`Failed to fetch module artifact: ${response.status}`);
183
+ }
184
+ bytes = new Uint8Array(await response.arrayBuffer());
185
+ } else {
186
+ bytes = source instanceof ArrayBuffer ? new Uint8Array(source) : source;
187
+ }
188
+ // Strip any appended publication record collection (signature/PNM/REC
189
+ // trailers) — wasm engines reject trailing non-section bytes.
190
+ return WebAssembly.compile(toLoadableWasmBytes(bytes));
191
+ }
192
+
193
+ const WASM_PAGE_BYTES = 65536;
194
+ const DEFAULT_IMPORTED_MEMORY_INITIAL_BYTES = 64 * 1024 * 1024;
195
+ const DEFAULT_IMPORTED_MEMORY_MAXIMUM_BYTES = 2 * 1024 * 1024 * 1024;
196
+ const DEFAULT_DIRECT_INVOKE_REQUEST_ARENA_BYTES = 64 * 1024;
197
+ const SHARED_ARRAY_BUFFER_TAG = "[object SharedArrayBuffer]";
198
+
199
+ export function isSharedArrayBufferLike(value) {
200
+ return (
201
+ value !== null &&
202
+ typeof value === "object" &&
203
+ ((typeof SharedArrayBuffer === "function" &&
204
+ value instanceof SharedArrayBuffer) ||
205
+ Object.prototype.toString.call(value) === SHARED_ARRAY_BUFFER_TAG)
206
+ );
207
+ }
208
+
209
+ function bytesToPages(value, fallbackBytes) {
210
+ const bytes =
211
+ Number.isFinite(value) && value > 0 ? Number(value) : fallbackBytes;
212
+ return Math.ceil(bytes / WASM_PAGE_BYTES);
213
+ }
214
+
215
+ function createImportedMemory(options = {}) {
216
+ const initialPages = bytesToPages(
217
+ options.initialMemoryBytes,
218
+ DEFAULT_IMPORTED_MEMORY_INITIAL_BYTES,
219
+ );
220
+ const maximumPages = Math.max(
221
+ initialPages,
222
+ bytesToPages(
223
+ options.maximumMemoryBytes,
224
+ DEFAULT_IMPORTED_MEMORY_MAXIMUM_BYTES,
225
+ ),
226
+ );
227
+ const descriptor = {
228
+ initial: initialPages,
229
+ maximum: maximumPages,
230
+ };
231
+
232
+ if (options.sharedMemory === true) {
233
+ if (typeof SharedArrayBuffer !== "function") {
234
+ throw new Error(
235
+ "Browser module harness shared imported memory requires SharedArrayBuffer.",
236
+ );
237
+ }
238
+ descriptor.shared = true;
70
239
  }
71
- if (typeof source === "string") {
72
- return WebAssembly.compileStreaming(fetch(source));
240
+
241
+ return new WebAssembly.Memory(descriptor);
242
+ }
243
+
244
+ function resolveManifestSurface(manifest) {
245
+ const surfaces = Array.isArray(manifest?.invokeSurfaces)
246
+ ? manifest.invokeSurfaces
247
+ : [];
248
+ if (surfaces.includes("command")) {
249
+ return "command";
73
250
  }
74
- const bytes = source instanceof ArrayBuffer ? new Uint8Array(source) : source;
75
- return WebAssembly.compile(bytes);
251
+ if (surfaces.includes("direct")) {
252
+ return "direct";
253
+ }
254
+ return null;
76
255
  }
77
256
 
78
257
  async function instantiateBrowserModule(options = {}) {
258
+ let providedMemory = options.wasmMemory ?? options.memory ?? null;
259
+ if (
260
+ providedMemory !== null &&
261
+ !(providedMemory instanceof WebAssembly.Memory)
262
+ ) {
263
+ throw new TypeError(
264
+ "Browser module harness memory must be a WebAssembly.Memory.",
265
+ );
266
+ }
79
267
  const wasi = createBrowserWasiShim({
80
268
  args: options.args ?? [],
81
269
  env: options.env ?? {},
@@ -88,30 +276,111 @@ async function instantiateBrowserModule(options = {}) {
88
276
  const needsHostBridge = moduleImports.some(
89
277
  (entry) => entry.module === DEFAULT_HOSTCALL_IMPORT_MODULE,
90
278
  );
279
+ // Isomorphic-pthreads (wasm32-wasip1-threads) artifacts import
280
+ // `wasi.thread-spawn` over a SHARED imported memory. Such a module can only be
281
+ // instantiated with shared memory, so force it here regardless of the caller's
282
+ // sharedMemory flag; single-thread artifacts are unaffected.
283
+ const isThreaded = isWasiThreadsModule(options.wasmModule);
284
+ const memoryImports = moduleImports.filter((entry) => entry.kind === "memory");
285
+ if (!providedMemory && memoryImports.length > 0) {
286
+ providedMemory = createImportedMemory(
287
+ isThreaded ? { ...options, sharedMemory: true } : options,
288
+ );
289
+ }
290
+ for (const entry of memoryImports) {
291
+ if (!providedMemory) {
292
+ throw new Error(
293
+ `Browser module imports ${entry.module}.${entry.name} memory; pass a WebAssembly.Memory as the memory option.`,
294
+ );
295
+ }
296
+ importObject[entry.module] = {
297
+ ...(importObject[entry.module] ?? {}),
298
+ [entry.name]: providedMemory,
299
+ };
300
+ }
301
+ addStandaloneSharedMemoryEnvStubs(importObject, moduleImports);
302
+
303
+ // Isomorphic-pthreads host: satisfy `wasi.thread-spawn` by running each guest
304
+ // pthread on a real OS thread (Node worker_threads / browser Worker) over the
305
+ // shared imported memory. Only wired for modules that import it.
306
+ let threadHost = null;
307
+ if (isThreaded) {
308
+ if (!providedMemory) {
309
+ throw new Error(
310
+ "wasi-threads module imports wasi.thread-spawn but no shared imported memory is available.",
311
+ );
312
+ }
313
+ threadHost = await createWasiThreadSpawn({
314
+ wasmModule: options.wasmModule,
315
+ memory: providedMemory,
316
+ // Browser warm-pool sizing: cap pooled workers at how many guest threads
317
+ // the module will actually ask for. Ignored by the Node lazy path.
318
+ requestedThreads: options.maxThreads,
319
+ hostcallChannel: options.threadHostcallChannel,
320
+ requiresHostcalls: needsHostBridge,
321
+ enableBrowserThreads: options.enableBrowserWasiThreads,
322
+ });
323
+ importObject.wasi = {
324
+ ...(importObject.wasi ?? {}),
325
+ "thread-spawn": threadHost.threadSpawn,
326
+ };
327
+ }
91
328
 
92
329
  let instance = null;
93
330
  let bridge = null;
331
+ let memory = providedMemory;
94
332
  if (needsHostBridge) {
95
- const dispatch = createHostSyncDispatcher(options.host);
96
- bridge = createJsonHostcallBridge({
333
+ // hostcallDispatch overrides the default sync dispatcher — used by the
334
+ // worker harness to route guest hostcalls through the SAB channel so
335
+ // async host capabilities (http/ipfs/storage/pubsub) become reachable.
336
+ const dispatch =
337
+ typeof options.hostcallDispatch === "function"
338
+ ? options.hostcallDispatch
339
+ : createHostSyncDispatcher(options.host);
340
+ bridge = createHostcallBridge({
97
341
  dispatch,
98
- getMemory: () => instance.exports.memory,
342
+ getMemory: () => memory ?? instance?.exports?.memory,
99
343
  });
100
344
  Object.assign(importObject, bridge.imports);
101
345
  }
102
346
 
103
347
  instance = await WebAssembly.instantiate(options.wasmModule, importObject);
104
- if (instance.exports.memory) {
105
- wasi.setMemory(instance.exports.memory);
348
+ memory = instance.exports.memory ?? providedMemory;
349
+ if (memory) {
350
+ if (
351
+ options.sharedMemory === true &&
352
+ !isSharedArrayBufferLike(memory.buffer)
353
+ ) {
354
+ throw new Error(
355
+ "Browser module harness sharedMemory requires shared WebAssembly.Memory backing.",
356
+ );
357
+ }
358
+ wasi.setMemory(memory);
106
359
  }
107
360
  if (instance.exports._initialize) {
108
361
  instance.exports._initialize();
362
+ } else if (isThreaded && typeof instance.exports._start === "function") {
363
+ // wasi-threads artifacts link the wasi command crt (exports `_start`), not a
364
+ // reactor (`_initialize`). Run `_start` ONCE to execute global constructors
365
+ // + WASI init before any direct invoke. The module declares no command
366
+ // surface, so its main is an empty stub — `_start` runs ctors and proc_exit's
367
+ // out; swallow that exit. Direct-invoke exports remain callable afterward
368
+ // (the linear memory + globals persist).
369
+ try {
370
+ instance.exports._start();
371
+ } catch (error) {
372
+ if (!(error instanceof WasiExitError)) {
373
+ throw error;
374
+ }
375
+ }
109
376
  }
110
377
 
111
378
  return {
112
379
  instance,
113
380
  bridge,
114
381
  wasi,
382
+ memory,
383
+ threadHost,
115
384
  };
116
385
  }
117
386
 
@@ -124,23 +393,69 @@ async function instantiateBrowserModule(options = {}) {
124
393
  * @param {Object} [options.host] - BrowserHost instance (created if omitted).
125
394
  * @param {string[]} [options.args] - WASI args passed to the module.
126
395
  * @param {Object} [options.env] - WASI environment variables.
396
+ * @param {Object} [options.manifest] - Plugin manifest used to choose the invoke surface.
127
397
  * @param {string} [options.surface] - "direct" or "command" (default: auto-detect).
398
+ * @param {WebAssembly.Memory} [options.wasmMemory] - Explicit imported memory.
399
+ * @param {WebAssembly.Memory} [options.memory] - Alias for wasmMemory.
400
+ * @param {boolean} [options.sharedMemory] - Create SharedArrayBuffer-backed imported memory.
401
+ * @param {boolean} [options.allowRawInvoke] - Permit direct-surface raw byte-frame invoke.
402
+ * @param {number} [options.initialMemoryBytes] - Initial imported memory size.
403
+ * @param {number} [options.maximumMemoryBytes] - Maximum imported memory size.
404
+ * @param {number} [options.maxThreads] - Upper bound on guest threads; sizes the
405
+ * browser wasi-threads warm pool. Ignored by single-thread artifacts and by
406
+ * the Node lazy worker path.
128
407
  */
129
408
  export async function createBrowserModuleHarness(options = {}) {
130
- const wasmModule = await compileWasmModule(options.wasmSource);
409
+ let wasmSource = options.wasmSource;
410
+ const signaturePolicy = resolveModuleSignaturePolicy(options);
411
+ if (signaturePolicy) {
412
+ if (wasmSource instanceof WebAssembly.Module) {
413
+ throw new ModuleSignatureError(
414
+ "unverifiable_source",
415
+ "Cannot verify a precompiled WebAssembly.Module; pass bytes, a URL, or a Response when signature verification is enabled.",
416
+ );
417
+ }
418
+ let artifactBytes;
419
+ if (wasmSource instanceof Response) {
420
+ artifactBytes = new Uint8Array(await wasmSource.arrayBuffer());
421
+ } else if (typeof wasmSource === "string") {
422
+ const response = await fetch(wasmSource);
423
+ if (!response.ok) {
424
+ throw new Error(
425
+ `Failed to fetch module artifact for verification: ${response.status}`,
426
+ );
427
+ }
428
+ artifactBytes = new Uint8Array(await response.arrayBuffer());
429
+ } else {
430
+ artifactBytes =
431
+ wasmSource instanceof ArrayBuffer
432
+ ? new Uint8Array(wasmSource)
433
+ : new Uint8Array(wasmSource);
434
+ }
435
+ await verifyModuleArtifact(artifactBytes, signaturePolicy);
436
+ wasmSource = artifactBytes;
437
+ }
438
+ const wasmModule = await compileWasmModule(wasmSource);
131
439
  const moduleImports = WebAssembly.Module.imports(wasmModule);
132
440
  const needsHostBridge = moduleImports.some(
133
441
  (entry) => entry.module === DEFAULT_HOSTCALL_IMPORT_MODULE,
134
442
  );
443
+ const hasHostcallDispatch = typeof options.hostcallDispatch === "function";
135
444
  const hostOptions =
136
- !options.host && needsHostBridge && !options.hostOptions?.wasmWallet
445
+ !options.host &&
446
+ needsHostBridge &&
447
+ !hasHostcallDispatch &&
448
+ !options.hostOptions?.wasmWallet
137
449
  ? {
138
450
  ...options.hostOptions,
139
451
  wasmWallet: await getWasmWallet(),
140
452
  }
141
453
  : options.hostOptions;
142
- const host = options.host ?? createBrowserHost(hostOptions);
143
- const dispatchHost = createAsyncHostDispatcher(host);
454
+ // With an external hostcallDispatch (worker harness), the host lives on the
455
+ // controlling thread — skip constructing a default local host.
456
+ const host =
457
+ options.host ?? (hasHostcallDispatch ? null : createBrowserHost(hostOptions));
458
+ const dispatchHost = host ? createAsyncHostDispatcher(host) : null;
144
459
 
145
460
  const profile = detectArtifactProfile(wasmModule);
146
461
  const moduleExports = WebAssembly.Module.exports(wasmModule);
@@ -148,11 +463,14 @@ export async function createBrowserModuleHarness(options = {}) {
148
463
 
149
464
  const hasDirectInvoke = exportNames.has(DefaultInvokeExports.invokeSymbol);
150
465
  const hasCommand = exportNames.has(DefaultInvokeExports.commandSymbol);
466
+ const manifestSurface = resolveManifestSurface(options.manifest);
151
467
  const surface =
152
- options.surface ?? (hasDirectInvoke ? "direct" : hasCommand ? "command" : "direct");
468
+ options.surface ??
469
+ manifestSurface ??
470
+ (hasDirectInvoke ? "direct" : hasCommand ? "command" : "direct");
153
471
  if (profile === "emscripten") {
154
472
  throw new Error(
155
- "Browser harness only supports standalone WASI or sdn_host artifacts. " +
473
+ "Browser harness only supports standalone WASI or space_data_module_host artifacts. " +
156
474
  'Compile shared browser/WasmEdge modules with runtimeTargets: ["browser", "wasmedge"] ' +
157
475
  'or override threadModel to "single-thread".',
158
476
  );
@@ -161,19 +479,28 @@ export async function createBrowserModuleHarness(options = {}) {
161
479
  const activeContext = await instantiateBrowserModule({
162
480
  wasmModule,
163
481
  host,
482
+ hostcallDispatch: options.hostcallDispatch,
164
483
  args: options.args,
165
484
  env: options.env,
166
485
  performance: options.performance ?? host?.performance,
167
486
  logOutput: options.logOutput === true,
487
+ wasmMemory: options.wasmMemory,
488
+ memory: options.memory,
489
+ sharedMemory: options.sharedMemory,
490
+ initialMemoryBytes: options.initialMemoryBytes,
491
+ maximumMemoryBytes: options.maximumMemoryBytes,
492
+ maxThreads: options.maxThreads,
493
+ threadHostcallChannel: options.threadHostcallChannel,
494
+ enableBrowserWasiThreads: options.enableBrowserWasiThreads,
168
495
  });
169
- const { instance, bridge, wasi } = activeContext;
496
+ const { instance, bridge, wasi, memory, threadHost } = activeContext;
497
+ const allowRawInvoke = options.allowRawInvoke !== false;
170
498
 
171
499
  // --- Invoke helpers ---
172
- function invokeDirectRaw(requestBytes) {
500
+ function directInvokeRuntime() {
173
501
  const alloc = instance.exports[DefaultInvokeExports.allocSymbol];
174
502
  const free = instance.exports[DefaultInvokeExports.freeSymbol];
175
503
  const invokeStream = instance.exports[DefaultInvokeExports.invokeSymbol];
176
- const memory = instance.exports.memory;
177
504
  if (
178
505
  typeof alloc !== "function" ||
179
506
  typeof free !== "function" ||
@@ -184,9 +511,24 @@ export async function createBrowserModuleHarness(options = {}) {
184
511
  "Direct browser invoke requires plugin_alloc, plugin_free, plugin_invoke_stream, and memory exports.",
185
512
  );
186
513
  }
514
+ return { alloc, free, invokeStream, memory };
515
+ }
516
+
517
+ function invokeDirectRaw(requestBytes) {
518
+ if (!allowRawInvoke) {
519
+ throw new Error(
520
+ "Browser module harness raw direct invoke is disabled; use a SharedArrayBuffer-backed externalArena descriptor.",
521
+ );
522
+ }
523
+ const { alloc, free, invokeStream, memory } = directInvokeRuntime();
187
524
  const reqLen = requestBytes.length;
188
525
  const reqPtr = alloc(reqLen);
189
526
  if (!reqPtr) throw new Error("plugin_alloc returned null for request.");
527
+ if (reqPtr % INVOKE_ARENA_ALIGNMENT !== 0) {
528
+ throw new Error(
529
+ `plugin_alloc returned a request pointer (${reqPtr}) that is not ${INVOKE_ARENA_ALIGNMENT}-byte aligned.`,
530
+ );
531
+ }
190
532
 
191
533
  new Uint8Array(memory.buffer, reqPtr, reqLen).set(requestBytes);
192
534
 
@@ -205,21 +547,210 @@ export async function createBrowserModuleHarness(options = {}) {
205
547
  if (!resPtr || !resLen) {
206
548
  throw new Error("plugin_invoke_stream returned null response.");
207
549
  }
550
+ if (resPtr % INVOKE_ARENA_ALIGNMENT !== 0) {
551
+ throw new Error(
552
+ `plugin_invoke_stream returned a response pointer (${resPtr}) that is not ${INVOKE_ARENA_ALIGNMENT}-byte aligned.`,
553
+ );
554
+ }
555
+
556
+ const responseBytes = new Uint8Array(memory.buffer, resPtr, resLen).slice();
557
+ free(resPtr, resLen);
558
+ return responseBytes;
559
+ }
560
+
561
+ function writeDirectInvokeRequestToModuleMemory(request) {
562
+ const { alloc, free, memory } = directInvokeRuntime();
563
+ const allocationSize = Number(
564
+ request?.requestEnvelopeCapacityBytes ??
565
+ options.directInvokeRequestArenaBytes ??
566
+ DEFAULT_DIRECT_INVOKE_REQUEST_ARENA_BYTES,
567
+ );
568
+ if (!Number.isInteger(allocationSize) || allocationSize <= 0) {
569
+ throw new Error(
570
+ "Direct browser invoke request arena capacity must be a positive integer.",
571
+ );
572
+ }
573
+ const allocationPtr = alloc(allocationSize);
574
+ if (!allocationPtr) {
575
+ throw new Error("plugin_alloc returned null for direct invoke request.");
576
+ }
577
+ if (allocationPtr % INVOKE_ARENA_ALIGNMENT !== 0) {
578
+ free(allocationPtr, allocationSize);
579
+ throw new Error(
580
+ `plugin_alloc returned a direct invoke request pointer (${allocationPtr}) that is not ${INVOKE_ARENA_ALIGNMENT}-byte aligned.`,
581
+ );
582
+ }
583
+ try {
584
+ const arena = new Uint8Array(memory.buffer, allocationPtr, allocationSize);
585
+ const payload = writePluginInvokeRequestToArena(request, arena);
586
+ if (payload.buffer !== memory.buffer) {
587
+ throw new Error(
588
+ "Direct browser invoke request was not authored in module memory.",
589
+ );
590
+ }
591
+ if (payload.byteOffset % INVOKE_ARENA_ALIGNMENT !== 0) {
592
+ throw new Error(
593
+ `Direct browser invoke request pointer (${payload.byteOffset}) is not ${INVOKE_ARENA_ALIGNMENT}-byte aligned.`,
594
+ );
595
+ }
596
+ return {
597
+ ptr: payload.byteOffset,
598
+ size: payload.byteLength,
599
+ allocationPtr,
600
+ allocationSize,
601
+ };
602
+ } catch (error) {
603
+ free(allocationPtr, allocationSize);
604
+ throw error;
605
+ }
606
+ }
607
+
608
+ function freeDirectInvokeRequest({ allocationPtr, allocationSize } = {}) {
609
+ if (
610
+ Number.isInteger(allocationPtr) &&
611
+ Number.isInteger(allocationSize) &&
612
+ allocationPtr > 0 &&
613
+ allocationSize > 0
614
+ ) {
615
+ const { free } = directInvokeRuntime();
616
+ free(allocationPtr, allocationSize);
617
+ }
618
+ }
619
+
620
+ function invokeDirectModuleMemoryRequest({ ptr, size }) {
621
+ const { alloc, free, invokeStream, memory } = directInvokeRuntime();
622
+ if (
623
+ !Number.isInteger(ptr) ||
624
+ !Number.isInteger(size) ||
625
+ ptr <= 0 ||
626
+ size <= 0
627
+ ) {
628
+ throw new Error("Direct browser invoke requires a module-memory request descriptor.");
629
+ }
630
+ if (ptr % INVOKE_ARENA_ALIGNMENT !== 0) {
631
+ throw new Error(
632
+ `Direct browser invoke request pointer (${ptr}) is not ${INVOKE_ARENA_ALIGNMENT}-byte aligned.`,
633
+ );
634
+ }
635
+
636
+ const outLenPtr = alloc(4);
637
+ if (!outLenPtr) throw new Error("plugin_alloc returned null for response length.");
638
+
639
+ new DataView(memory.buffer).setUint32(outLenPtr, 0, true);
640
+
641
+ const resPtr = invokeStream(ptr, size, outLenPtr);
642
+ const resLen = new DataView(memory.buffer).getUint32(outLenPtr, true);
643
+
644
+ free(outLenPtr, 4);
645
+
646
+ if (!resPtr || !resLen) {
647
+ throw new Error("plugin_invoke_stream returned null response.");
648
+ }
649
+ if (resPtr % INVOKE_ARENA_ALIGNMENT !== 0) {
650
+ throw new Error(
651
+ `plugin_invoke_stream returned a response pointer (${resPtr}) that is not ${INVOKE_ARENA_ALIGNMENT}-byte aligned.`,
652
+ );
653
+ }
208
654
 
209
655
  const responseBytes = new Uint8Array(memory.buffer, resPtr, resLen).slice();
210
656
  free(resPtr, resLen);
211
657
  return responseBytes;
212
658
  }
213
659
 
660
+ function assertModuleMemoryExternalArena(externalArena, memory) {
661
+ if (!externalArena) {
662
+ throw new TypeError(
663
+ "Direct external arena invoke requires request.externalArena bytes.",
664
+ );
665
+ }
666
+ if (!isSharedArrayBufferLike(memory.buffer)) {
667
+ throw new Error(
668
+ "Direct externalArena invoke requires SharedArrayBuffer-backed module memory.",
669
+ );
670
+ }
671
+ if (
672
+ externalArena.buffer !== memory.buffer ||
673
+ externalArena.byteOffset !== 0 ||
674
+ externalArena.byteLength !== memory.buffer.byteLength
675
+ ) {
676
+ throw new Error(
677
+ "Direct externalArena invoke requires request.externalArena to be a full Uint8Array view of module memory.",
678
+ );
679
+ }
680
+ }
681
+
682
+ function externalArenaFrameDescriptor(frame, externalArena) {
683
+ if (frame?.payload !== undefined && frame?.payload !== null) {
684
+ throw new Error(
685
+ "Direct externalArena input frames must use offset/size descriptors, not payload bytes.",
686
+ );
687
+ }
688
+ const offset = Number(frame?.offset ?? frame?.OFFSET ?? 0);
689
+ const size = Number(frame?.size ?? frame?.SIZE ?? frame?.byteLength ?? 0);
690
+ if (
691
+ !Number.isInteger(offset) ||
692
+ !Number.isInteger(size) ||
693
+ offset < 0 ||
694
+ size < 0 ||
695
+ offset > externalArena.length ||
696
+ size > externalArena.length - offset
697
+ ) {
698
+ throw new Error("Direct external arena frame range exceeds externalArena.");
699
+ }
700
+ return { offset, size };
701
+ }
702
+
703
+ function externalArenaInputFrames(request) {
704
+ return Array.isArray(request?.inputs)
705
+ ? request.inputs
706
+ : request?.inputFrames ?? [];
707
+ }
708
+
709
+ function invokeDirectExternalArena(request) {
710
+ const { memory } = directInvokeRuntime();
711
+ const externalArena = toUint8Array(request?.externalArena);
712
+ assertModuleMemoryExternalArena(externalArena, memory);
713
+ const inputs = externalArenaInputFrames(request).map((frame) => {
714
+ const { offset, size } = externalArenaFrameDescriptor(frame, externalArena);
715
+ const nextFrame = {
716
+ ...frame,
717
+ offset,
718
+ size,
719
+ };
720
+ delete nextFrame.payload;
721
+ return nextFrame;
722
+ });
723
+ const requestDescriptor = writeDirectInvokeRequestToModuleMemory({
724
+ ...request,
725
+ inputs,
726
+ inputFrames: undefined,
727
+ externalArena,
728
+ });
729
+ try {
730
+ return invokeDirectModuleMemoryRequest(requestDescriptor);
731
+ } finally {
732
+ freeDirectInvokeRequest(requestDescriptor);
733
+ }
734
+ }
735
+
214
736
  async function invokeCommandRaw(stdinBytes) {
215
737
  const commandContext = await instantiateBrowserModule({
216
738
  wasmModule,
217
739
  host,
740
+ hostcallDispatch: options.hostcallDispatch,
218
741
  args: options.args,
219
742
  env: options.env,
220
743
  stdinBytes,
221
744
  performance: options.performance ?? host?.performance,
222
745
  logOutput: false,
746
+ wasmMemory: options.wasmMemory,
747
+ memory: options.memory,
748
+ sharedMemory: options.sharedMemory,
749
+ initialMemoryBytes: options.initialMemoryBytes,
750
+ maximumMemoryBytes: options.maximumMemoryBytes,
751
+ maxThreads: options.maxThreads,
752
+ threadHostcallChannel: options.threadHostcallChannel,
753
+ enableBrowserWasiThreads: options.enableBrowserWasiThreads,
223
754
  });
224
755
  try {
225
756
  const commandExport = commandContext.instance.exports[DefaultInvokeExports.commandSymbol];
@@ -246,13 +777,44 @@ export async function createBrowserModuleHarness(options = {}) {
246
777
  return invokeDirectRaw(requestBytes);
247
778
  }
248
779
 
780
+ async function invokeDirect(request) {
781
+ if (surface !== "direct") {
782
+ throw new Error(
783
+ "Browser module harness direct invoke requires the direct surface.",
784
+ );
785
+ }
786
+ if (request?.externalArena !== undefined) {
787
+ const responseBytes = invokeDirectExternalArena(request);
788
+ const { memory } = directInvokeRuntime();
789
+ const externalArena = new Uint8Array(memory.buffer);
790
+ assertModuleMemoryExternalArena(externalArena, memory);
791
+ return decodePluginInvokeResponse(responseBytes, { externalArena });
792
+ }
793
+ const requestBytes = encodePluginInvokeRequest(request);
794
+ const responseBytes = invokeDirectRaw(requestBytes);
795
+ return decodePluginInvokeResponse(responseBytes);
796
+ }
797
+
249
798
  async function invoke(request) {
799
+ if (request?.externalArena !== undefined && surface === "direct") {
800
+ return invokeDirect(request);
801
+ }
802
+ if (request?.externalArena !== undefined) {
803
+ throw new Error(
804
+ "Browser module harness externalArena invoke requires the direct surface.",
805
+ );
806
+ }
250
807
  const requestBytes = encodePluginInvokeRequest(request);
251
808
  const responseBytes = await invokeRaw(requestBytes);
252
809
  return decodePluginInvokeResponse(responseBytes);
253
810
  }
254
811
 
255
812
  async function callHost(operation, params = {}) {
813
+ if (!dispatchHost) {
814
+ throw new Error(
815
+ "callHost is unavailable: this harness routes hostcalls through an external hostcallDispatch (no local host).",
816
+ );
817
+ }
256
818
  return dispatchHost(operation, params);
257
819
  }
258
820
 
@@ -267,11 +829,16 @@ export async function createBrowserModuleHarness(options = {}) {
267
829
  const size = getSizeExport();
268
830
  if (!ptr || !size) return null;
269
831
 
270
- return new Uint8Array(instance.exports.memory.buffer, ptr, size).slice();
832
+ if (!memory) return null;
833
+
834
+ return new Uint8Array(memory.buffer, ptr, size).slice();
271
835
  }
272
836
 
273
837
  function destroy() {
274
838
  wasi.flushOutput();
839
+ if (threadHost) {
840
+ void threadHost.terminateAll();
841
+ }
275
842
  }
276
843
 
277
844
  return {
@@ -285,7 +852,13 @@ export async function createBrowserModuleHarness(options = {}) {
285
852
  host,
286
853
  bridge,
287
854
  wasi,
855
+ memory,
856
+ // Present only for isomorphic-pthreads (wasi-threads) artifacts: exposes the
857
+ // spawn host so callers can observe real thread activity
858
+ // (spawnCount/distinctOsThreadCount).
859
+ threadHost,
288
860
  callHost,
861
+ invokeDirect,
289
862
  invoke,
290
863
  invokeRaw,
291
864
  readManifest,