space-data-module-sdk 0.8.18 → 0.8.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "space-data-module-sdk",
3
- "version": "0.8.18",
3
+ "version": "0.8.19",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Module SDK for building, validating, signing, and deploying WebAssembly modules on the Space Data Network.",
6
6
  "type": "module",
@@ -52,6 +52,8 @@ import { runWithEmceptionLock } from "../compiler/emceptionNode.js";
52
52
  import {
53
53
  assertPthreadArtifact,
54
54
  assertPthreadFlagsPresent,
55
+ assertSequentialArtifact,
56
+ assertSequentialFlagsAbsent,
55
57
  PTHREAD_FINAL_LINK_FLAGS,
56
58
  } from "../compiler/pthreadArtifactGuard.js";
57
59
  import { resolveWasiThreadsToolchain } from "../compiler/wasiThreadsToolchain.js";
@@ -96,12 +98,11 @@ const execFileAsync = promisify(execFile);
96
98
  const FLOW_THREAD_MODEL = Object.freeze({
97
99
  SINGLE_THREAD: "single-thread",
98
100
  WASI_THREADS: "wasi-threads",
101
+ WASI_SEQUENTIAL: "wasi-sequential",
99
102
  });
100
103
  const HISTORICAL_PTHREAD_THREAD_MODEL = "emscripten-pthreads";
101
- // A guest built by the clang wasi toolchain that provably never spawns a
102
- // thread. For LINKING purposes it is a wasi-threads object — same target, same
103
- // object format, same ABI — so it unions with wasi-threads rather than
104
- // conflicting with it. See normalizeGuestThreadModel.
104
+ // Sequential and threaded WASI objects can link together. Preserve the
105
+ // distinction until composition: an all-sequential flow must own its memory and not claim thread spawning.
105
106
  const WASI_SEQUENTIAL_THREAD_MODEL = "wasi-sequential";
106
107
 
107
108
  const RUNTIME_ABI_EXPORTS = [
@@ -762,18 +763,12 @@ function normalizeGuestThreadModel(value) {
762
763
  if (normalized === FLOW_THREAD_MODEL.SINGLE_THREAD) {
763
764
  return FLOW_THREAD_MODEL.SINGLE_THREAD;
764
765
  }
766
+ if (normalized === WASI_SEQUENTIAL_THREAD_MODEL) {
767
+ return FLOW_THREAD_MODEL.WASI_SEQUENTIAL;
768
+ }
765
769
  if (
766
770
  normalized === FLOW_THREAD_MODEL.WASI_THREADS ||
767
- normalized === HISTORICAL_PTHREAD_THREAD_MODEL ||
768
- // wasi-sequential collapses to wasi-threads HERE, at the linking layer,
769
- // and only here. The distinction is a property of a guest (may it spawn?),
770
- // not of the object format: both are clang wasm32-wasip1-threads objects
771
- // and link together cleanly. Keeping them separate at this layer would
772
- // make a flow of one sequential node fall through to the emception branch
773
- // and be linked by emcc — exactly the toolchain drift this model exists to
774
- // prevent. The per-guest guarantee is enforced where it belongs: on each
775
- // MODULE artifact, by assertSequentialArtifact.
776
- normalized === WASI_SEQUENTIAL_THREAD_MODEL
771
+ normalized === HISTORICAL_PTHREAD_THREAD_MODEL
777
772
  ) {
778
773
  return FLOW_THREAD_MODEL.WASI_THREADS;
779
774
  }
@@ -1941,6 +1936,9 @@ export function checkFlowProgram({ flow, dependencies = new Map() } = {}) {
1941
1936
  }
1942
1937
  }
1943
1938
 
1939
+ if (threadModels.has(FLOW_THREAD_MODEL.WASI_THREADS)) {
1940
+ threadModels.delete(FLOW_THREAD_MODEL.WASI_SEQUENTIAL);
1941
+ }
1944
1942
  let threadModel =
1945
1943
  threadModels.size === 1
1946
1944
  ? [...threadModels][0]
@@ -2245,6 +2243,12 @@ export function buildFlowModuleManifest({ flow, check, dependencies }) {
2245
2243
  name: flow.name ?? flow.programId,
2246
2244
  version: flow.version ?? "0.0.0",
2247
2245
  pluginFamily: "flow",
2246
+ ...(check.threadModel === FLOW_THREAD_MODEL.WASI_SEQUENTIAL
2247
+ ? { sequentialJustification: {
2248
+ kind: "caller-level-parallelism",
2249
+ detail: "Every linked guest is wasi-sequential; the flow dispatches them serially and delegates external concurrency to its host.",
2250
+ } }
2251
+ : {}),
2248
2252
  description:
2249
2253
  flow.description ??
2250
2254
  `Compiled SDN flow "${flow.programId}" (linked-direct monolithic artifact).`,
@@ -2941,6 +2945,7 @@ async function linkFlowArtifactWithWasiThreads({
2941
2945
  programSource,
2942
2946
  dependencyObjects,
2943
2947
  engineLinked = false,
2948
+ sequential = false,
2944
2949
  }) {
2945
2950
  const toolchain = resolveWasiThreadsToolchain();
2946
2951
  const workDir = await mkdtemp(
@@ -2975,9 +2980,8 @@ async function linkFlowArtifactWithWasiThreads({
2975
2980
  "-std=c++17",
2976
2981
  `-I${workDir}`,
2977
2982
  "-O3",
2978
- "-matomics",
2983
+ ...(sequential ? [] : ["-matomics", "-pthread"]),
2979
2984
  "-mbulk-memory",
2980
- "-pthread",
2981
2985
  "-fno-exceptions",
2982
2986
  "-DNDEBUG",
2983
2987
  ];
@@ -3010,16 +3014,20 @@ async function linkFlowArtifactWithWasiThreads({
3010
3014
  ...dependencyObjectPaths,
3011
3015
  "-O3",
3012
3016
  "-mexec-model=reactor",
3013
- ...PTHREAD_FINAL_LINK_FLAGS,
3017
+ ...(sequential
3018
+ ? ["-mbulk-memory", "-Wl,--initial-memory=16777216", "-Wl,--max-memory=2147483648"]
3019
+ : PTHREAD_FINAL_LINK_FLAGS),
3014
3020
  "-Wl,--export-memory",
3015
3021
  "-Wl,--allow-undefined",
3016
3022
  ...exportSymbols.map((symbol) => `-Wl,--export=${symbol}`),
3017
3023
  "-o",
3018
3024
  outputPath,
3019
3025
  ];
3020
- assertPthreadFlagsPresent(linkArgs, {
3021
- threadModel: HISTORICAL_PTHREAD_THREAD_MODEL,
3022
- });
3026
+ if (sequential) {
3027
+ assertSequentialFlagsAbsent(linkArgs, { threadModel: WASI_SEQUENTIAL_THREAD_MODEL });
3028
+ } else {
3029
+ assertPthreadFlagsPresent(linkArgs, { threadModel: HISTORICAL_PTHREAD_THREAD_MODEL });
3030
+ }
3023
3031
  await runWasiThreadsCompiler(toolchain.clangxx, linkArgs, workDir);
3024
3032
  return new Uint8Array(await readFile(outputPath));
3025
3033
  } finally {
@@ -3118,7 +3126,7 @@ export async function compileFlowProgram({
3118
3126
  });
3119
3127
 
3120
3128
  const linkFlowArtifact =
3121
- check.threadModel === FLOW_THREAD_MODEL.WASI_THREADS
3129
+ check.threadModel !== FLOW_THREAD_MODEL.SINGLE_THREAD
3122
3130
  ? linkFlowArtifactWithWasiThreads
3123
3131
  : linkFlowArtifactWithEmception;
3124
3132
  let wasmBytes = await linkFlowArtifact({
@@ -3129,6 +3137,7 @@ export async function compileFlowProgram({
3129
3137
  programSource,
3130
3138
  dependencyObjects: linkedDependencies.map((dependency) => dependency.guestLink.objectBytes),
3131
3139
  engineLinked: Boolean(check.engineLinkage),
3140
+ sequential: check.threadModel === FLOW_THREAD_MODEL.WASI_SEQUENTIAL,
3132
3141
  });
3133
3142
  wasmBytes = appendWasmCustomSection(
3134
3143
  wasmBytes,
@@ -3137,6 +3146,8 @@ export async function compileFlowProgram({
3137
3146
  );
3138
3147
  if (check.threadModel === FLOW_THREAD_MODEL.WASI_THREADS) {
3139
3148
  assertPthreadArtifact(wasmBytes, { source: sourceName });
3149
+ } else if (check.threadModel === FLOW_THREAD_MODEL.WASI_SEQUENTIAL) {
3150
+ assertSequentialArtifact(wasmBytes, { source: sourceName });
3140
3151
  }
3141
3152
 
3142
3153
  const report = await validateArtifactWithStandards({
@@ -3193,8 +3204,8 @@ export async function compileFlowProgram({
3193
3204
  name: flow.name ?? null,
3194
3205
  version: flow.version ?? null,
3195
3206
  compiler:
3196
- check.threadModel === FLOW_THREAD_MODEL.WASI_THREADS
3197
- ? "space-data-module flow compile (isomorphic, wasi-threads)"
3207
+ check.threadModel !== FLOW_THREAD_MODEL.SINGLE_THREAD
3208
+ ? `space-data-module flow compile (isomorphic, ${check.threadModel})`
3198
3209
  : "space-data-module flow compile (isomorphic, emception)",
3199
3210
  threadModel: check.threadModel,
3200
3211
  nodes: (flow.nodes ?? []).length,