Uses HTTPL requests to stream jQuery RPC operations between VM environments. The common use-case is to run the nQuery server on a page, then use the nQuery client in a Worker or RTC peer to remotely manipulate the DOM. Uses region-sandboxing and function whitelisting to control what clients can access.
Depends on jquery and local.js.
Not ready for production. There needs to be some security analysis before this can be used in live software.
From a page constructing the nQuery server:
var nQueryService = new nQuery.Server();
local.spawnWorker('myworker.js', nQueryService);
// ^ incoming requests by myworker.js will be handled by nQueryService
var regionPath = nQueryService.addRegion($('#worker-content'));
console.log(regionPath); // "/regions/1"
nQueryService.removeRegion(regionPath);
regionPath = nQueryService.addRegion($('#worker-content'), { token: 1251098671093850 });
console.log(regionPath); // "/regions/2?token=1251098671093850"
// regions with access tokens will forbid requests without the correct token query param
From myworker.js:
var n$ = nQuery.client('httpl://host.page/regions/1');
// -or-
var n$ = nQuery.client('httpl://host.page/regions/2?token=1251098671093850');
// Traversal and manipulation
n$('div')
.eq(3)
.html('<p class="foo">Hello, world</p>')
.css('background', 'red');
// Reading return values with the optional callback
n$('.foo').css('background', 'green', function(numAffected) {
console.log(numAffected); // 1
});
n$('.foo').css('background', function(bgs) {
console.log(bgs); // ['green']
});
// Events
n$('.foo').on('click', onClick, function(eventStreamURI) {
console.log(eventStreamURI); // "httpl://host.page/regions/2/evt/1?token=...."
n$.off(eventStreamURI); // stop listening
});
function onClick(e) {
console.log(e); /* =>
{
altKey: false
bubbles: true
button: 0
...
type: "click"
which: 1
} */
// note that unpassable references such as `target` are not included
}
Operations are serialized and streamed through the request body, which the server reads and checks against a whitelist before executing. Traversals are checked to make sure they remain within the allowed region. Return values of the operations are serialized into the response body.
The request stream's lifetime is considered a transaction which maintains a traversal position. Ending the request closes the transaction and releases that state.
// This jQuery command
$('li').eq(2).css('background-color', 'red');
// Translates to
POST /regions/1
Content-Type: application/json-stream
["find", "li"]
["eq", 2]
["css", "background-color", "red"]
// Which receives
200 OK
Content-Type: application/json-stream
5
1
1
The response stream includes direct or representative return values. Traversals are an example of representative returns: they get back the numeric length of the set created by the traversal (rather than the set itself, which contains non-transferrable references). The return values are written to the response stream as the operations are run.
Persistant transactions (requests) can be used to make continuous updates.
// Persistant transactions
var num_updates = 0;
var $foo = n$('.foo', { persist: true });
var interval = setInterval(function() {
// Do a "clock" output for five seconds, then close the transaction
$foo.text(''+new Date());
if (++num_updates == 5) {
clearInterval(interval);
$foo.closeTxn();
}
}, 1000);
By default, however, where persist
is false, the transaction is automatically closed on next tick.
Event registration works like other operations, but it generates a new SSE event-stream resource to send the events. The return value, then, is the path of that event stream.
// This request
POST /regions/1
Content-Type: application/json-stream
["find", ".foo a"]
["on", "click"]
// Receives
200 OK
Content-Type: application/json-stream
1
"/regions/1/evt/1"
The n$
client auto-subscribes to the URI with the given cb parameter.
// The example above, rewritten:
n$('.foo a').on('click', function(e) { console.log(e); /* => { ... } */ });
This media type is a set of CLRF-delimited (\r\n
) JSON strings. It's used to serialize the operations and return values.
todo
This list is still being evaluated.
add addClass after append appendTo attr before contents css data detach empty hasClass height hide html index innerHeight innerWidth insertAfter insertBefore offset outerHeight outerWidth position prepend prependTo prop remove removeAttr removeClass removeData removeProp replaceAll replaceWith scrollLeft scrollTop serialize serializeArray show text toggle toggleClass unwrap val width wrap wrapAll wrapInner
addBack andSelf children clone closest die end eq filter find first has hover is last next nextAll nextUntil not offsetParent parent parents parentsUntil prev prevAll prevUntil slice siblings
delegate off on one trigger triggerHandler unbind undelegate
ajax* animate clearQueue delay dequeue each fadeIn fadeOut fadeTo fadeToggle finish get live load map promise pushStack queue ready slideDown slideToggle slideUp stop toArray unload
blur change click dblclick error focus focusin focusout keydown keypress keyup mousedown mouseenter mouseleave mousemove mouseout mouseover mouseup resize scroll select submit