diff --git a/lib/hyperscript/runtime.sx b/lib/hyperscript/runtime.sx index 956d158c..23cc5210 100644 --- a/lib/hyperscript/runtime.sx +++ b/lib/hyperscript/runtime.sx @@ -2532,36 +2532,27 @@ hs-socket-register! (fn (name-path url timeout-ms handler json?) - ;; 1. Normalise URL — absolute ws/wss pass through; relative paths get scheme+host (let - ((ws-url - (cond - ((or (starts-with? url "ws://") (starts-with? url "wss://")) url) - (true - (let - ((proto (host-get (host-global "location") "protocol")) - (h (host-get (host-global "location") "host"))) - (str (if (= proto "https:") "wss:" "ws:") "//" h url)))))) - ;; 2. Construct WebSocket + ((ws-url (cond ((or (starts-with? url "ws://") (starts-with? url "wss://")) url) (true (let ((proto (host-get (host-global "location") "protocol")) (h (host-get (host-global "location") "host"))) (str (if (= proto "https:") "wss:" "ws:") "//" h url)))))) (let ((ws (host-new "WebSocket" ws-url))) - ;; 3. Build wrapper dict (let - ((wrapper - {:raw ws - :url ws-url - :timeout timeout-ms - :pending {} - :handler handler - :json? json? - :closed? false})) - ;; 4. Wire RPC proxy via JS factory (if available) + ((wrapper (host-new "Object"))) + (host-set! wrapper "raw" ws) + (host-set! wrapper "url" ws-url) + (host-set! wrapper "timeout" timeout-ms) + (host-set! wrapper "pending" (host-new "Object")) + (host-set! wrapper "handler" handler) + (host-set! wrapper "json?" json?) + (host-set! wrapper "closed?" false) (let ((proxy-factory (host-global "_hs_make_rpc_proxy"))) - (when proxy-factory - (host-set! wrapper "rpc" + (when + proxy-factory + (host-set! + wrapper + "rpc" (host-call proxy-factory "call" nil wrapper)))) - ;; 5. Bind wrapper on window, walking name-path (define bind-path! (fn @@ -2570,10 +2561,9 @@ (= (len path) 1) (host-set! obj (first path) wrapper) (let - ((key (first path)) - (rest-path (rest path))) + ((key (first path)) (rest-path (rest path))) (let - ((next (or (host-get obj key) {}))) + ((next (or (host-get obj key) (host-new "Object")))) (host-set! obj key next) (bind-path! next rest-path)))))) (bind-path! (host-global "window") name-path) diff --git a/shared/static/wasm/sx/hs-runtime.sx b/shared/static/wasm/sx/hs-runtime.sx index 956d158c..23cc5210 100644 --- a/shared/static/wasm/sx/hs-runtime.sx +++ b/shared/static/wasm/sx/hs-runtime.sx @@ -2532,36 +2532,27 @@ hs-socket-register! (fn (name-path url timeout-ms handler json?) - ;; 1. Normalise URL — absolute ws/wss pass through; relative paths get scheme+host (let - ((ws-url - (cond - ((or (starts-with? url "ws://") (starts-with? url "wss://")) url) - (true - (let - ((proto (host-get (host-global "location") "protocol")) - (h (host-get (host-global "location") "host"))) - (str (if (= proto "https:") "wss:" "ws:") "//" h url)))))) - ;; 2. Construct WebSocket + ((ws-url (cond ((or (starts-with? url "ws://") (starts-with? url "wss://")) url) (true (let ((proto (host-get (host-global "location") "protocol")) (h (host-get (host-global "location") "host"))) (str (if (= proto "https:") "wss:" "ws:") "//" h url)))))) (let ((ws (host-new "WebSocket" ws-url))) - ;; 3. Build wrapper dict (let - ((wrapper - {:raw ws - :url ws-url - :timeout timeout-ms - :pending {} - :handler handler - :json? json? - :closed? false})) - ;; 4. Wire RPC proxy via JS factory (if available) + ((wrapper (host-new "Object"))) + (host-set! wrapper "raw" ws) + (host-set! wrapper "url" ws-url) + (host-set! wrapper "timeout" timeout-ms) + (host-set! wrapper "pending" (host-new "Object")) + (host-set! wrapper "handler" handler) + (host-set! wrapper "json?" json?) + (host-set! wrapper "closed?" false) (let ((proxy-factory (host-global "_hs_make_rpc_proxy"))) - (when proxy-factory - (host-set! wrapper "rpc" + (when + proxy-factory + (host-set! + wrapper + "rpc" (host-call proxy-factory "call" nil wrapper)))) - ;; 5. Bind wrapper on window, walking name-path (define bind-path! (fn @@ -2570,10 +2561,9 @@ (= (len path) 1) (host-set! obj (first path) wrapper) (let - ((key (first path)) - (rest-path (rest path))) + ((key (first path)) (rest-path (rest path))) (let - ((next (or (host-get obj key) {}))) + ((next (or (host-get obj key) (host-new "Object")))) (host-set! obj key next) (bind-path! next rest-path)))))) (bind-path! (host-global "window") name-path) diff --git a/spec/tests/test-hyperscript-behavioral.sx b/spec/tests/test-hyperscript-behavioral.sx index 57b4b65d..f75f41b3 100644 --- a/spec/tests/test-hyperscript-behavioral.sx +++ b/spec/tests/test-hyperscript-behavioral.sx @@ -11524,7 +11524,11 @@ (deftest "dispatchEvent sends JSON-encoded event over the socket" (error "SKIP (untranslated): dispatchEvent sends JSON-encoded event over the socket")) (deftest "namespaced sockets work" - (error "SKIP (untranslated): namespaced sockets work")) + (hs-cleanup!) + (eval-hs "socket MyApp.chat ws://localhost/ws end") + (let ((my-app (host-get (host-global "window") "MyApp"))) + (let ((chat (host-get my-app "chat"))) + (assert (not (nil? (host-get chat "raw"))))))) (deftest "on message as JSON handler decodes JSON payload" (error "SKIP (untranslated): on message as JSON handler decodes JSON payload")) (deftest "on message as JSON throws on non-JSON payload" @@ -11552,7 +11556,12 @@ (deftest "rpc reconnects after the underlying socket closes" (error "SKIP (untranslated): rpc reconnects after the underlying socket closes")) (deftest "with timeout parses and uses the configured timeout" - (error "SKIP (untranslated): with timeout parses and uses the configured timeout")) + (hs-cleanup!) + (eval-hs "socket TimedSocket ws://localhost/ws with timeout 1500 end") + (let ((sock (host-get (host-global "window") "TimedSocket"))) + (do + (assert (not (nil? sock))) + (assert (not (nil? (host-get sock "rpc"))))))) ) ;; ── swap (4 tests) ── diff --git a/tests/hs-run-filtered.js b/tests/hs-run-filtered.js index 322dca8d..b97a3adc 100755 --- a/tests/hs-run-filtered.js +++ b/tests/hs-run-filtered.js @@ -590,7 +590,8 @@ function _hs_make_rpc_proxy(wrapper, overrides) { } }); } -globalThis._hs_make_rpc_proxy = { call: _hs_make_rpc_proxy }; +// host-call passes args as (this_placeholder, ...rest); strip the nil first-arg. +globalThis._hs_make_rpc_proxy = { call: (_, w, overrides) => _hs_make_rpc_proxy(w, overrides) }; const _origLog = console.log; globalThis.console = { log: () => {}, error: () => {}, warn: () => {}, info: () => {}, debug: () => {} }; // suppress ALL console noise const _log = _origLog; // keep reference for our own output @@ -754,7 +755,7 @@ for(let i=startTest;i