diff --git a/README.md b/README.md
index add083e34..a7ac5f960 100755
--- a/README.md
+++ b/README.md
@@ -235,6 +235,7 @@ List of Definitions
* [Viewporter](https://github.com/zynga/viewporter) (by [Boris Yankov](https://github.com/borisyankov))
* [Vimeo](http://developer.vimeo.com/player/js-api) (by [Daz Wilkin](https://github.com/DazWilkin/))
* [WebRTC](http://dev.w3.org/2011/webrtc/editor/webrtc.html) (by [Ken Smith](https://github.com/smithkl42))
+* [websocket](https://github.com/Worlize/WebSocket-Node) (by [Paul Loyd](https://github.com/loyd))
* [WinJS](http://msdn.microsoft.com/en-us/library/windows/apps/br229773.aspx) (from TypeScript samples)
* [WinRT](http://msdn.microsoft.com/en-us/library/windows/apps/br211377.aspx) (from TypeScript samples)
* [YouTube](https://developers.google.com/youtube/) (by [Daz Wilkin](https://github.com/DazWilkin/))
diff --git a/websocket/websocket-tests.ts b/websocket/websocket-tests.ts
new file mode 100644
index 000000000..7de0fa5b0
--- /dev/null
+++ b/websocket/websocket-tests.ts
@@ -0,0 +1,86 @@
+///
+
+import websocket = require('websocket');
+import http = require('http');
+
+{
+ var server = http.createServer((req, res) => {
+ console.log((new Date()) + ' Received request for ' + req.url);
+ res.writeHead(404);
+ res.end();
+ });
+
+ server.listen(8080, () => {
+ console.log((new Date()) + ' Server is listening on port 8080');
+ });
+
+ var wsServer = new websocket.server({
+ httpServer: server,
+ autoAcceptConnections: false
+ });
+
+ function originIsAllowed(origin: string) { return true; }
+
+ wsServer.on('request', (request: websocket.request) => {
+ if(!originIsAllowed(request.origin)) {
+ request.reject();
+ console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');
+ return;
+ }
+
+ var connection = request.accept('echo-protocol', request.origin);
+ console.log((new Date()) + ' Connection accepted.');
+ connection.on('message', (message: websocket.IMessage) => {
+ if (message.type === 'utf8') {
+ console.log('Received Message: ' + message.utf8Data);
+ connection.sendUTF(message.utf8Data);
+ }
+ else if (message.type === 'binary') {
+ console.log('Received Binary Message of ' + message.binaryData.length + ' bytes');
+ connection.sendBytes(message.binaryData);
+ }
+ });
+
+ connection.on('close', (code: number) => {
+ console.log(Date.now() + ' Peer ' + connection.remoteAddress + ' disconnected.');
+ });
+ });
+}
+
+{
+ var WebSocketClient = require('websocket').client;
+ var client = new WebSocketClient();
+
+ client.on('connectFailed', (error: Error) => {
+ console.log('Connect Error: ' + error.toString());
+ });
+
+ client.on('connect', (connection: websocket.connection) => {
+ console.log('WebSocket client connected');
+ connection.on('error', (error: Error) => {
+ console.log("Connection Error: " + error.toString());
+ });
+
+ connection.on('close', () => {
+ console.log('echo-protocol Connection Closed');
+ });
+
+ connection.on('message', (message: websocket.IMessage) => {
+ if (message.type === 'utf8') {
+ console.log("Received: '" + message.utf8Data + "'");
+ }
+ });
+
+ function sendNumber() {
+ if (connection.connected) {
+ var number = Math.round(Math.random() * 0xFFFFFF);
+ connection.sendUTF(number.toString());
+ setTimeout(sendNumber, 1000);
+ }
+ }
+
+ sendNumber();
+ });
+
+ client.connect('ws://localhost:8080/', 'echo-protocol');
+}
diff --git a/websocket/websocket.d.ts b/websocket/websocket.d.ts
new file mode 100644
index 000000000..7dbd9a67c
--- /dev/null
+++ b/websocket/websocket.d.ts
@@ -0,0 +1,466 @@
+// Type definitions for websocket
+// Project: https://github.com/Worlize/WebSocket-Node
+// Definitions by: Paul Loyd
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+///
+
+declare module "websocket" {
+ import events = require('events');
+ import http = require('http');
+ import net = require('net');
+ import url = require('url');
+
+ export interface IServerConfig {
+ /** The http server instance to attach to */
+ httpServer: http.Server;
+
+ /**
+ * The maximum allowed received frame size in bytes.
+ * Single frame messages will also be limited to this maximum.
+ * @default 64KiB
+ */
+ maxReceivedFrameSize?: number;
+
+ /**
+ * The maximum allowed aggregate message size (for fragmented messages) in bytes.
+ * @default 1MiB
+ */
+ maxReceivedMessageSize?: number;
+
+ /**
+ * Whether or not to fragment outgoing messages. If true, messages will be
+ * automatically fragmented into chunks of up to `fragmentationThreshold` bytes.
+ * @default true
+ */
+ fragmentOutgoingMessages?: boolean;
+
+ /**
+ * The maximum size of a frame in bytes before it is automatically fragmented.
+ * @default 16KiB
+ */
+ fragmentationThreshold?: number;
+
+ /**
+ * If true, the server will automatically send a ping to all clients every
+ * `keepaliveInterval` milliseconds. Each client has an independent `keepalive`
+ * timer, which is reset when any data is received from that client.
+ * @default true
+ */
+ keepalive?: boolean;
+
+ /**
+ * The interval in milliseconds to send `keepalive` pings to connected clients.
+ * @default 20000
+ */
+ keepaliveInterval?: number;
+
+ /**
+ * If true, the server will consider any connection that has not received any
+ * data within the amount of time specified by `keepaliveGracePeriod` after a
+ * `keepalive` ping has been sent. Ignored if `keepalive` is false.
+ * @default true
+ */
+ dropConnectionOnKeepaliveTimeout?: boolean;
+
+ /**
+ * The amount of time to wait after sending a `keepalive` ping before closing
+ * the connection if the connected peer does not respond. Ignored if `keepalive`
+ * or `dropConnectionOnKeepaliveTimeout` are false. The grace period timer is
+ * reset when any data is received from the client.
+ * @default 10000
+ */
+ keepaliveGracePeriod?: number;
+
+ /**
+ * If true, fragmented messages will be automatically assembled and the full
+ * message will be emitted via a `message` event. If false, each frame will be
+ * emitted on the `connection` object via a `frame` event and the application
+ * will be responsible for aggregating multiple fragmented frames. Single-frame
+ * messages will emit a `message` event in addition to the `frame` event.
+ * @default true
+ */
+ assembleFragments?: boolean;
+
+ /**
+ * If this is true, websocket connections will be accepted regardless of the path
+ * and protocol specified by the client. The protocol accepted will be the first
+ * that was requested by the client.
+ * @default false
+ */
+ autoAcceptConnections?: boolean;
+
+ /**
+ * The number of milliseconds to wait after sending a close frame for an
+ * `acknowledgement` to come back before giving up and just closing the socket.
+ * @default 5000
+ */
+ closeTimeout?: number;
+
+ /**
+ * The Nagle Algorithm makes more efficient use of network resources by introducing a
+ * small delay before sending small packets so that multiple messages can be batched
+ * together before going onto the wire. This however comes at the cost of latency.
+ * @default true
+ */
+ disableNagleAlgorithm?: boolean;
+ }
+
+ export class server extends events.EventEmitter {
+ constructor(serverConfig?: IServerConfig);
+
+ /** Attach the `server` instance to a Node http.Server instance */
+ mount(serverConfig: IServerConfig): void;
+
+ /**
+ * Detach the `server` instance from the Node http.Server instance.
+ * All existing connections are left alone and will not be affected,
+ * but no new WebSocket connections will be accepted.
+ */
+ unmount(): void;
+
+ /** Close all open WebSocket connections */
+ closeAllConnections(): void;
+ /** Close all open WebSocket connections and unmount the server */
+ shutDown(): void;
+
+ // Events
+ on(event: string, listener: () => void): server;
+ on(event: 'request', cb: (request: request) => void): server;
+ on(event: 'connect', cb: (connection: connection) => void): server;
+ on(event: 'close', cb: (connection: connection, reason: number, desc: string) => void): server;
+ addListener(event: string, listener: () => void): server;
+ addListener(event: 'request', cb: (request: request) => void): server;
+ addListener(event: 'connect', cb: (connection: connection) => void): server;
+ addListener(event: 'close', cb: (connection: connection, reason: number, desc: string) => void): server;
+ }
+
+ export class request extends events.EventEmitter {
+ /** A reference to the original Node HTTP request object */
+ httpRequest: http.ClientRequest;
+ /** This will include the port number if a non-standard port is used */
+ host: string;
+ /** A string containing the path that was requested by the client */
+ resource: string;
+ /** Parsed resource, including the query string parameters */
+ resourceURL: url.Url;
+
+ /**
+ * Client's IP. If an `X-Forwarded-For` header is present, the value will be taken
+ * from that header to facilitate WebSocket servers that live behind a reverse-proxy
+ */
+ remoteAddress: string;
+
+ /**
+ * If the client is a web browser, origin will be a string containing the URL
+ * of the page containing the script that opened the connection.
+ * If the client is not a web browser, origin may be `null` or "*".
+ */
+ origin: string;
+
+ /** The version of the WebSocket protocol requested by the client */
+ webSocketVersion: number;
+ /** An array containing a list of extensions requested by the client */
+ requestedExtensions: any[];
+
+ /**
+ * List of strings that indicate the subprotocols the client would like to speak.
+ * The server should select the best one that it can support from the list and
+ * pass it to the `accept` function when accepting the connection.
+ * Note that all the strings in the `requestedProtocols` array will have been
+ * converted to lower case.
+ */
+ requestedProtocols: string[];
+
+ constructor(socket: net.NodeSocket, httpRequest: http.ClientRequest, config: IServerConfig);
+
+ /**
+ * After inspecting the `request` properties, call this function on the
+ * request object to accept the connection. If you don't have a particular subprotocol
+ * you wish to speak, you may pass `null` for the `acceptedProtocol` parameter.
+ *
+ * @param [acceptedProtocol] case-insensitive value that was requested by the client
+ */
+ accept(acceptedProtocol?: string, allowedOrigin?: string, cookies?: any[]): connection;
+
+ /**
+ * Reject connection.
+ * You may optionally pass in an HTTP Status code (such as 404) and a textual
+ * description that will be sent to the client in the form of an
+ * `X-WebSocket-Reject-Reason` header.
+ */
+ reject(httpStatus?: number, reason?: string): void;
+
+ // Events
+ on(event: string, listener: () => void): request;
+ on(event: 'requestAccepted', cb: (connection: connection) => void): request;
+ on(event: 'requestRejected', cb: () => void): request;
+ addListener(event: string, listener: () => void): request;
+ addListener(event: 'requestAccepted', cb: (connection: connection) => void): request;
+ addListener(event: 'requestRejected', cb: () => void): request;
+ }
+
+ export interface IMessage {
+ type: string;
+ utf8Data?: string;
+ binaryData?: NodeBuffer;
+ }
+
+ class connection extends events.EventEmitter {
+ static CLOSE_REASON_NORMAL: number;
+ static CLOSE_REASON_GOING_AWAY: number;
+ static CLOSE_REASON_PROTOCOL_ERROR: number;
+ static CLOSE_REASON_UNPROCESSABLE_INPUT: number;
+ static CLOSE_REASON_RESERVED: number;
+ static CLOSE_REASON_NOT_PROVIDED: number;
+ static CLOSE_REASON_ABNORMAL: number;
+ static CLOSE_REASON_INVALID_DATA: number;
+ static CLOSE_REASON_POLICY_VIOLATION: number;
+ static CLOSE_REASON_MESSAGE_TOO_BIG: number;
+ static CLOSE_REASON_EXTENSION_REQUIRED: number;
+
+ /**
+ * After the connection is closed, contains a textual description of the reason for
+ * the connection closure, or `null` if the connection is still open.
+ */
+ closeDescription: string;
+
+ /**
+ * After the connection is closed, contains the numeric close reason status code,
+ * or `-1` if the connection is still open.
+ */
+ closeReasonCode: number;
+
+ /**
+ * The subprotocol that was chosen to be spoken on this connection. This field
+ * will have been converted to lower case.
+ */
+ protocol: string;
+
+ socket: net.NodeSocket;
+ /** An array of extensions that were negotiated for this connection */
+ extensions: any[];
+
+ /**
+ * The IP address of the remote peer as a string. In the case of a server,
+ * the `X-Forwarded-For` header will be respected and preferred for the purposes
+ * of populating this field. If you need to get to the actual remote IP address,
+ * `socket.remoteAddress` will provide it.
+ */
+ remoteAddress: string;
+
+ /** The version of the WebSocket protocol requested by the client */
+ webSocketVersion: number;
+ /** Whether or not the connection is still connected. Read-only */
+ connected: boolean;
+
+ constructor(socket: net.NodeSocket, extensions: any[], protocol: string,
+ maskOutgoingPackets: boolean, config: IServerConfig);
+
+ /**
+ * Close the connection. A close frame will be sent to the remote peer indicating
+ * that we wish to close the connection, and we will then wait for up to
+ * `config.closeTimeout` milliseconds for an acknowledgment from the remote peer
+ * before terminating the underlying socket connection.
+ */
+ close(): void;
+
+ /**
+ * Send a close frame to the remote peer and immediately close the socket without
+ * waiting for a response. This should generally be used only in error conditions.
+ */
+ drop(reasonCode?: number, description?: string): void;
+
+ /**
+ * Immediately sends the specified string as a UTF-8 WebSocket message to the remote
+ * peer. If `config.fragmentOutgoingMessages` is true the message may be sent as
+ * multiple fragments if it exceeds `config.fragmentationThreshold` bytes.
+ */
+ sendUTF(data: {toString: (...args: any[]) => string}): void;
+
+ /**
+ * Immediately sends the specified Node Buffer object as a Binary WebSocket message
+ * to the remote peer. If config.fragmentOutgoingMessages is true the message may be
+ * sent as multiple fragments if it exceeds config.fragmentationThreshold bytes.
+ */
+ sendBytes(buffer: NodeBuffer): void;
+
+ /** Auto-detect the data type and send UTF-8 or Binary message */
+ send(data: NodeBuffer): void;
+ send(data: {toString: (...args: any[]) => string}): void;
+
+ /** Sends a ping frame. Ping frames must not exceed 125 bytes in length. */
+ ping(data: NodeBuffer): void;
+ ping(data: {toString: (...args: any[]) => string}): void;
+
+ /**
+ * Sends a pong frame. Pong frames may be sent unsolicited and such pong frames will
+ * trigger no action on the receiving peer. Pong frames sent in response to a ping
+ * frame must mirror the payload data of the ping frame exactly.
+ * The `connection` object handles this internally for you, so there should
+ * be no need to use this method to respond to pings.
+ * Pong frames must not exceed 125 bytes in length.
+ */
+ pong(buffer: NodeBuffer): void;
+
+ /**
+ * Serializes a `frame` object into binary data and immediately sends it to
+ * the remote peer. This is an advanced function, requiring you to manually compose
+ * your own `frame`. You should probably use sendUTF or sendBytes instead.
+ */
+ sendFrame(frame: frame): void;
+
+ // Events
+ on(event: string, listener: () => void): connection;
+ on(event: 'message', cb: (data: IMessage) => void): connection;
+ on(event: 'frame', cb: (frame: frame) => void): connection;
+ on(event: 'close', cb: (code: number, desc: string) => void): connection;
+ on(event: 'error', cb: (err: Error) => void): connection;
+ addListener(event: string, listener: () => void): connection;
+ addListener(event: 'message', cb: (data: IMessage) => void): connection;
+ addListener(event: 'frame', cb: (frame: frame) => void): connection;
+ addListener(event: 'close', cb: (code: number, desc: string) => void): connection;
+ addListener(event: 'error', cb: (err: Error) => void): connection;
+ }
+
+ class frame {
+ /** Whether or not this is last frame in a fragmentation sequence */
+ fin: boolean;
+
+ /**
+ * Represents the RSV1 field in the framing. Setting this to true will result in
+ * a Protocol Error on the receiving peer.
+ */
+ rsv1: boolean;
+
+ /**
+ * Represents the RSV1 field in the framing. Setting this to true will result in
+ * a Protocol Error on the receiving peer.
+ */
+ rsv2: boolean;
+
+ /**
+ * Represents the RSV1 field in the framing. Setting this to true will result in
+ * a Protocol Error on the receiving peer.
+ */
+ rsv3: boolean;
+
+ /**
+ * Whether or not this frame is (or should be) masked. For outgoing frames, when
+ * connected as a client, this flag is automatically forced to true by `connection`.
+ * Outgoing frames sent from the server-side of a connection are not masked.
+ */
+ mask: number;
+
+ /**
+ * Identifies which kind of frame this is.
+ *
+ * Hex - Dec - Description
+ * 0x00 - 0 - Continuation
+ * 0x01 - 1 - Text Frame
+ * 0x02 - 2 - Binary Frame
+ * 0x08 - 8 - Close Frame
+ * 0x09 - 9 - Ping Frame
+ * 0x0A - 10 - Pong Frame
+ */
+ opcode: number;
+
+ /**
+ * Identifies the length of the payload data on a received frame.
+ * When sending a frame, will be automatically calculated from `binaryPayload` object.
+ */
+ length: number;
+
+ /**
+ * The binary payload data.
+ * Even text frames are sent with a Buffer providing the binary payload data.
+ */
+ binaryPayload: NodeBuffer;
+ }
+
+ export interface IClientConfig {
+ /**
+ * Which version of the WebSocket protocol to use when making the connection.
+ * Currently supported values are 8 and 13. This option will be removed once the
+ * protocol is finalized by the IETF It is only available to ease the transition
+ * through the intermediate draft protocol versions. The only thing this affects
+ * the name of the Origin header.
+ * @default 13
+ */
+ webSocketVersion: number;
+
+ /**
+ * The maximum allowed received frame size in bytes.
+ * Single frame messages will also be limited to this maximum.
+ * @default 1MiB
+ */
+ maxReceivedFrameSize: number;
+
+ /**
+ * The maximum allowed aggregate message size (for fragmented messages) in bytes.
+ * @default 8MiB
+ */
+ maxReceivedMessageSize: number;
+
+ /**
+ * Whether or not to fragment outgoing messages. If true, messages will be
+ * automatically fragmented into chunks of up to `fragmentationThreshold` bytes.
+ * @default true
+ */
+ fragmentOutgoingMessages: boolean;
+
+ /**
+ * The maximum size of a frame in bytes before it is automatically fragmented.
+ * @default 16KiB
+ */
+ fragmentationThreshold: number;
+
+ /**
+ * If true, fragmented messages will be automatically assembled and the full message
+ * will be emitted via a `message` event. If false, each frame will be emitted on
+ * the `connection` object via a `frame` event and the application will be responsible
+ * for aggregating multiple fragmented frames. Single-frame messages will emit
+ * a `message` event in addition to the `frame` event. Most users will want to
+ * leave this set to true.
+ * @default true
+ */
+ assembleFragments: boolean;
+
+ /**
+ * The number of milliseconds to wait after sending a close frame for
+ * an acknowledgement to come back before giving up and just closing the socket.
+ * @default 5000
+ */
+ closeTimeout: number;
+ }
+
+ class client extends events.EventEmitter {
+ constructor(clientConfig?: IClientConfig);
+
+ /**
+ * Establish a connection. The remote server will select the best subprotocol that
+ * it supports and send that back when establishing the connection.
+ *
+ * @param [origin] can be used in user-agent scenarios to identify the page containing
+ * any scripting content that caused the connection to be requested.
+ * @param requestUrl should be a standard websocket url
+ */
+ connect(requestUrl: url.Url, protocols?: string[], origin?: string, headers?: any[]): void;
+ connect(requestUrl: string, protocols?: string[], origin?: string, headers?: any[]): void;
+ connect(requestUrl: url.Url, protocols?: string, origin?: string, headers?: any[]): void;
+ connect(requestUrl: string, protocols?: string, origin?: string, headers?: any[]): void;
+
+ // Events
+ on(event: string, listener: () => void): client;
+ on(event: 'connect', cb: (connection: connection) => void): client;
+ on(event: 'connectFailed', cb: (err: Error) => void): client;
+ addListener(event: string, listener: () => void): client;
+ addListener(event: 'connect', cb: (connection: connection) => void): client;
+ addListener(event: 'connectFailed', cb: (err: Error) => void): client;
+ }
+
+ export var version: string;
+ export var constants: {
+ DEBUG: boolean;
+ };
+}