JS.Class 3.0, or, how I suck at shipping

Real artists ship.

Steve Jobs, apparently

Yeah, about that.

commit 01c84f61211f0ea81aac48422122d094567eeb1b
Author: James Coglan <jcoglan@googlemail.com>
Date:   Thu Jul 2 17:26:22 2009 +0100

    Begin porting Ruby's Test::Unit to JavaScript.

Twenty-oh-nine? I had a different job back then. Boy, is my face red.

All of which is a clumsy apology to those of you that use JS.Class, that say lovely things about it, and have had to put up with me responding to bug/feature requests with some combination of the words “um”, “yeah” and “maybe” for months. The good news is that there’s a new release out. You can download it and tell me about all the new bugs I’ve introduced.

So what’s in this release that took so long? Well, the major themes are portability and testing, as I hinted at in an essay last month. Version 3.0 is designed to run on a very broad array of JavaScript platforms, specifically:

By ‘run’, I mean that the parts of it that contain platform-specific code should run on all these platforms, no hacking required. The package manager should work, method call tracing should work, and the testing framework should run. To make this possible, JS.Class now its own testing framework, designed specifically to make sure it can run correctly on all these environments.

So what else is new? As well as the portable package manager and testing tools, there’s a bunch of new features:

  • We’ve got a Deferrable mixin that you can use to model futures and promises.
  • Hash and Set now have ordered versions, that iterate over their members in insertion order. This is handy if you’ve been accidentally relying on most JS engines (but not all) having this behaviour for objects.
  • HashSet has become the base Set class, and you can refer to it simply as ‘Set’. This is considerably faster than the original array-based Set class.
  • There’s a new collection type called Range.
  • I’ve added a port of Ruby’s TSort library.
  • There’s a Console module, which provides a cross-platform abstraction for writing to the console, whatever ‘console’ may mean in the current environment.
  • StackTrace has been totally overhauled to support user-defined method tracing functionality. Out of the box, it comes with logger for printing call graphs to the console, and a test coverage tool.
  • The Benchmark library can be used to measure performance of sections of code.
  • Module#alias is a quicker way to create method aliases.
  • Users can define their own ‘keyword’ methods (methods like callSuper) that behave based on their implicit method call environment.
  • And a few minor fixes and tweaks detailed in the changelog when you download the library.

That’s basically it, or at least of you want to know anything else it’s in the documentation. I’m particularly happy to have the testing framework out, since it’s going to make the next round of Faye development much more pleasant and reliable. A lot of the tools in there come from my experience testing Faye and a few other projects, including JS.Class itself, so it’s really been exercised a lot over the last year or so.

Oh and finally, this release would not have happened without John Resig’s (he of jQuery fame) TestSwarm, which lets you run your tests remotely on a range of different browsers, including a ton of systems I don’t have copies of. Thanks to everyone who donated their machine or phone to get this release out. Needless to say, JS.Test supports TestSwarm out of the box so it’s easy to use it for your CI needs.

Right, I’m off to have a drink and watch The Social Network.

Turning Faye into a push-only server

This came up on the mailing list recently, and I had the same problem writing Primer‘s real-time component. I want to turn my Faye server into a push-only server, meaning that only the server is allowed to publish messages and all other clients can only listen. This of course means we need some authentication.

The simplest way to do this is to have a password which is known only to your server-side application, and not exposed to the outside world. Your Faye server should then validate that any published messages contain the password before it allows them to be published. Let’s implement this as an extension:

var ServerAuth = {
  incoming: function(message, callback) {
    if (/^\/meta\//.test(message.channel))
      return callback(message);
    
    var password = message.ext && message.ext.password;
    
    if (password !== APP_PASSWORD)
      message.error = Faye.Error.extMismatch();
    
    if (password) delete message.ext.password;
    callback(message);
  }
};

This extension filters incoming messages on the server side. We let meta-messages through so that all clients can still connect and subscribe to channels. If a message is not in the /meta/* namespace, it is a publish message and must be authorized. We add an error if the password is invalid, since adding an error will stop the server from distributing it. Finally we delete the password from the message: if it is left in place, it will be broadcast when the message goes back out to clients, and will be visible to anyone with a working Firebug console.

To satisfy this authorization extension, we need a client extension that adds the password to all outgoing messages:

var ClientAuth = {
  outgoing: function(message, callback) {
    message.ext = message.ext || {};
    message.ext.password = APP_PASSWORD;
    callback(message);
  }
};

Finally we just need to add these extensions to our server-side components and set a password:

APP_PASSWORD = 'something super secret';
server.addExtension(ServerAuth);
server.getClient().addExtension(ClientAuth);

And voila, only your server can publish messages.

This is a very useful pattern when you need to make sure that data being sent to your client-side apps came from your server. For example, in Primer I use Faye to publish updates to the current page’s HTML, and I don’t want anybody to be able to inject arbitrary HTML into my site. If I know the HTML came from my server, I know it’s safe to inject it into the page.