diff --git a/phoenix/phoenix-tests.ts b/phoenix/phoenix-tests.ts
new file mode 100644
index 0000000000..6724fc6434
--- /dev/null
+++ b/phoenix/phoenix-tests.ts
@@ -0,0 +1,72 @@
+///
+
+import { Socket, Channel, Presence } from 'phoenix';
+
+function test_socket() {
+ const socket = new Socket("/ws", {params: {userToken: "123"}});
+ socket.connect();
+}
+
+function test_channel() {
+ const socket = new Socket("/ws", {params: {userToken: "123"}});
+ socket.connect();
+
+ const channel = socket.channel("room:123", {token: '123'});
+
+ channel.on("new_msg", msg => console.log("Got message", msg));
+
+ channel.push("new_msg", {body: 'some value'}, 10000)
+ .receive("ok", (msg) => console.log("created message", msg))
+ .receive("error", (reasons) => console.log("create failed", reasons))
+ .receive("timeout", () => console.log("Networking issue..."));
+
+ channel.join()
+ .receive("ok", ({messages}) => console.log("catching up", messages))
+ .receive("error", ({reason}) => console.log("failed join", reason))
+ .receive("timeout", () => console.log("Networking issue. Still waiting..."));
+}
+
+function test_hooks() {
+ const socket = new Socket("/ws", {params: {userToken: "123"}});
+ socket.connect();
+
+ socket.onError(() => console.log("there was an error with the connection!"));
+ socket.onClose(() => console.log("the connection dropped"));
+
+ const channel = socket.channel("room:123", {token: '123'});
+
+ channel.onError(() => console.log("there was an error!"));
+ channel.onClose(() => console.log("the channel has gone away gracefully"))
+}
+
+function test_presence() {
+ let state = {};
+ const stateFromServer = {};
+
+ const onJoin = (id: string, current: any, newPres: any) => {
+ if(!current){
+ console.log("user has entered for the first time", newPres)
+ } else {
+ console.log("user additional presence", newPres)
+ }
+ };
+
+ const onLeave = (id: string, current: any, leftPres: any) => {
+ if(current.metas.length === 0){
+ console.log("user has left from all devices", leftPres)
+ } else {
+ console.log("user left from a device", leftPres)
+ }
+ };
+
+ state = Presence.syncState(state, stateFromServer, onJoin, onLeave);
+
+ const listBy = (id: string, {metas: [first, ...rest]} : {metas: any[]}) => {
+ first.count = rest.length + 1;
+ first.id = id;
+
+ return first;
+ };
+
+ const onlineUsers = Presence.list(state, listBy);
+}
diff --git a/phoenix/phoenix.d.ts b/phoenix/phoenix.d.ts
new file mode 100644
index 0000000000..5f8956bee5
--- /dev/null
+++ b/phoenix/phoenix.d.ts
@@ -0,0 +1,143 @@
+// Type definitions for phoenix
+// Project: https://github.com/phoenixframework/phoenix
+// Definitions by: Mirosław Ciastek
+// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
+
+declare module "phoenix" {
+ class Push {
+ constructor(channel: Channel, event: string, payload: any, timeout: number);
+
+ resend(timeout: number): void;
+ send(): void;
+
+ receive(status: string, callback: (response?: any) => void): Push;
+ }
+
+ export class Channel {
+ constructor(topic: string, params?: Object, socket?: Socket);
+
+ rejoinUntilConnected(): void;
+
+ join(timeout?: number): Push;
+ leave(timeout?: number): Push;
+
+ onClose(callback: Function): void;
+ onError(callback: (reason?: any) => void): void;
+ onMessage(event: string, payload: any, ref: any): any;
+
+ on(event: string, callback: (response?: any) => void): void;
+ off(event: string): void;
+
+ canPush(): boolean;
+
+ push(event: string, payload: Object, timeout?: number): Push;
+ }
+
+ export class Socket {
+ constructor(endPoint: string, opts?: Object);
+
+ protocol(): string;
+ endPointURL(): string;
+
+ disconnect(callback?: Function, code?: string, reason?: any): void;
+ connect(params?: any): void;
+
+ log(kind: string, msg: string, data: any): void;
+
+ onOpen(callback: Function): void;
+ onClose(callback: Function): void;
+ onError(callback: Function): void;
+ onMessage(callback: Function): void;
+
+ onConnOpen(): void;
+ onConnClose(event: any): void;
+ onConnError(error: any): void;
+
+ triggerChanError(): void;
+
+ connectionState(): string;
+
+ isConnected(): boolean;
+
+ remove(channel: Channel): void;
+ channel(topic: string, chanParams?: Object): Channel;
+
+ push(data: any): void;
+
+ makeRef(): string;
+ sendHeartbeat(): void;
+ flushSendBuffer(): void;
+
+ onConnMessage(rawMessage: any): void;
+ }
+
+ export class LongPoll {
+ constructor(endPoint: string);
+
+ normalizeEndpoint(endPoint: string): string;
+ endpointURL(): string;
+
+ closeAndRetry(): void;
+ ontimeout(): void;
+
+ poll(): void;
+
+ send(body: any): void;
+ close(code?: any, reason?: any): void;
+ }
+
+ export class Ajax {
+ request(
+ method: string,
+ endPoint: string,
+ accept: string,
+ body: any,
+ timeout?: number,
+ ontimeout?: any,
+ callback?: (response?: any) => void
+ ): void;
+
+ xdomainRequest(
+ req: any,
+ method: string,
+ endPoint: string,
+ body: any,
+ timeout?: number,
+ ontimeout?: any,
+ callback?: (response?: any) => void
+ ): void;
+
+ xhrRequest(
+ req: any,
+ method: string,
+ endPoint: string,
+ accept: string,
+ body: any,
+ timeout?: number,
+ ontimeout?: any,
+ callback?: (response?: any) => void
+ ): void;
+
+ parseJSON(resp: string): JSON;
+ serialize(obj: any, parentKey: string): string;
+ appendParams(url: string, params: any): string;
+ }
+
+ export var Presence: {
+ syncState(
+ currentState: any,
+ newState: any,
+ onJoin?: (key?: string, currentPresence?: any, newPresence?: any) => void,
+ onLeave?: (key?: string, currentPresence?: any, newPresence?: any) => void
+ ): any;
+
+ syncDiff(
+ currentState: any,
+ newState: any,
+ onJoin?: (key?: string, currentPresence?: any, newPresence?: any) => void,
+ onLeave?: (key?: string, currentPresence?: any, newPresence?: any) => void
+ ): any;
+
+ list(presences: any, chooser?: Function): any;
+ }
+}