diff --git a/packages/cultmesh-ts/src/realtime-quic-native.ts b/packages/cultmesh-ts/src/realtime-quic-native.ts index 0eb1242e..eab33595 100644 --- a/packages/cultmesh-ts/src/realtime-quic-native.ts +++ b/packages/cultmesh-ts/src/realtime-quic-native.ts @@ -217,22 +217,26 @@ function loadBindings(): NativeBindings { const { promisify } = require("node:util") as typeof import("node:util"); const nextEventAsync = promisify(nextEvent.async) as NativeBindings["nextEventAsync"]; + // Every `_Out_` parameter still occupies a call-site slot in this koffi + // version (an arity check rejects a shorter call); its value is written + // back through the named field on the returned object regardless of what + // was passed here, so `null` is a safe placeholder at each such slot. bindingsCache = { - runtimeOpen: (appName) => runtimeOpen(appName), + runtimeOpen: (appName) => runtimeOpen(appName, null), runtimeClose: (runtime) => runtimeClose(runtime), listenerOpen: (runtime, host, port, pkcs12, pkcs12Length, password) => - listenerOpen(runtime, host, port, pkcs12, pkcs12Length, password), + listenerOpen(runtime, host, port, pkcs12, pkcs12Length, password, null, null), listenerClose: (runtime, listenerId) => listenerClose(runtime, listenerId), - connectionOpen: (runtime, host, port) => connectionOpen(runtime, host, port), + connectionOpen: (runtime, host, port) => connectionOpen(runtime, host, port, null), connectionCertificateComplete: (runtime, connectionId, accept) => connectionCertificateComplete(runtime, connectionId, accept), connectionShutdown: (runtime, connectionId, code) => connectionShutdown(runtime, connectionId, code), - streamOpen: (runtime, connectionId, kind) => streamOpen(runtime, connectionId, kind), + streamOpen: (runtime, connectionId, kind) => streamOpen(runtime, connectionId, kind, null), streamSendFrame: (runtime, streamId, encodedFrame, length, fin) => streamSendFrame(runtime, streamId, encodedFrame, length, fin), streamShutdown: (runtime, streamId, code) => streamShutdown(runtime, streamId, code), nextEventAsync: (runtime, timeoutMs, payload, payloadCapacity) => - nextEventAsync(runtime, timeoutMs, payload, payloadCapacity) as Promise>, + nextEventAsync(runtime, timeoutMs, null, payload, payloadCapacity, null) as Promise>, lastError: (runtime, destination, capacity) => lastError(runtime, destination, capacity), lastStatus: (runtime) => lastStatus(runtime), }; diff --git a/packages/cultmesh-ts/test/realtime-quic-consumer.test.ts b/packages/cultmesh-ts/test/realtime-quic-consumer.test.ts index 8e4128fb..9b3104a9 100644 --- a/packages/cultmesh-ts/test/realtime-quic-consumer.test.ts +++ b/packages/cultmesh-ts/test/realtime-quic-consumer.test.ts @@ -245,13 +245,16 @@ function base64UrlToBase64(value: string): string { return base64; } +let odinRootSequence = 0; + function generateOdinRoot(): { privateKey: KeyObject; publicKey: CultMeshP256PublicKey } { const { publicKey, privateKey } = generateKeyPairSync("ec", { namedCurve: "prime256v1" }); const jwk = publicKey.export({ format: "jwk" }) as { x: string; y: string }; + odinRootSequence += 1; return { privateKey, publicKey: { - keyId: "odin-root-1", + keyId: `odin-root-${odinRootSequence}`, x: base64UrlToBase64(jwk.x), y: base64UrlToBase64(jwk.y), }, diff --git a/packages/cultmesh-ts/test/realtime-quic-native.test.ts b/packages/cultmesh-ts/test/realtime-quic-native.test.ts index 660a83d9..ebde8eea 100644 --- a/packages/cultmesh-ts/test/realtime-quic-native.test.ts +++ b/packages/cultmesh-ts/test/realtime-quic-native.test.ts @@ -137,7 +137,9 @@ test("a full loopback connection delivers one raw frame end to end", async (t) = }); test("negative grep: no koffi callbacks, .async only on nextEvent", () => { - const source = readFileSync(join(__dirname, "..", "src", "realtime-quic-native.ts"), "utf8"); + // __dirname at runtime is dist-test/test; the source lives two levels up, + // in src/, since only .js output is mirrored under dist-test. + const source = readFileSync(join(__dirname, "..", "..", "src", "realtime-quic-native.ts"), "utf8"); const asyncUses = [...source.matchAll(/\.async\(/g)]; assert.ok(asyncUses.length > 0, "expected at least one .async( use for nextEvent"); for (const match of asyncUses) {