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
@@ -0,0 +1,910 @@
1
+ // Isomorphic-pthreads guardrail: the enforced flag set + the emitted-artifact
2
+ // validator. `space-data-module-sdk` is the source of truth for isomorphic
3
+ // pthreads module artifacts, so a build that claims pthreads but does not emit a
4
+ // shared-memory/atomics wasm must FAIL the compile here rather than ship.
5
+ //
6
+ // See docs/isomorphic-pthreads.md.
7
+
8
+ import {
9
+ decodeUnsignedLeb128,
10
+ listWasmCustomSections,
11
+ parseWasmModuleSections,
12
+ } from "../bundle/wasm.js";
13
+
14
+ // Mirrors ModuleThreadModel.EMSCRIPTEN_PTHREADS in compileModule.js. Kept as a
15
+ // local literal to avoid an import cycle (compileModule imports this module).
16
+ // NOTE: the enum value string is historical; this model now compiles to a
17
+ // wasi-threads artifact (NOT an Emscripten Web-Worker build). See
18
+ // docs/isomorphic-pthreads.md and wasiThreadsToolchain.js.
19
+ const EMSCRIPTEN_PTHREADS = "emscripten-pthreads";
20
+
21
+ // The non-bypassable final-LINK flag set for the isomorphic-pthreads model.
22
+ //
23
+ // These are the wasm-ld / clang flags that produce a wasi-threads artifact:
24
+ // -pthread select the threads runtime (wasi-threads libc/libc++)
25
+ // -matomics -mbulk-memory enable the atomics + bulk-memory target features
26
+ // -Wl,--import-memory import the (shared) memory from the host (env.memory)
27
+ // -Wl,--shared-memory make that memory shared (SharedArrayBuffer / atomics)
28
+ // -Wl,--max-memory=2GiB required maximum for a shared, growable memory
29
+ //
30
+ // These deliberately do NOT use Emscripten `-s` settings. Emscripten `-pthread`
31
+ // (even with -s STANDALONE_WASM=1) emits the browser-only Web Worker model
32
+ // (env.__pthread_create_js + _emscripten_* mailbox/postMessage imports, no wasi
33
+ // thread-spawn) which CANNOT thread under WasmEdge. `-mthreads` is likewise not
34
+ // used (a MinGW driver flag, not a wasm target feature). The thread guarantee is
35
+ // delivered by these flags AND validated on the emitted artifact by
36
+ // assertPthreadArtifact() below (shared memory + atomics + wasi.thread-spawn
37
+ // import + wasi_thread_start export, and NO Emscripten thread hooks).
38
+ // The ONE sanctioned clang target for every SDK-built guest, threaded or not.
39
+ // assertSequentialArtifact holds the sequential model to it so that the model
40
+ // cannot be used to slip off the isomorphic toolchain via SDN_WASI_TARGET.
41
+ export const SANCTIONED_WASI_TARGET = "wasm32-wasip1-threads";
42
+
43
+ // Link flags a wasi-sequential final link must NEVER carry.
44
+ //
45
+ // The one that MATTERS is `--import-memory`: it makes the guest depend on a
46
+ // host-supplied memory it has no wasi-threads contract to receive, which is
47
+ // precisely what WasmEdge refuses to instantiate.
48
+ //
49
+ // `--shared-memory` is listed too, but NOT because shared memory is a defect —
50
+ // on `wasm32-wasip1-threads` a DECLARED shared memory is the normal, expected
51
+ // driver output for a sequential artifact (the triple implies atomics; see
52
+ // assertSequentialArtifact). Passing it EXPLICITLY is rejected only as a
53
+ // configuration smell: it signals someone reaching for the threaded profile in
54
+ // a sequential link, and it is free to catch at flag time.
55
+ const SEQUENTIAL_FORBIDDEN_LINK_FLAGS = Object.freeze([
56
+ "-Wl,--shared-memory",
57
+ "-Wl,--import-memory",
58
+ ]);
59
+
60
+ /**
61
+ * The mirror of assertPthreadFlagsPresent: after the final-link args are
62
+ * assembled for the wasi-sequential model, confirm none of the thread-memory
63
+ * flags survived. A future edit that reuses PTHREAD_FINAL_LINK_FLAGS for the
64
+ * sequential profile fails here, loudly, instead of silently shipping a guest
65
+ * that needs cross-origin isolation to load in a browser.
66
+ *
67
+ * @param {string[]} args assembled final-link argument list.
68
+ * @param {{ threadModel?: string }} [context]
69
+ */
70
+ export function assertSequentialFlagsAbsent(args, context = {}) {
71
+ const present = SEQUENTIAL_FORBIDDEN_LINK_FLAGS.filter((flag) =>
72
+ (Array.isArray(args) ? args : []).includes(flag),
73
+ );
74
+ if (present.length > 0) {
75
+ throw new Error(
76
+ `wasi-sequential final-link args must not contain ${present.join(" ")} ` +
77
+ `(threadModel ${JSON.stringify(context.threadModel ?? "wasi-sequential")}). ` +
78
+ "--import-memory gives the guest a memory it has no wasi-threads contract to " +
79
+ "receive, which is what WasmEdge refuses to instantiate. --shared-memory is " +
80
+ "rejected as a configuration smell, NOT because shared memory is wrong: a " +
81
+ "declared shared memory is the expected driver output on this triple.",
82
+ );
83
+ }
84
+ return args;
85
+ }
86
+ const SEQUENTIAL_MIRROR_PTHREAD_MODEL = "emscripten-pthreads";
87
+
88
+ export const PTHREAD_FINAL_LINK_FLAGS = Object.freeze([
89
+ "-pthread",
90
+ "-matomics",
91
+ "-mbulk-memory",
92
+ "-Wl,--import-memory",
93
+ "-Wl,--shared-memory",
94
+ "-Wl,--max-memory=2147483648",
95
+ ]);
96
+
97
+ // The bare flags that must be present in the assembled final-link args for the
98
+ // pthreads model.
99
+ const PTHREAD_REQUIRED_BARE_FLAGS = Object.freeze([
100
+ "-pthread",
101
+ "-matomics",
102
+ "-mbulk-memory",
103
+ "-Wl,--import-memory",
104
+ "-Wl,--shared-memory",
105
+ ]);
106
+
107
+ // A `-Wl,--max-memory=<n>` flag (any value) must also be present.
108
+ const PTHREAD_MAX_MEMORY_PREFIX = "-Wl,--max-memory=";
109
+
110
+ /**
111
+ * Defensive invariant: after the final-link args are assembled, confirm that the
112
+ * pthreads model still carries every mandated flag. This makes it impossible for
113
+ * a future edit to silently drop a thread-enabling flag — the compile fails loud
114
+ * instead.
115
+ *
116
+ * @param {string[]} args assembled final-link argument list.
117
+ * @param {{ threadModel?: string }} [context]
118
+ */
119
+ export function assertPthreadFlagsPresent(args, context = {}) {
120
+ if (context.threadModel !== EMSCRIPTEN_PTHREADS) {
121
+ return;
122
+ }
123
+ const argList = Array.isArray(args) ? args.map((value) => String(value)) : [];
124
+ const missing = [];
125
+ for (const flag of PTHREAD_REQUIRED_BARE_FLAGS) {
126
+ if (!argList.includes(flag)) {
127
+ missing.push(flag);
128
+ }
129
+ }
130
+ if (!argList.some((value) => value.startsWith(PTHREAD_MAX_MEMORY_PREFIX))) {
131
+ missing.push(`${PTHREAD_MAX_MEMORY_PREFIX}<bytes>`);
132
+ }
133
+ if (missing.length > 0) {
134
+ throw new Error(
135
+ "Pthreads final-link flag assembler dropped mandated flags: " +
136
+ `${missing.join(", ")}. The emscripten-pthreads model must always link ` +
137
+ `with ${PTHREAD_FINAL_LINK_FLAGS.join(" ")}.`,
138
+ );
139
+ }
140
+ }
141
+
142
+ const VALTYPE_BYTES = new Set([0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x70, 0x6f]);
143
+
144
+ /**
145
+ * Skip a LEB128-encoded integer (signedness is irrelevant for skipping — only
146
+ * the continuation bits matter). Bounds-checked.
147
+ */
148
+ function skipLeb(bytes, cursor, end) {
149
+ let position = cursor;
150
+ while (position < end) {
151
+ const byte = bytes[position++];
152
+ if ((byte & 0x80) === 0) {
153
+ return position;
154
+ }
155
+ }
156
+ throw new Error("LEB128 immediate ran past end of function body.");
157
+ }
158
+
159
+ /** Decode a LEB128 value AND return the next offset (bounds-checked). */
160
+ function readLeb(bytes, cursor, end) {
161
+ if (cursor >= end) {
162
+ throw new Error("LEB128 immediate ran past end of function body.");
163
+ }
164
+ const info = decodeUnsignedLeb128(bytes, cursor);
165
+ if (info.nextOffset > end) {
166
+ throw new Error("LEB128 immediate ran past end of function body.");
167
+ }
168
+ return info;
169
+ }
170
+
171
+ function skipBlockType(bytes, cursor, end) {
172
+ if (cursor >= end) {
173
+ throw new Error("Block type ran past end of function body.");
174
+ }
175
+ const byte = bytes[cursor];
176
+ // 0x40 (empty), single-byte value types, and single-byte type indices all
177
+ // consume exactly one byte; only a multi-byte (continuation-bit) type index
178
+ // needs a full LEB skip.
179
+ if ((byte & 0x80) !== 0) {
180
+ return skipLeb(bytes, cursor, end);
181
+ }
182
+ return cursor + 1;
183
+ }
184
+
185
+ function skipMemArg(bytes, cursor, end) {
186
+ const alignInfo = readLeb(bytes, cursor, end);
187
+ let position = alignInfo.nextOffset;
188
+ // Multi-memory / memory64: align bit 6 flags a following memory index.
189
+ if ((alignInfo.value & 0x40) !== 0) {
190
+ position = skipLeb(bytes, position, end);
191
+ }
192
+ return skipLeb(bytes, position, end);
193
+ }
194
+
195
+ function skipVec(bytes, cursor, end, bytesPerElement) {
196
+ const countInfo = readLeb(bytes, cursor, end);
197
+ let position = countInfo.nextOffset;
198
+ for (let i = 0; i < countInfo.value; i += 1) {
199
+ if (bytesPerElement === "leb") {
200
+ position = skipLeb(bytes, position, end);
201
+ } else {
202
+ position += bytesPerElement;
203
+ }
204
+ }
205
+ if (position > end) {
206
+ throw new Error("Vector immediate ran past end of function body.");
207
+ }
208
+ return position;
209
+ }
210
+
211
+ /**
212
+ * Walk one function body and count genuine 0xFE-prefixed atomic instructions.
213
+ * This is a real instruction decoder — NOT a byte scan — so `0xFE` bytes that
214
+ * appear inside i32.const / LEB128 / memarg immediates are never miscounted.
215
+ */
216
+ function countAtomicsInFunctionBody(bytes, bodyStart, bodyEnd) {
217
+ let cursor = bodyStart;
218
+ // Local declarations: vec of (count, valtype).
219
+ const localVecCount = readLeb(bytes, cursor, bodyEnd);
220
+ cursor = localVecCount.nextOffset;
221
+ for (let i = 0; i < localVecCount.value; i += 1) {
222
+ cursor = skipLeb(bytes, cursor, bodyEnd); // count
223
+ if (cursor >= bodyEnd) {
224
+ throw new Error("Local declaration ran past end of function body.");
225
+ }
226
+ // valtype: usually one byte; concrete heap types are a LEB.
227
+ if ((bytes[cursor] & 0x80) !== 0) {
228
+ cursor = skipLeb(bytes, cursor, bodyEnd);
229
+ } else {
230
+ cursor += 1;
231
+ }
232
+ }
233
+
234
+ let atomics = 0;
235
+ while (cursor < bodyEnd) {
236
+ const opcode = bytes[cursor++];
237
+ switch (opcode) {
238
+ // Control / parametric with no immediates.
239
+ case 0x00: // unreachable
240
+ case 0x01: // nop
241
+ case 0x05: // else
242
+ case 0x0b: // end
243
+ case 0x0f: // return
244
+ case 0x1a: // drop
245
+ case 0x1b: // select
246
+ break;
247
+ case 0x02: // block
248
+ case 0x03: // loop
249
+ case 0x04: // if
250
+ cursor = skipBlockType(bytes, cursor, bodyEnd);
251
+ break;
252
+ case 0x0c: // br
253
+ case 0x0d: // br_if
254
+ cursor = skipLeb(bytes, cursor, bodyEnd);
255
+ break;
256
+ case 0x0e: {
257
+ // br_table: vec<labelidx> + default labelidx
258
+ cursor = skipVec(bytes, cursor, bodyEnd, "leb");
259
+ cursor = skipLeb(bytes, cursor, bodyEnd);
260
+ break;
261
+ }
262
+ case 0x10: // call
263
+ case 0x12: // return_call
264
+ cursor = skipLeb(bytes, cursor, bodyEnd);
265
+ break;
266
+ case 0x11: // call_indirect
267
+ case 0x13: // return_call_indirect
268
+ cursor = skipLeb(bytes, cursor, bodyEnd); // typeidx
269
+ cursor = skipLeb(bytes, cursor, bodyEnd); // tableidx
270
+ break;
271
+ case 0x1c: // select t*
272
+ cursor = skipVec(bytes, cursor, bodyEnd, 1);
273
+ break;
274
+ case 0x20: // local.get
275
+ case 0x21: // local.set
276
+ case 0x22: // local.tee
277
+ case 0x23: // global.get
278
+ case 0x24: // global.set
279
+ case 0x25: // table.get
280
+ case 0x26: // table.set
281
+ cursor = skipLeb(bytes, cursor, bodyEnd);
282
+ break;
283
+ case 0x3f: // memory.size
284
+ case 0x40: // memory.grow
285
+ cursor = skipLeb(bytes, cursor, bodyEnd); // memidx (reserved)
286
+ break;
287
+ case 0x41: // i32.const
288
+ case 0x42: // i64.const
289
+ cursor = skipLeb(bytes, cursor, bodyEnd);
290
+ break;
291
+ case 0x43: // f32.const
292
+ cursor += 4;
293
+ break;
294
+ case 0x44: // f64.const
295
+ cursor += 8;
296
+ break;
297
+ case 0xd0: // ref.null
298
+ if (cursor < bodyEnd && (bytes[cursor] & 0x80) !== 0) {
299
+ cursor = skipLeb(bytes, cursor, bodyEnd);
300
+ } else {
301
+ cursor += 1;
302
+ }
303
+ break;
304
+ case 0xd1: // ref.is_null
305
+ break;
306
+ case 0xd2: // ref.func
307
+ cursor = skipLeb(bytes, cursor, bodyEnd);
308
+ break;
309
+ case 0xfc: {
310
+ // Bulk-memory / saturating-truncation / table ops.
311
+ const sub = readLeb(bytes, cursor, bodyEnd);
312
+ cursor = sub.nextOffset;
313
+ switch (sub.value) {
314
+ case 0: case 1: case 2: case 3:
315
+ case 4: case 5: case 6: case 7:
316
+ break; // trunc_sat: no immediates
317
+ case 8: // memory.init dataidx memidx
318
+ cursor = skipLeb(bytes, cursor, bodyEnd);
319
+ cursor = skipLeb(bytes, cursor, bodyEnd);
320
+ break;
321
+ case 9: // data.drop
322
+ cursor = skipLeb(bytes, cursor, bodyEnd);
323
+ break;
324
+ case 10: // memory.copy memidx memidx
325
+ cursor = skipLeb(bytes, cursor, bodyEnd);
326
+ cursor = skipLeb(bytes, cursor, bodyEnd);
327
+ break;
328
+ case 11: // memory.fill memidx
329
+ cursor = skipLeb(bytes, cursor, bodyEnd);
330
+ break;
331
+ case 12: // table.init elemidx tableidx
332
+ case 14: // table.copy tableidx tableidx
333
+ cursor = skipLeb(bytes, cursor, bodyEnd);
334
+ cursor = skipLeb(bytes, cursor, bodyEnd);
335
+ break;
336
+ case 13: // elem.drop
337
+ case 15: // table.grow
338
+ case 16: // table.size
339
+ case 17: // table.fill
340
+ cursor = skipLeb(bytes, cursor, bodyEnd);
341
+ break;
342
+ default:
343
+ break;
344
+ }
345
+ break;
346
+ }
347
+ case 0xfd: {
348
+ // SIMD (not emitted by our pthreads builds, but decode defensively).
349
+ const sub = readLeb(bytes, cursor, bodyEnd);
350
+ cursor = sub.nextOffset;
351
+ const op = sub.value;
352
+ if (op <= 0x0b) {
353
+ cursor = skipMemArg(bytes, cursor, bodyEnd); // v128 load/store
354
+ } else if (op === 0x0c || op === 0x0d) {
355
+ cursor += 16; // v128.const / i8x16.shuffle
356
+ } else if (op >= 0x15 && op <= 0x22) {
357
+ cursor += 1; // extract/replace lane
358
+ } else if (op >= 0x54 && op <= 0x5b) {
359
+ cursor = skipMemArg(bytes, cursor, bodyEnd);
360
+ cursor += 1; // load/store lane
361
+ } else if (op === 0x5c || op === 0x5d) {
362
+ cursor = skipMemArg(bytes, cursor, bodyEnd); // load32/64_zero
363
+ }
364
+ break;
365
+ }
366
+ case 0xfe: {
367
+ // Atomics / threads.
368
+ const sub = readLeb(bytes, cursor, bodyEnd);
369
+ cursor = sub.nextOffset;
370
+ atomics += 1;
371
+ if (sub.value === 0x03) {
372
+ cursor += 1; // atomic.fence: one reserved byte, no memarg
373
+ } else {
374
+ cursor = skipMemArg(bytes, cursor, bodyEnd);
375
+ }
376
+ break;
377
+ }
378
+ default:
379
+ if (opcode >= 0x28 && opcode <= 0x3e) {
380
+ // Memory load/store family (i32.load .. i64.store32): each carries a
381
+ // memarg (align + offset). Skipping this is what prevents 0xFE bytes
382
+ // inside memory-offset immediates from being miscounted as atomics.
383
+ cursor = skipMemArg(bytes, cursor, bodyEnd);
384
+ break;
385
+ }
386
+ // All remaining MVP numeric/comparison/conversion opcodes
387
+ // (0x45..0xc4, sign-extension, etc.) take no immediates.
388
+ break;
389
+ }
390
+ if (cursor > bodyEnd) {
391
+ throw new Error("Instruction immediate ran past end of function body.");
392
+ }
393
+ }
394
+ return atomics;
395
+ }
396
+
397
+ function countAtomicInstructions(parsed) {
398
+ const codeSection = parsed.sections.find((section) => section.id === 10);
399
+ if (!codeSection) {
400
+ return 0;
401
+ }
402
+ const bytes = parsed.bytes;
403
+ let total = 0;
404
+ try {
405
+ let cursor = codeSection.payloadStart;
406
+ const funcCount = readLeb(bytes, cursor, codeSection.payloadEnd);
407
+ cursor = funcCount.nextOffset;
408
+ for (let i = 0; i < funcCount.value && cursor < codeSection.payloadEnd; i += 1) {
409
+ const sizeInfo = readLeb(bytes, cursor, codeSection.payloadEnd);
410
+ const bodyStart = sizeInfo.nextOffset;
411
+ const bodyEnd = bodyStart + sizeInfo.value;
412
+ if (bodyEnd > codeSection.payloadEnd) {
413
+ break;
414
+ }
415
+ try {
416
+ total += countAtomicsInFunctionBody(bytes, bodyStart, bodyEnd);
417
+ } catch {
418
+ // Best-effort per function: skip an undecodable body rather than crash.
419
+ }
420
+ cursor = bodyEnd;
421
+ }
422
+ } catch {
423
+ // Truncated / malformed code section: return best-effort count.
424
+ }
425
+ return total;
426
+ }
427
+
428
+ function readLimits(bytes, cursor, end) {
429
+ const flags = bytes[cursor];
430
+ let position = cursor + 1;
431
+ const minInfo = decodeUnsignedLeb128(bytes, position);
432
+ position = minInfo.nextOffset;
433
+ let max = null;
434
+ if ((flags & 0x01) !== 0) {
435
+ const maxInfo = decodeUnsignedLeb128(bytes, position);
436
+ position = maxInfo.nextOffset;
437
+ max = maxInfo.value;
438
+ }
439
+ return {
440
+ nextOffset: position,
441
+ limits: {
442
+ flags,
443
+ min: minInfo.value,
444
+ max,
445
+ shared: (flags & 0x02) !== 0,
446
+ growable: max === null || max > minInfo.value,
447
+ },
448
+ };
449
+ }
450
+
451
+ const textDecoder = new TextDecoder();
452
+
453
+ function collectImportedMemories(parsed) {
454
+ const section = parsed.sections.find((s) => s.id === 2);
455
+ if (!section) {
456
+ return [];
457
+ }
458
+ const bytes = parsed.bytes;
459
+ const memories = [];
460
+ let cursor = section.payloadStart;
461
+ const countInfo = decodeUnsignedLeb128(bytes, cursor);
462
+ cursor = countInfo.nextOffset;
463
+ for (let i = 0; i < countInfo.value; i += 1) {
464
+ const modLen = decodeUnsignedLeb128(bytes, cursor);
465
+ cursor = modLen.nextOffset;
466
+ const moduleName = textDecoder.decode(bytes.subarray(cursor, cursor + modLen.value));
467
+ cursor += modLen.value;
468
+ const nameLen = decodeUnsignedLeb128(bytes, cursor);
469
+ cursor = nameLen.nextOffset;
470
+ const importName = textDecoder.decode(bytes.subarray(cursor, cursor + nameLen.value));
471
+ cursor += nameLen.value;
472
+ const kind = bytes[cursor++];
473
+ if (kind === 0x00) {
474
+ cursor = decodeUnsignedLeb128(bytes, cursor).nextOffset; // typeidx
475
+ } else if (kind === 0x01) {
476
+ cursor += 1; // reftype
477
+ const limits = readLimits(bytes, cursor, section.payloadEnd);
478
+ cursor = limits.nextOffset;
479
+ } else if (kind === 0x02) {
480
+ const limits = readLimits(bytes, cursor, section.payloadEnd);
481
+ cursor = limits.nextOffset;
482
+ memories.push({
483
+ source: "import",
484
+ module: moduleName,
485
+ name: importName,
486
+ ...limits.limits,
487
+ });
488
+ } else if (kind === 0x03) {
489
+ cursor += 1; // valtype
490
+ cursor += 1; // mutability
491
+ } else {
492
+ break;
493
+ }
494
+ }
495
+ return memories;
496
+ }
497
+
498
+ function collectDeclaredMemories(parsed) {
499
+ const section = parsed.sections.find((s) => s.id === 5);
500
+ if (!section) {
501
+ return [];
502
+ }
503
+ const bytes = parsed.bytes;
504
+ const memories = [];
505
+ let cursor = section.payloadStart;
506
+ const countInfo = decodeUnsignedLeb128(bytes, cursor);
507
+ cursor = countInfo.nextOffset;
508
+ for (let i = 0; i < countInfo.value; i += 1) {
509
+ const limits = readLimits(bytes, cursor, section.payloadEnd);
510
+ cursor = limits.nextOffset;
511
+ memories.push({ source: "declared", ...limits.limits });
512
+ }
513
+ return memories;
514
+ }
515
+
516
+ const IMPORT_KIND_NAMES = ["function", "table", "memory", "global"];
517
+
518
+ function collectAllImports(parsed) {
519
+ const section = parsed.sections.find((s) => s.id === 2);
520
+ if (!section) {
521
+ return [];
522
+ }
523
+ const bytes = parsed.bytes;
524
+ const imports = [];
525
+ let cursor = section.payloadStart;
526
+ const countInfo = decodeUnsignedLeb128(bytes, cursor);
527
+ cursor = countInfo.nextOffset;
528
+ for (let i = 0; i < countInfo.value; i += 1) {
529
+ const modLen = decodeUnsignedLeb128(bytes, cursor);
530
+ cursor = modLen.nextOffset;
531
+ const moduleName = textDecoder.decode(bytes.subarray(cursor, cursor + modLen.value));
532
+ cursor += modLen.value;
533
+ const nameLen = decodeUnsignedLeb128(bytes, cursor);
534
+ cursor = nameLen.nextOffset;
535
+ const importName = textDecoder.decode(bytes.subarray(cursor, cursor + nameLen.value));
536
+ cursor += nameLen.value;
537
+ const kind = bytes[cursor++];
538
+ imports.push({ module: moduleName, name: importName, kind: IMPORT_KIND_NAMES[kind] ?? kind });
539
+ if (kind === 0x00) {
540
+ cursor = decodeUnsignedLeb128(bytes, cursor).nextOffset; // typeidx
541
+ } else if (kind === 0x01) {
542
+ cursor += 1; // reftype
543
+ const limits = readLimits(bytes, cursor, section.payloadEnd);
544
+ cursor = limits.nextOffset;
545
+ } else if (kind === 0x02) {
546
+ const limits = readLimits(bytes, cursor, section.payloadEnd);
547
+ cursor = limits.nextOffset;
548
+ } else if (kind === 0x03) {
549
+ cursor += 2; // valtype + mutability
550
+ } else {
551
+ break;
552
+ }
553
+ }
554
+ return imports;
555
+ }
556
+
557
+ function collectExportNames(parsed) {
558
+ const section = parsed.sections.find((s) => s.id === 7);
559
+ if (!section) {
560
+ return [];
561
+ }
562
+ const bytes = parsed.bytes;
563
+ const names = [];
564
+ let cursor = section.payloadStart;
565
+ const countInfo = decodeUnsignedLeb128(bytes, cursor);
566
+ cursor = countInfo.nextOffset;
567
+ for (let i = 0; i < countInfo.value; i += 1) {
568
+ const nameLen = decodeUnsignedLeb128(bytes, cursor);
569
+ cursor = nameLen.nextOffset;
570
+ names.push(textDecoder.decode(bytes.subarray(cursor, cursor + nameLen.value)));
571
+ cursor += nameLen.value;
572
+ cursor += 1; // export kind
573
+ cursor = decodeUnsignedLeb128(bytes, cursor).nextOffset; // index
574
+ }
575
+ return names;
576
+ }
577
+
578
+ // The WasmEdge/wasi thread-spawn host contract: the guest imports a
579
+ // `thread-spawn` function and exports `wasi_thread_start`.
580
+ function isWasiThreadSpawnImport(entry) {
581
+ return (
582
+ (entry.module === "wasi" || entry.module === "wasi_snapshot_preview1") &&
583
+ entry.name === "thread-spawn"
584
+ );
585
+ }
586
+
587
+ // Emscripten's browser-only Web Worker thread hooks. Their presence means the
588
+ // artifact threads via JS postMessage workers and CANNOT spawn threads under
589
+ // WasmEdge — it must be rejected as an isomorphic-pthreads artifact.
590
+ function isEmscriptenThreadHook(entry) {
591
+ if (entry.module !== "env") {
592
+ return false;
593
+ }
594
+ return (
595
+ entry.name === "__pthread_create_js" ||
596
+ /pthread_create/.test(entry.name) ||
597
+ /^_?emscripten_.*(thread|mailbox|main_thread|postmessage)/i.test(entry.name)
598
+ );
599
+ }
600
+
601
+ function readDeclaredFeatures(wasmBytes) {
602
+ let customSections;
603
+ try {
604
+ customSections = listWasmCustomSections(wasmBytes);
605
+ } catch {
606
+ return null;
607
+ }
608
+ const featureSection = customSections.find(
609
+ (section) => section.name === "target_features",
610
+ );
611
+ if (!featureSection) {
612
+ return null;
613
+ }
614
+ const bytes = featureSection.dataBytes;
615
+ const features = [];
616
+ try {
617
+ let cursor = 0;
618
+ const countInfo = decodeUnsignedLeb128(bytes, cursor);
619
+ cursor = countInfo.nextOffset;
620
+ for (let i = 0; i < countInfo.value; i += 1) {
621
+ cursor += 1; // prefix ('+', '-', '=')
622
+ const nameLen = decodeUnsignedLeb128(bytes, cursor);
623
+ cursor = nameLen.nextOffset;
624
+ features.push(
625
+ textDecoder.decode(bytes.subarray(cursor, cursor + nameLen.value)),
626
+ );
627
+ cursor += nameLen.value;
628
+ }
629
+ } catch {
630
+ return features.length > 0 ? features : null;
631
+ }
632
+ return features;
633
+ }
634
+
635
+ /**
636
+ * Parse a compiled wasm artifact and report its threading features, including
637
+ * the isomorphic wasi-threads host contract.
638
+ *
639
+ * @param {Uint8Array|ArrayBuffer|ArrayBufferView} wasmBytes
640
+ * @returns {{
641
+ * hasSharedMemory: boolean,
642
+ * sharedMemory: object|null,
643
+ * memories: object[],
644
+ * usesAtomics: boolean,
645
+ * atomicInstructionCount: number,
646
+ * declaredFeatures: string[]|null,
647
+ * isGrowableSharedMemory: boolean,
648
+ * hasWasiThreadSpawnImport: boolean,
649
+ * hasWasiThreadStartExport: boolean,
650
+ * emscriptenThreadHooks: string[],
651
+ * isIsomorphicPthreads: boolean,
652
+ * }}
653
+ */
654
+ export function analyzeWasmThreadFeatures(wasmBytes) {
655
+ const parsed = parseWasmModuleSections(wasmBytes);
656
+ const memories = [
657
+ ...collectImportedMemories(parsed),
658
+ ...collectDeclaredMemories(parsed),
659
+ ];
660
+ const sharedMemory = memories.find((memory) => memory.shared) ?? null;
661
+ const atomicInstructionCount = countAtomicInstructions(parsed);
662
+ const declaredFeatures = readDeclaredFeatures(parsed.bytes);
663
+ const usesAtomics =
664
+ atomicInstructionCount > 0 ||
665
+ (Array.isArray(declaredFeatures) && declaredFeatures.includes("atomics"));
666
+ const imports = collectAllImports(parsed);
667
+ const exportNames = collectExportNames(parsed);
668
+ const hasWasiThreadSpawnImport = imports.some(isWasiThreadSpawnImport);
669
+ const hasWasiThreadStartExport = exportNames.includes("wasi_thread_start");
670
+ const emscriptenThreadHooks = imports
671
+ .filter(isEmscriptenThreadHook)
672
+ .map((entry) => `${entry.module}.${entry.name}`);
673
+ const hasSharedMemory = sharedMemory !== null;
674
+ return {
675
+ hasSharedMemory,
676
+ sharedMemory,
677
+ memories,
678
+ usesAtomics,
679
+ atomicInstructionCount,
680
+ declaredFeatures,
681
+ isGrowableSharedMemory: hasSharedMemory && sharedMemory.growable === true,
682
+ hasWasiThreadSpawnImport,
683
+ hasWasiThreadStartExport,
684
+ emscriptenThreadHooks,
685
+ isIsomorphicPthreads:
686
+ hasSharedMemory &&
687
+ usesAtomics &&
688
+ hasWasiThreadSpawnImport &&
689
+ hasWasiThreadStartExport &&
690
+ emscriptenThreadHooks.length === 0,
691
+ };
692
+ }
693
+
694
+ /**
695
+ * Reject a compiled wasm artifact that claims the isomorphic-pthreads thread
696
+ * model but is not a real wasi-threads artifact. To pass, the emitted wasm MUST:
697
+ * - declare/import a shared memory (shared limits flag), and
698
+ * - use atomics (atomic instructions in the code section), and
699
+ * - import the wasi `thread-spawn` host function, and
700
+ * - export `wasi_thread_start`, and
701
+ * - NOT import Emscripten's browser-only Web Worker thread hooks
702
+ * (env.__pthread_create_js / env._emscripten_* mailbox/postMessage), which
703
+ * cannot spawn threads under WasmEdge.
704
+ *
705
+ * Shared memory + atomics alone are necessary but NOT sufficient — an Emscripten
706
+ * `-pthread` browser build has both yet threads only via JS workers. Returns the
707
+ * analysis on success; throws a clear, actionable error otherwise.
708
+ *
709
+ * @param {Uint8Array|ArrayBuffer|ArrayBufferView} wasmBytes
710
+ * @param {{ source?: string }} [options]
711
+ */
712
+ export function assertPthreadArtifact(wasmBytes, options = {}) {
713
+ const source = options.source ? String(options.source) : "emitted wasm";
714
+ let analysis;
715
+ try {
716
+ analysis = analyzeWasmThreadFeatures(wasmBytes);
717
+ } catch (error) {
718
+ throw new Error(
719
+ `pthreads artifact validation failed for ${source}: could not parse the ` +
720
+ `emitted wasm (${error instanceof Error ? error.message : String(error)}).`,
721
+ );
722
+ }
723
+ const failures = [];
724
+ if (!analysis.hasSharedMemory) {
725
+ failures.push(
726
+ "it declares no shared memory (a threaded module must import or declare a " +
727
+ "memory with the shared limits flag)",
728
+ );
729
+ }
730
+ if (!analysis.usesAtomics) {
731
+ failures.push(
732
+ "it uses no atomics (no atomic/threads instructions were found in the code section)",
733
+ );
734
+ }
735
+ if (!analysis.hasWasiThreadSpawnImport) {
736
+ failures.push(
737
+ "it does not import the wasi `thread-spawn` host function (WasmEdge cannot " +
738
+ "spawn guest threads without the wasi-threads contract)",
739
+ );
740
+ }
741
+ if (!analysis.hasWasiThreadStartExport) {
742
+ failures.push(
743
+ "it does not export `wasi_thread_start` (the wasi-threads entry a host " +
744
+ "invokes to run a spawned thread)",
745
+ );
746
+ }
747
+ if (analysis.emscriptenThreadHooks.length > 0) {
748
+ failures.push(
749
+ "it imports Emscripten's browser-only Web Worker thread hooks " +
750
+ `(${analysis.emscriptenThreadHooks.join(", ")}) — this is a JS-worker ` +
751
+ "build that cannot thread under WasmEdge, not an isomorphic artifact",
752
+ );
753
+ }
754
+ if (failures.length > 0) {
755
+ throw new Error(
756
+ `isomorphic-pthreads artifact validation REJECTED ${source}: the build ` +
757
+ "claims the pthreads thread model but the emitted wasm is not a valid " +
758
+ `wasi-threads shared-memory/atomics artifact — ${failures.join("; ")}. ` +
759
+ "This build must not ship.",
760
+ );
761
+ }
762
+ return analysis;
763
+ }
764
+
765
+ /**
766
+ * The MIRROR of assertPthreadArtifact, for the wasi-sequential thread model.
767
+ *
768
+ * A module that declares itself sequential is making a permanent architectural
769
+ * claim: this guest can never spawn a thread. That claim buys it a
770
+ * self-contained artifact (its own memory, no wasi-threads contract) which is
771
+ * what lets an inherently-sequential guest instantiate under WasmEdge at all —
772
+ * an artifact that imports `env.memory` without exporting `wasi_thread_start`
773
+ * is an INCOMPLETE wasi-threads contract and WasmEdge refuses it with
774
+ * "unknown import: env.memory".
775
+ *
776
+ * So the guard is the exact inverse of the pthreads one. To pass, the emitted
777
+ * wasm MUST:
778
+ * - declare NO shared memory (a sequential guest owns an unshared memory), and
779
+ * - NOT import the wasi `thread-spawn` host function, and
780
+ * - NOT export `wasi_thread_start`, and
781
+ * - NOT import Emscripten's browser-only Web Worker thread hooks.
782
+ *
783
+ * It must ALSO have been produced by the sanctioned target. Without that check
784
+ * `SDN_WASI_TARGET` would be an unpoliced route to a plain `wasm32-wasip1`
785
+ * object: the sequential model would become a way to leave the isomorphic
786
+ * toolchain entirely, which is the opposite of its purpose.
787
+ *
788
+ * @param {Uint8Array|ArrayBuffer|ArrayBufferView} wasmBytes
789
+ * @param {{ source?: string, target?: string }} [options]
790
+ */
791
+ export function assertSequentialArtifact(wasmBytes, options = {}) {
792
+ const source = options.source ? String(options.source) : "emitted wasm";
793
+ let analysis;
794
+ try {
795
+ analysis = analyzeWasmThreadFeatures(wasmBytes);
796
+ } catch (error) {
797
+ throw new Error(
798
+ `wasi-sequential artifact validation failed for ${source}: could not parse the ` +
799
+ `emitted wasm (${error instanceof Error ? error.message : String(error)}).`,
800
+ );
801
+ }
802
+
803
+ const failures = [];
804
+
805
+ // WHY THIS GUARD REJECTS AN IMPORTED MEMORY BUT NOT THE SHARED LIMITS BIT.
806
+ //
807
+ // READ THIS FIRST: on `wasm32-wasip1-threads` a DECLARED shared memory is the
808
+ // NORMAL, EXPECTED output for a sequential artifact — it is not a defect and
809
+ // not a hole. "Self-contained" here means the guest OWNS its memory; it does
810
+ // NOT mean "has no SharedArrayBuffer dependency". Those are different claims,
811
+ // and conflating them is what re-opens this argument.
812
+ //
813
+ // Read this before tightening the guard to "no shared memory" — on the
814
+ // mandated target that change is UNSATISFIABLE, and here is the measured
815
+ // reason rather than an assertion.
816
+ //
817
+ // ROOT CAUSE: the `wasm32-wasip1-threads` TRIPLE implies the `atomics` target
818
+ // feature. `wasm-objdump -x` on an object compiled for that triple with
819
+ // NEITHER `-matomics` NOR `-pthread` still reports
820
+ // `target_features: [+] atomics`. wasm-ld then infers a shared memory from
821
+ // that feature, so the DECLARED memory carries limits flags 0x03 with no
822
+ // `--shared-memory` anywhere on the link line. `--no-shared-memory` is not a
823
+ // wasm-ld flag ("unknown argument"). So "reject any shared limits bit" and
824
+ // "require target wasm32-wasip1-threads" cannot both hold — every artifact on
825
+ // that target would be rejected.
826
+ //
827
+ // Measured three ways on clang 22.1.2 + homebrew wasi-libc, all giving a
828
+ // DECLARED memory with flags 0x03: (a) threads-libc objects with no atomics
829
+ // flags; (b) the same objects with `-matomics -pthread`; (c) `--shared-memory`
830
+ // passed WITHOUT `--import-memory`.
831
+ //
832
+ // ARBITRATED 2026-07-28 on the SDK's OWN resolved toolchain (the exact
833
+ // clang/sysroot/resource-dir that resolveWasiThreadsToolchain picks), because
834
+ // an architecture review initially measured the opposite and required a
835
+ // "no shared memory" clause. Three independent re-runs:
836
+ // 1. bare `--target=wasm32-wasip1-threads`, zero feature flags
837
+ // -> `+atomics` present in target_features. Triple-implies-atomics holds.
838
+ // 2. driver-default link of `int main(){}` on that triple
839
+ // -> DECLARED shared memory (0x03) with no shared/import flag anywhere.
840
+ // 3. the review's own counter-artifacts were found to LACK `+atomics`,
841
+ // i.e. they had been built on the NON-threads triple that the same
842
+ // review's target clause forbids — so the counter-measurement did not
843
+ // apply to the mandated target.
844
+ // The "no shared memory" clause was therefore DROPPED as
845
+ // unsatisfiable-as-measured. Recorded here so nobody re-derives it from
846
+ // first principles and re-breaks the model.
847
+ //
848
+ // WHAT THE GUARD DOES ENFORCE, and why it is the property that matters:
849
+ // an artifact that IMPORTS `env.memory` while exporting no `wasi_thread_start`
850
+ // is an incomplete wasi-threads contract, and WasmEdge refuses to instantiate
851
+ // it — "unknown import: env.memory", reproduced on both the native 0.16.4
852
+ // binary and the pinned Docker image. A module that OWNS and exports its
853
+ // memory instantiates cleanly in every runtime.
854
+ //
855
+ // The residual exposure — a module-declared shared memory implies a
856
+ // SharedArrayBuffer / COOP-COEP dependency in the browser — is REAL, but it is
857
+ // a property of the mandated target itself and is shared by EVERY SDK guest,
858
+ // so this guard cannot remove it. Tracked as its own task because it decides
859
+ // whether browser-served modules need cross-origin isolation.
860
+ //
861
+ // What IS fixable here is a misconfiguration: explicitly passing
862
+ // `--shared-memory` / `--import-memory` into a sequential link. wasm-ld
863
+ // accepts `--shared-memory` even WITHOUT `--import-memory`, and an
864
+ // artifact-only check cannot tell that apart from the driver's own doing.
865
+ // assertSequentialFlagsAbsent() rejects it at flag time, which is the layer
866
+ // where the intent actually exists.
867
+ const importedMemories = analysis.memories.filter((memory) => memory.source === "import");
868
+ if (importedMemories.length > 0) {
869
+ failures.push(
870
+ "it IMPORTS its memory — a sequential guest must declare and export its own " +
871
+ "memory, because importing one without exporting `wasi_thread_start` is an " +
872
+ "incomplete wasi-threads contract that WasmEdge refuses to instantiate",
873
+ );
874
+ }
875
+ if (analysis.hasWasiThreadSpawnImport) {
876
+ failures.push(
877
+ "it imports the wasi `thread-spawn` host function — a guest that can spawn " +
878
+ `threads must declare threadModel "${SEQUENTIAL_MIRROR_PTHREAD_MODEL}", not wasi-sequential`,
879
+ );
880
+ }
881
+ if (analysis.hasWasiThreadStartExport) {
882
+ failures.push(
883
+ "it exports `wasi_thread_start` — that is the wasi-threads entry point, " +
884
+ "which a sequential guest must not have",
885
+ );
886
+ }
887
+ if (analysis.emscriptenThreadHooks.length > 0) {
888
+ failures.push(
889
+ "it imports Emscripten's browser-only Web Worker thread hooks " +
890
+ `(${analysis.emscriptenThreadHooks.join(", ")})`,
891
+ );
892
+ }
893
+
894
+ const target = options.target === undefined ? null : String(options.target);
895
+ if (target !== null && target !== SANCTIONED_WASI_TARGET) {
896
+ failures.push(
897
+ `it was built for target "${target}" rather than "${SANCTIONED_WASI_TARGET}" — ` +
898
+ "the sequential model is a concurrency exemption, NOT a toolchain exemption, " +
899
+ "and must not become an unpoliced route off the isomorphic target (check SDN_WASI_TARGET)",
900
+ );
901
+ }
902
+
903
+ if (failures.length > 0) {
904
+ throw new Error(
905
+ `wasi-sequential artifact validation REJECTED ${source}: the build claims the ` +
906
+ `sequential thread model but — ${failures.join("; ")}. This build must not ship.`,
907
+ );
908
+ }
909
+ return analysis;
910
+ }