diff --git a/types/expirymanager/expirymanager-tests.ts b/types/expirymanager/expirymanager-tests.ts new file mode 100644 index 0000000000..2206b2673e --- /dev/null +++ b/types/expirymanager/expirymanager-tests.ts @@ -0,0 +1,19 @@ +import { ExpiryManager } from "expirymanager"; + +const expiryManager = new ExpiryManager(); + +const keys = ['1', '2']; + +expiryManager.expire(keys, 1); + +expiryManager.unexpire(keys); + +const expiry: number = expiryManager.getExpiry(keys[0]); + +let expiredKeys = expiryManager.getExpiredKeys(); +expiredKeys = expiryManager.getExpiredKeys(expiryManager.now()); + +expiredKeys = expiryManager.extractExpiredKeys(); +expiredKeys = expiryManager.extractExpiredKeys(expiryManager.now()); + +expiryManager.clear(); diff --git a/types/expirymanager/index.d.ts b/types/expirymanager/index.d.ts new file mode 100644 index 0000000000..c192da7af7 --- /dev/null +++ b/types/expirymanager/index.d.ts @@ -0,0 +1,25 @@ +// Type definitions for expirymanager 0.9 +// Project: https://github.com/SocketCluster/expirymanager +// Definitions by: Daniel Rose +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +export type Key = any; +export type Keys = Key[]; + +export class ExpiryManager { + constructor(); + + now(): number; + + expire(keys: Keys, seconds: number): void; + unexpire(keys: Keys): void; + + getExpiry(key: Key): number; + + getKeysByExpiry(expiry: number): Keys; + + getExpiredKeys(time?: number): Keys; + extractExpiredKeys(time?: number): Keys; + + clear(): void; +} diff --git a/types/expirymanager/tsconfig.json b/types/expirymanager/tsconfig.json new file mode 100644 index 0000000000..094c4e8c8d --- /dev/null +++ b/types/expirymanager/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": [ + "es6" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "expirymanager-tests.ts" + ] +} diff --git a/types/expirymanager/tslint.json b/types/expirymanager/tslint.json new file mode 100644 index 0000000000..f93cf8562a --- /dev/null +++ b/types/expirymanager/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": "dtslint/dt.json" +} diff --git a/types/fleximap/fleximap-tests.ts b/types/fleximap/fleximap-tests.ts new file mode 100644 index 0000000000..4ca0181662 --- /dev/null +++ b/types/fleximap/fleximap-tests.ts @@ -0,0 +1,27 @@ +import { FlexiMap } from "fleximap"; + +let flexiMap = new FlexiMap(); +flexiMap = new FlexiMap({ arr: [] }); +flexiMap = new FlexiMap([{ arr: [] }, { obj: {} }]); + +flexiMap.set('keyA', {arr: [], obj: {}}); +let result = flexiMap.get(['keyA', 'arr']); + +flexiMap.add(['keyB1', 'keyB2', 'keyB3'], 123); +result = flexiMap.get(['keyB1', 'keyB2']); + +const arr = []; +arr[5] = 'Hello world'; + +flexiMap.set(['keyC1', 'keyC2'], arr); +result = flexiMap.get(['keyC1', 'keyC2']); + +flexiMap.set(['itemsA', 0], 'hello'); +flexiMap.set(['itemsA', 2], 'world'); +flexiMap.remove(['itemsA', 0]); + +flexiMap.set(['itemsB', 0], 'a'); +flexiMap.set(['itemsB', 1], 'b'); +flexiMap.set(['itemsB', 2], 'c'); +let splicedItems = flexiMap.splice(['itemsB'], 1, 1); +splicedItems = flexiMap.splice(['itemsB'], 1, 0, 'b2'); diff --git a/types/fleximap/index.d.ts b/types/fleximap/index.d.ts new file mode 100644 index 0000000000..8481134ffe --- /dev/null +++ b/types/fleximap/index.d.ts @@ -0,0 +1,38 @@ +// Type definitions for fleximap 0.9 +// Project: https://github.com/SocketCluster/fleximap +// Definitions by: Daniel Rose +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.4 + +export type KeyChain = any; + +export class FlexiMap { + constructor(object?: any[] | object); + + get(keyChain: KeyChain): any; + getRange(keyChain: KeyChain, fromIndex: number, toIndex: number): any; + getRaw(keyChain: KeyChain): any; + getAll(): any[] | object; + + count(keyChain: KeyChain): number; + + hasImmediateKey(key: string): boolean; + hasKey(keyChain: KeyChain): boolean; + hasType(keyChain: KeyChain, type: any): boolean; + hasValue(keyChain: KeyChain, value: any): boolean; + hasObject(keyChain: KeyChain, object: object): boolean; + + set(keyChain: KeyChain, value: any): any; + + add(keyChain: KeyChain, value: any): number; + + concat(keyChain: KeyChain, value: any): any; + + remove(keyChain: KeyChain): any; + removeRange(keyChain: KeyChain, fromIndex: number, toIndex: number): any[]; + removeAll(): void; + + splice(keyChain: KeyChain, index: number, count: number, ...items: any[]): any[]; + + pop(keyChain: KeyChain): any[]; +} diff --git a/types/fleximap/tsconfig.json b/types/fleximap/tsconfig.json new file mode 100644 index 0000000000..710fa81c96 --- /dev/null +++ b/types/fleximap/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": [ + "es6" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "fleximap-tests.ts" + ] +} diff --git a/types/fleximap/tslint.json b/types/fleximap/tslint.json new file mode 100644 index 0000000000..f93cf8562a --- /dev/null +++ b/types/fleximap/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": "dtslint/dt.json" +} diff --git a/types/sc-auth/index.d.ts b/types/sc-auth/index.d.ts new file mode 100644 index 0000000000..84f92bf674 --- /dev/null +++ b/types/sc-auth/index.d.ts @@ -0,0 +1,19 @@ +// Type definitions for sc-auth 5.0 +// Project: https://github.com/SocketCluster/sc-auth +// Definitions by: Daniel Rose +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.2 + +import { VerifyOptions, VerifyCallback, Secret, SignCallback, SignOptions } from "jsonwebtoken"; + +export interface SCAuthEngine { + verifyToken(signedToken: string, key: string | Buffer, options?: VerifyOptions, callback?: VerifyCallback): void; + signToken(token: string | object | Buffer, key: Secret, options?: SignOptions, callback?: SignCallback): void; +} + +export class AuthEngine implements SCAuthEngine { + constructor(); + + verifyToken(signedToken: string, key: string | Buffer, options?: VerifyOptions, callback?: VerifyCallback): void; + signToken(token: string | object | Buffer, key: Secret, options?: SignOptions, callback?: SignCallback): void; +} diff --git a/types/sc-auth/sc-auth-tests.ts b/types/sc-auth/sc-auth-tests.ts new file mode 100644 index 0000000000..4fa57d3391 --- /dev/null +++ b/types/sc-auth/sc-auth-tests.ts @@ -0,0 +1,102 @@ +/** + * This mostly delegates to jwt, so using its tests as base + */ + +import scAuth = require("sc-auth"); +import fs = require("fs"); + +let signedToken = ""; +let cert: Buffer; + +interface TestObject { + foo: string; +} + +const testObject = { foo: "bar" }; + +const authEngine = new scAuth.AuthEngine(); + +// sign with default (HMAC SHA256) +authEngine.signToken(testObject, "shhhhh"); + +// sign with default (HMAC SHA256) and single audience +authEngine.signToken(testObject, "shhhhh", { audience: "theAudience" }); + +// sign with default (HMAC SHA256) and multiple audiences +authEngine.signToken(testObject, "shhhhh", { + audience: ["audience1", "audience2"] +}); + +// sign with default (HMAC SHA256) and a keyid +authEngine.signToken(testObject, "shhhhh", { keyid: "theKeyId" }); + +// sign with RSA SHA256 +cert = fs.readFileSync("private.key"); // get private key +authEngine.signToken(testObject, cert, { algorithm: "RS256" }); + +// sign with encrypted RSA SHA256 private key (only PEM encoding is supported) +const privKey: Buffer = fs.readFileSync("encrypted_private.key"); // get private key +const secret = { key: privKey.toString(), passphrase: "keypwd" }; +authEngine.signToken(testObject, secret, { algorithm: "RS256" }); // the algorithm option is mandatory in this case + +// sign asynchronously +authEngine.signToken(testObject, cert, { algorithm: "RS256" }, (err, token) => { + signedToken = token; +}); + +// verify a token symmetric +authEngine.verifyToken(signedToken, "shhhhh", {}, (err, decoded) => { + const result = decoded as TestObject; + + console.log(result.foo); // bar +}); + +// use external time for verifying +authEngine.verifyToken(signedToken, "shhhhh", { clockTimestamp: 1 }, (err, decoded) => { + const result = decoded as TestObject; + + console.log(result.foo); // bar +}); + +// invalid token +authEngine.verifyToken(signedToken, "wrong-secret", {}, (err, decoded) => { + console.log(err); + + // decoded undefined +}); + +// verify a token asymmetric +cert = fs.readFileSync("public.pem"); // get public key +authEngine.verifyToken(signedToken, cert, {}, (err, decoded) => { + const result = decoded as TestObject; + + console.log(result.foo); // bar +}); + +// verify audience +cert = fs.readFileSync("public.pem"); // get public key +authEngine.verifyToken(signedToken, cert, { audience: "urn:foo" }, (err, decoded) => { + // if audience mismatch, err == invalid audience + console.log(err); +}); + +// verify issuer +cert = fs.readFileSync("public.pem"); // get public key +authEngine.verifyToken(signedToken, cert, { audience: "urn:foo", issuer: "urn:issuer" }, (err, decoded) => { + // if issuer mismatch, err == invalid issuer + console.log(err); +}); + +// verify algorithm +cert = fs.readFileSync("public.pem"); // get public key +authEngine.verifyToken(signedToken, cert, { algorithms: ["RS256"] }, (err, decoded) => { + // if algorithm mismatch, err == invalid algorithm + console.log(err); +}); + +// verify without expiration check +cert = fs.readFileSync("public.pem"); // get public key +authEngine.verifyToken(signedToken, cert, { ignoreExpiration: true }, (err, decoded) => { + // if ignoreExpration == false and token is expired, err == expired token + console.log(err); +}); diff --git a/types/sc-auth/tsconfig.json b/types/sc-auth/tsconfig.json new file mode 100644 index 0000000000..5c8e3a1e19 --- /dev/null +++ b/types/sc-auth/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": [ + "es6" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "sc-auth-tests.ts" + ] +} diff --git a/types/sc-auth/tslint.json b/types/sc-auth/tslint.json new file mode 100644 index 0000000000..3db14f85ea --- /dev/null +++ b/types/sc-auth/tslint.json @@ -0,0 +1 @@ +{ "extends": "dtslint/dt.json" } diff --git a/types/sc-broker-cluster/clientcluster.d.ts b/types/sc-broker-cluster/clientcluster.d.ts new file mode 100644 index 0000000000..f2234df6ab --- /dev/null +++ b/types/sc-broker-cluster/clientcluster.d.ts @@ -0,0 +1,10 @@ +import { EventEmitter } from "events"; +import { SCBrokerClient } from "sc-broker"; +import { mapperFunction } from "."; + +export class ClientCluster extends EventEmitter { + constructor(clients: SCBrokerClient[]); + + setMapper(mapper: mapperFunction): void; + getMapper(): mapperFunction; +} diff --git a/types/sc-broker-cluster/index.d.ts b/types/sc-broker-cluster/index.d.ts new file mode 100644 index 0000000000..9314acda82 --- /dev/null +++ b/types/sc-broker-cluster/index.d.ts @@ -0,0 +1,160 @@ +// Type definitions for sc-broker-cluster 6.1 +// Project: https://github.com/SocketCluster/sc-broker-cluster +// Definitions by: Daniel Rose +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.4 + +import { SCServerSocket, SCServer } from "socketcluster-server"; +import { BrokerStartInfo, BrokerExitInfo } from "socketcluster"; +import { SpliceOptions, QueryOptions } from "sc-broker"; +import { SCChannel } from "sc-channel"; +import { EventEmitter } from "events"; +import { AsyncResultArrayCallback } from "async"; +import { KeyChain, FlexiMap } from "fleximap"; +import { Keys } from "expirymanager"; +import { ClientCluster } from "./clientcluster"; + +export class AbstractDataClient extends EventEmitter { + constructor(dataClient: ClientCluster); + + set(keyChain: KeyChain, value: any, getValue?: boolean, callback?: (err?: Error) => void): void; + set(keyChain: KeyChain, value: any, callback?: (err?: Error) => void): void; + + expire(keys: Keys, seconds: number, callback?: (err?: Error) => void): void; + unexpire(keys: Keys, callback?: (err?: Error) => void): void; + + add(keyChain: KeyChain, value: any, getValue?: boolean, callback?: (err?: Error) => void): void; + add(keyChain: KeyChain, value: any, callback?: (err?: Error) => void): void; + + get(keyChain: KeyChain, callback: (err: Error | null, value: any) => void): void; + + getRange(keyChain: KeyChain, fromIndex: number, toIndex: number, callback: (err: Error | null, value: any) => void): void; + getRange(keyChain: KeyChain, fromIndex: number, callback: (err: Error | null, value: any) => void): void; + + getAll(callback: (err: Error | null, value: any[] | object) => void): void; + + count(keyChain: KeyChain, callback: (err: Error | null, value: number) => void): void; + + remove(keyChain: KeyChain, getValue?: boolean, callback?: (err?: Error) => void): void; + remove(keyChain: KeyChain, callback?: (err?: Error) => void): void; + + removeRange(keyChain: KeyChain, fromIndex: number, toIndex?: number, getValue?: boolean, callback?: (err?: Error) => void): void; + removeRange(keyChain: KeyChain, fromIndex: number, toIndex?: number, callback?: (err?: Error) => void): void; + removeRange(keyChain: KeyChain, fromIndex: number, callback?: (err?: Error) => void): void; + + removeAll(callback?: (err: Error) => void): void; + + splice(keyChain: KeyChain, options?: SpliceOptions, callback?: (err?: Error) => void): void; + splice(keyChain: KeyChain, callback?: (err?: Error) => void): void; + + pop(keyChain: KeyChain, callback: (err: Error | null, data: any) => void): void; + + hasKey(keyChain: KeyChain, callback: (err: Error | null, data: boolean) => void): void; + + extractKeys(keyChain: KeyChain): string[]; + + extractValues(keyChain: KeyChain): any[]; + + exec(query: (datamap: FlexiMap) => void, options?: QueryOptions, callback?: (err: Error | null, data: any) => void): void; + exec(query: (datamap: FlexiMap) => void, callback: (err: Error | null, data: any) => void): void; +} + +export type handlerFunction = (data: any) => void; + +export type mapperFunction = (keyChain: KeyChain, method: string, clientIds: number[]) => number | number[]; + +/** + * The exchange object is a top-level SCBrokerClient which lets you publish events and manipulate data within your brokers - It represents a cluster of 1 or more brokers. + */ +export class SCExchange extends AbstractDataClient { + constructor(privateClientCluster: ClientCluster, publicClientCluster: ClientCluster, ioClusterClient: Client); + + send(data: any, mapIndex: number | string | string[] | null, callback?: (err?: Error) => void): void; + + publish(channelName: string, data: any, callback: (err?: Error) => void): void; + + subscribe(channelName: string): SCChannel; + unsubscribe(channelName: string): void; + + channel(channelName: string): SCChannel; + destroyChannel(channelName: string): void; + + subscriptions(includePending?: boolean): string[]; + isSubscribed(channelName: string, includePending?: boolean): boolean; + + watch(channelName: string, handler: handlerFunction): void; + unwatch(channelName: string, handler?: handlerFunction): void; + watchers(channelName: string): handlerFunction[]; + + setMapper(mapper: mapperFunction): void; + getMapper(): mapperFunction; + + map(keyChain: KeyChain, method: string): { type: string; targets: Client[] }; + + destroy(): void; +} + +export interface SCBrokerClusterServerOptions { + brokers: string[]; + debug?: boolean; + inspect?: boolean; + instanceId?: string; + secretKey?: string; + expiryAccuracy?: number; + downgradeToUser: number | string; + appBrokerControllerPath?: string; + processTermTimeout?: number; + ipcAckTimeout?: number; + brokerOptions?: SCServer.SCServerOptions; +} + +export class Server extends EventEmitter { + constructor(options: SCBrokerClusterServerOptions); + + on(event: "brokerStart", listener: (brokerInfo: BrokerStartInfo) => void): this; + on(event: "brokerExit", listener: (brokerInfo: BrokerExitInfo) => void): this; + on(event: "brokerMessage", listener: (brokerId: string, data: any, callback: (err: Error | null, data: any) => void) => void): this; + on(event: "ready", listener: () => void): this; + on(event: "error", listener: (err?: Error) => void): this; + + sendToBroker(brokerId: string, data: any, callback: (err: Error | null, data: any) => void): void; + killBrokers(): void; + destroy(): void; +} + +export interface SCBrokerClusterClientOptions { + brokers: string[]; + secretKey?: string; + pubSubBatchDuration?: number; + connectRetryErrorThreshold: number; +} + +export interface MessagePacket { + channel: string; + data: any; +} + +export class Client extends EventEmitter { + constructor(options: SCBrokerClusterClientOptions); + + exchange(): SCExchange; + + options: SCBrokerClusterClientOptions; + + on(event: "error", listener: (err?: Error) => void): this; + on(event: "warning", listener: (warning?: Error) => void): this; + on(event: "ready", listener: () => void): this; + on(event: "message", listener: (packet: MessagePacket) => void): this; + + destroy(callback: AsyncResultArrayCallback): void; + + subscribe(channel: string, callback: (err?: Error) => void): void; + unsubscribe(channel: string, callback: () => void): void; + unsubscribeAll(callback: () => void): void; + isSubscribed(channel: string, includePending: boolean): boolean; + + subscribeSocket(socket: SCServerSocket, channel: string, callback?: (err?: Error) => void): void; + unsubscribeSocket(socket: SCServerSocket, channel: string, callback?: () => void): void; + + setSCServer(scServer: SCServer): void; +} diff --git a/types/sc-broker-cluster/sc-broker-cluster-tests.ts b/types/sc-broker-cluster/sc-broker-cluster-tests.ts new file mode 100644 index 0000000000..0f5c274248 --- /dev/null +++ b/types/sc-broker-cluster/sc-broker-cluster-tests.ts @@ -0,0 +1,29 @@ +import { Client } from "sc-broker-cluster"; +import { SCServer, SCServerSocket } from "socketcluster-server"; +import WebSocket = require("ws"); + +const client = new Client({ + brokers: [], + secretKey: "secretKey", + pubSubBatchDuration: 100, + connectRetryErrorThreshold: 5 +}); + +client.on("error", err => {}); +client.on("warning", err => {}); + +const exchange = client.exchange(); + +const scServer = new SCServer(); +client.setSCServer(scServer); + +client.once("ready", () => {}); + +const wsSocket = new WebSocket("address"); +const socket = new SCServerSocket("id", scServer, wsSocket); +client.subscribeSocket(socket, "channelName", err => {}); + +client.unsubscribeSocket(socket, "channelName"); + +const data: any = {}; +exchange.publish("channelName", data, err => {}); diff --git a/types/sc-broker-cluster/scbroker.d.ts b/types/sc-broker-cluster/scbroker.d.ts new file mode 100644 index 0000000000..a7ddb7db87 --- /dev/null +++ b/types/sc-broker-cluster/scbroker.d.ts @@ -0,0 +1,3 @@ +import SCBroker = require("sc-broker/scbroker"); + +export = SCBroker; diff --git a/types/sc-broker-cluster/tsconfig.json b/types/sc-broker-cluster/tsconfig.json new file mode 100644 index 0000000000..8ace8fc9dc --- /dev/null +++ b/types/sc-broker-cluster/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": [ + "es6" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "clientcluster.d.ts", + "scbroker.d.ts", + "sc-broker-cluster-tests.ts" + ] +} diff --git a/types/sc-broker-cluster/tslint.json b/types/sc-broker-cluster/tslint.json new file mode 100644 index 0000000000..f93cf8562a --- /dev/null +++ b/types/sc-broker-cluster/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": "dtslint/dt.json" +} diff --git a/types/sc-broker/index.d.ts b/types/sc-broker/index.d.ts new file mode 100644 index 0000000000..ccb83e880e --- /dev/null +++ b/types/sc-broker/index.d.ts @@ -0,0 +1,165 @@ +// Type definitions for sc-broker 5.1 +// Project: https://github.com/SocketCluster/sc-broker +// Definitions by: Daniel Rose +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.4 + +import { SCServer } from "socketcluster-server"; +import { WorkerExitInfo } from "socketcluster"; +import { EventEmitter } from "events"; +import { KeyChain, FlexiMap } from "fleximap"; +import { Keys, Key } from "expirymanager"; + +export interface SCBrokerServerOptions { + id?: string; + instanceId?: string; + debug?: boolean; + inspect?: boolean; + socketPath?: string; + port?: number; + expiryAccuracy?: number; + downgradeToUser: number | string; + brokerControllerPath?: string; + processTermTimeout?: number; + ipcAckTimeout?: number; + secretKey?: string; + brokerOptions?: SCServer.SCServerOptions; +} + +export interface SCBrokerServer extends EventEmitter { + options: SCBrokerServerOptions; + socketPath?: string; + port?: number; + ipcAckTimeout: number; + + on(event: "error", listener: (err?: Error) => void): this; + on(event: "brokerMessage", listener: (brokerId: string, data: any, callback: (err: Error | null, data: any) => void) => void): this; + on(event: "ready", listener: (data: any) => void): this; + on(event: "exit", listener: (data: WorkerExitInfo) => void): this; + + sendToBroker(data: any, callback?: (err: Error | null, data: any, brokerId: string) => void): void; +} + +export function createServer(options?: SCBrokerServerOptions): SCBrokerServer; + +export interface AutoReconnectOptions { + initialDelay?: number; + randomness?: number; + multiplier?: number; + maxDelay?: number; +} + +export interface SCBrokerClientOptions { + secretKey?: string; + timeout?: number; + socketPath?: string; + port?: number; + host?: string; + autoReconnect?: boolean; + autoReconnectOptions?: AutoReconnectOptions; + connectRetryErrorThreshold?: number; + pubSubBatchDuration?: number; +} + +export interface QueryOptions { + baseKey?: KeyChain; + noAck?: boolean; + data?: any; +} + +export interface SpliceOptions { + index?: number; + count?: number; + items?: any[]; + getValue?: boolean; + noAck?: boolean; +} + +export interface SCBrokerClient extends EventEmitter { + readonly CONNECTED: "connected"; + readonly CONNECTING: "connecting"; + readonly DISCONNECTED: "disconnected"; + + socketPath?: string; + port?: number; + host?: string; + autoReconnect: boolean; + autoReconnectOptions?: AutoReconnectOptions; + connectRetryErrorThreshold: number; + state: "connected" | "connecting" | "disconnected"; + connectAttempts: number; + pendingReconnect: boolean; + pendingReconnectTimeout: number | null; + + on(event: "error", listener: (err?: Error) => void): this; + on(event: "warning", listener: (warning?: Error) => void): this; + on(event: "ready", listener: (data: any) => void): this; + on(event: "message", listener: (channel: string, data: any) => void): this; + on(event: "subscribeFail", listener: (err: Error | null, channel: string) => void): this; + on(event: "subscribe", listener: (channel: string) => void): this; + on(event: "unsubscribe", listener: () => void): this; + + isConnected(): boolean; + + subscribe(channel: string, ackCallback: (err?: Error) => void, force?: boolean): void; + unsubscribe(channel: string, ackCallback: (err?: Error) => void): void; + + subscriptions(includePending?: boolean): string[]; + isSubscribed(channel: string, includePending?: boolean): boolean; + + publish(channel: string, data: any, callback: (err?: Error) => void): void; + + send(data: any, callback: (err?: Error) => void): void; + + set(keyChain: KeyChain, value: any, getValue?: boolean, callback?: (err?: Error) => void): void; + set(keyChain: KeyChain, value: any, callback?: (err?: Error) => void): void; + + expire(keys: Keys, seconds: number, callback?: (err?: Error) => void): void; + unexpire(keys: Keys, callback?: (err?: Error) => void): void; + getExpiry(key: Key, callback?: (err?: Error) => void): number; + + add(keyChain: KeyChain, value: any, getValue?: boolean, callback?: (err?: Error) => void): void; + add(keyChain: KeyChain, value: any, callback?: (err?: Error) => void): void; + + concat(keyChain: KeyChain, value: any, getValue?: boolean, callback?: (err?: Error) => void): void; + concat(keyChain: KeyChain, value: any, callback?: (err?: Error) => void): void; + + get(keyChain: KeyChain, callback: (err: Error | null, value: any) => void): void; + + getRange(keyChain: KeyChain, fromIndex: number, toIndex: number, callback: (err: Error | null, value: any) => void): void; + getRange(keyChain: KeyChain, fromIndex: number, callback: (err: Error | null, value: any) => void): void; + + getAll(callback: (err: Error | null, value: any[] | object) => void): void; + + count(keyChain: KeyChain, callback: (err: Error | null, value: number) => void): void; + + exec(query: (datamap: FlexiMap) => void, options?: QueryOptions, callback?: (err: Error | null, data: any) => void): void; + exec(query: (datamap: FlexiMap) => void, callback: (err: Error | null, data: any) => void): void; + + query(query: (datamap: FlexiMap) => void, data?: any, callback?: (err: Error | null, data: any) => void): void; + query(query: (datamap: FlexiMap) => void, callback: (err: Error | null, data: any) => void): void; + + remove(keyChain: KeyChain, getValue?: boolean, callback?: (err?: Error) => void): void; + remove(keyChain: KeyChain, callback?: (err?: Error) => void): void; + + removeRange(keyChain: KeyChain, fromIndex: number, toIndex?: number, getValue?: boolean, callback?: (err?: Error) => void): void; + removeRange(keyChain: KeyChain, fromIndex: number, toIndex?: number, callback?: (err?: Error) => void): void; + removeRange(keyChain: KeyChain, fromIndex: number, callback?: (err?: Error) => void): void; + + removeAll(callback?: (err: Error) => void): void; + + splice(keyChain: KeyChain, options?: SpliceOptions, callback?: (err?: Error) => void): void; + splice(keyChain: KeyChain, callback?: (err?: Error) => void): void; + + pop(keyChain: KeyChain, callback: (err: Error | null, data: any) => void): void; + + hasKey(keyChain: KeyChain, callback: (err: Error | null, data: boolean) => void): void; + + extractKeys(keyChain: KeyChain): string[]; + + extractValues(keyChain: KeyChain): any[]; + + end(callback: (err?: Error) => void): void; +} + +export function createClient(options?: SCBrokerClientOptions): SCBrokerClient; diff --git a/types/sc-broker/sc-broker-tests.ts b/types/sc-broker/sc-broker-tests.ts new file mode 100644 index 0000000000..201ff10a27 --- /dev/null +++ b/types/sc-broker/sc-broker-tests.ts @@ -0,0 +1,58 @@ +import { SCServer, SCServerSocket } from "socketcluster-server"; +import SCBroker = require("sc-broker/scbroker"); +import { FlexiMap } from "fleximap"; +import { ExpiryManager } from "expirymanager"; + +//////////////////////////////////////////////////// +/// SCBroker tests +//////////////////////////////////////////////////// + +const options: SCServer.SCServerOptions = { port: 80 }; + +let scBroker = new SCBroker(); +scBroker = new SCBroker(options); +scBroker.options = { environment: "prod" }; + +const id: number = scBroker.id; +const instanceId: number = scBroker.instanceId; +const dataMap: FlexiMap = scBroker.dataMap; +const dataExpirer: ExpiryManager = scBroker.dataExpirer; +const subscriptions = scBroker.subscriptions; + +const socket: SCServerSocket = subscriptions[1]["test"]; + +scBroker.on("subscribe", channel => { + const subscribeChannel: string = channel; +}); +scBroker.on("unsubscribe", channel => { + const unsubscribeChannel: string = channel; +}); +scBroker.on("publish", (channel, data) => { + const publishChannel: string = channel; + const publishData: any = data; +}); +scBroker.on("masterMessage", (data, masterMessageResponse) => { + const masterMessageData: any = data; + masterMessageResponse(null, "test"); + masterMessageResponse(new Error(), null); +}); + +scBroker.publish("testChannel", 123); + +scBroker.exec(dataMap => { + dataMap.set(["main", "message"], "Message"); + return dataMap.get(["main"]); +}); + +scBroker.sendToMaster("data"); +scBroker.sendToMaster(123, (err, response) => { + if (!err) { + const answer = response; + } +}); + +class MyBroker extends SCBroker { + run() { + this.on("subscribe", channel => {}); + } +} diff --git a/types/sc-broker/scbroker.d.ts b/types/sc-broker/scbroker.d.ts new file mode 100644 index 0000000000..057b983adf --- /dev/null +++ b/types/sc-broker/scbroker.d.ts @@ -0,0 +1,32 @@ +import { EventEmitter } from "events"; +import { SCServer, SCServerSocket } from "socketcluster-server"; +import { FlexiMap, KeyChain } from "fleximap"; +import { ExpiryManager } from "expirymanager"; + +export = SCBroker; + +interface Subscriptions { + [socketId: number]: { + [channel: string]: SCServerSocket; + }; +} + +declare class SCBroker extends EventEmitter { + id: number; + options: SCServer.SCServerOptions; + instanceId: number; + dataMap: FlexiMap; + dataExpirer: ExpiryManager; + subscriptions: Subscriptions; + + constructor(options?: SCServer.SCServerOptions); + + on(event: "subscribe" | "unsubscribe", listener: (channel: string) => void): this; + on(event: "publish", listener: (channel: string, data: any) => void): this; + on(event: "masterMessage", listener: (data: any, respond: (err: Error | null, responseData: any) => void) => void): this; + + publish(channel: string, message: any): void; + run(): void; + exec(query: (dataMap: FlexiMap, dataExpirer: ExpiryManager, subscriptions: Subscriptions) => any, baseKey?: KeyChain): any; + sendToMaster(data: any, callback?: (err: Error | null, responseData: any) => void): void; +} diff --git a/types/sc-broker/tsconfig.json b/types/sc-broker/tsconfig.json new file mode 100644 index 0000000000..6adfe07a5b --- /dev/null +++ b/types/sc-broker/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": [ + "es6" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "scbroker.d.ts", + "sc-broker-tests.ts" + ] +} diff --git a/types/sc-broker/tslint.json b/types/sc-broker/tslint.json new file mode 100644 index 0000000000..f93cf8562a --- /dev/null +++ b/types/sc-broker/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": "dtslint/dt.json" +} diff --git a/types/sc-channel/index.d.ts b/types/sc-channel/index.d.ts new file mode 100644 index 0000000000..034723c0ba --- /dev/null +++ b/types/sc-channel/index.d.ts @@ -0,0 +1,45 @@ +// Type definitions for sc-channel 1.2 +// Project: https://github.com/SocketCluster/sc-channel +// Definitions by: Daniel Rose +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.4 + +import Emitter = require("component-emitter"); +import { SCExchange, handlerFunction } from "sc-broker-cluster"; + +export interface SCChannelOptions { + waitForAuth?: boolean; + batch?: boolean; + data?: any; +} + +export class SCChannel extends Emitter { + readonly PENDING: "pending"; + readonly SUBSCRIBED: "subscribed"; + readonly UNSUBSCRIBED: "unsubscribed"; + + name: string; + state: ChannelState; + waitForAuth: boolean; + batch: boolean; + data: any; + + constructor(name: string, client: SCExchange, options?: SCChannelOptions); + + setOptions(options?: SCChannelOptions): void; + getState(): "pending" | "subscribed" | "unsubscribed"; + + subscribe(options?: any): void; + unsubscribe(): void; + isSubscribed(includePending?: boolean): boolean; + + publish(data: any, callback?: (err?: Error) => void): void; + + watch(handler: handlerFunction): void; + unwatch(handler?: handlerFunction): void; + watchers(): handlerFunction[]; + + destroy(): void; +} + +export type ChannelState = "pending" | "subscribed" | "unsubscribed"; diff --git a/types/sc-channel/sc-channel-tests.ts b/types/sc-channel/sc-channel-tests.ts new file mode 100644 index 0000000000..bfc90cee12 --- /dev/null +++ b/types/sc-channel/sc-channel-tests.ts @@ -0,0 +1,33 @@ +import { SCChannel, SCChannelOptions } from "sc-channel"; +import { handlerFunction, Client, SCBrokerClusterClientOptions } from "sc-broker-cluster"; + +const clientOptions: SCBrokerClusterClientOptions = { brokers: [], connectRetryErrorThreshold: 0 }; +const client = new Client(clientOptions); + +let channel = new SCChannel("channelName", client.exchange()); +const channelOptions: SCChannelOptions = {}; +channel = new SCChannel("channelName", client.exchange(), channelOptions); + +channel.state = channel.PENDING; +channel.state = channel.SUBSCRIBED; +channel.state = channel.UNSUBSCRIBED; + +const channelName: string = channel.name; + +const handler: handlerFunction = () => { }; + +channel.watch(handler); +channel.unwatch(); + +channel.subscribe(); +channel.subscribe(channelOptions); +channel.unsubscribe(); + +const data: any = channel.data; + +channel.emit("subscribe", channelName); +channel.emit("unsubscribe", channelName); + +channel.setOptions(channelOptions); + +channel.publish(data); diff --git a/types/sc-channel/tsconfig.json b/types/sc-channel/tsconfig.json new file mode 100644 index 0000000000..c5c5ce5f14 --- /dev/null +++ b/types/sc-channel/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": [ + "es6" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "sc-channel-tests.ts" + ] +} diff --git a/types/sc-channel/tslint.json b/types/sc-channel/tslint.json new file mode 100644 index 0000000000..f93cf8562a --- /dev/null +++ b/types/sc-channel/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": "dtslint/dt.json" +} diff --git a/types/socketcluster-client/index.d.ts b/types/socketcluster-client/index.d.ts new file mode 100644 index 0000000000..9c15a45465 --- /dev/null +++ b/types/socketcluster-client/index.d.ts @@ -0,0 +1,23 @@ +// Type definitions for socketcluster-client 13.0 +// Project: https://github.com/SocketCluster/socketcluster-client +// Definitions by: Daniel Rose +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.4 + +import { SCAuthEngine } from "sc-auth"; +import { SCServer } from "socketcluster-server"; + +export import SCClientSocket = require("./lib/scclientsocket"); + +export function create(options?: SCClientSocket.ClientOptions): SCClientSocket; + +/** @deprecated */ +export function connect(options?: SCClientSocket.ClientOptions): SCClientSocket; + +export function destroy(socket: SCClientSocket): void; + +export const clients: { + [id: string]: SCClientSocket; +}; + +export const version: string; diff --git a/types/socketcluster-client/lib/scclientsocket.d.ts b/types/socketcluster-client/lib/scclientsocket.d.ts new file mode 100644 index 0000000000..19552bd102 --- /dev/null +++ b/types/socketcluster-client/lib/scclientsocket.d.ts @@ -0,0 +1,251 @@ +import Emitter = require("component-emitter"); +import { SCServer } from "socketcluster-server"; +import { SCAuthEngine } from "sc-auth"; +import { SCChannel, SCChannelOptions, ChannelState } from "sc-channel"; +import WebSocket = require("ws"); + +declare class SCClientSocket extends Emitter { + constructor(opts: SCClientSocket.ClientOptions); + + id: string; + + channels: { + [channelName: string]: SCChannel; + }; + + CONNECTING: "connecting"; + OPEN: "open"; + CLOSED: "closed"; + + state: SCClientSocket.States; + getState(): SCClientSocket.States; + + AUTHENTICATED: "authenticated"; + UNAUTHENTICATED: "unauthenticated"; + + authState: SCClientSocket.AuthStates; + + PENDING: "pending"; + + pendingReconnect: boolean; + pendingReconnectTimeout: number; + + getBytesReceived(): number; + + deauthenticate(callback?: (err: Error) => void): void; + + connect(): void; + open(): void; + disconnect(code?: number, data?: string | object): void; + reconnect(code?: number, data?: string | object): void; + destroy(code?: number, data?: string | object): void; + + decodeBase64(encodedString: string): string; + encodeBase64(decodedString: string): string; + + getAuthToken(): object | null; + authToken: object | null; + + getSignedAuthToken(): string | null; + signedAuthToken: string | null; + + // Perform client-initiated authentication by providing an encrypted token string. + authenticate(signedAuthToken: string, callback?: (err: Error, authStatus: SCClientSocket.AuthStatus) => void): void; + + decode(message: any): any; + encode(object: any): any; + + send(data: any): void; + + emit(event: string, data: any, callback?: (err: Error, responseData: any) => void): void; + + publish(channelName: string, data: any, callback?: (err: Error, ackData: any) => void): void; + + subscribe(channelName: string, options?: SCChannelOptions): SCChannel; + unsubscribe(channelName: string): void; + + channel(channelName: string, options?: SCChannelOptions): SCChannel; + + destroyChannel(channelName: string): void; + + subscriptions(includePending?: boolean): string[]; + isSubscribed(channelName: string, includePending?: boolean): boolean; + + processPendingSubscriptions(): void; + + watch(channelName: string, handler: SCClientSocket.WatcherFunction): void; + unwatch(channelName: string, handler?: SCClientSocket.WatcherFunction): void; + watchers(channelName: string): SCClientSocket.WatcherFunction[]; + + on(event: "connecting", listener: () => void): this; + on(event: "connect", listener: (status: SCClientSocket.ConnectStatus, processSubscriptions: () => void) => void): this; + on(event: "connectAbort" | "disconnect" | "close", listener: (code: number, data: string | object) => void): this; + + on(event: "kickOut", listener: (message: string, channelName: string) => void): this; + + on(event: "authenticate", listener: (signedAuthToken: string | null) => void): this; + on(event: "deauthenticate", listener: (oldSignedToken: string | null) => void): this; + on(event: "authStateChange", listener: (stateChangeData: SCClientSocket.AuthStateChangeData) => void): this; + on(event: "removeAuthToken", listener: (oldToken: object | null) => void): this; + + on(event: "subscribe" | "subscribeRequest", listener: (channelName: string, subscriptionOptions: SCChannelOptions) => void): this; + on(event: "subscribeStateChange", listener: (stateChangeData: SCClientSocket.SubscribeStateChangeData) => void): this; + on(event: "subscribeFail", listener: (err: Error, channelName: string, subscriptionOptions: SCChannelOptions) => void): this; + on(event: "unsubscribe", listener: (channelName: string) => void): this; + + on(event: "error", listener: (err: Error) => void): this; + + on(event: "raw", listener: (data: any) => void): this; + on(event: "message", listener: (message: WebSocket.Data) => void): this; + + // Implements Emitter interface + + // tslint:disable:ban-types + // tslint:disable:adjacent-overload-signatures + on(event: string, listener: Function): this; + once(event: string, listener: Function): this; + off(event?: string, listener?: Function): this; + emit(event: string, ...args: any[]): boolean; + listeners(event: string): Function[]; + hasListeners(event: string): boolean; + // tslint:enable:adjacent-overload-signatures + // tslint:enable:ban-types +} + +export = SCClientSocket; + +declare namespace SCClientSocket { + interface ClientOptions { + host?: string; + + // Defaults to the current host (read from the URL). + hostname?: string; + + // Defaults to false. + secure?: boolean; + + // Defaults to 80 if !secure otherwise defaults to 443. + port?: number; + + // The URL which SC uses to make the initial handshake for the WebSocket. Defaults to '/socketcluster/'. + path?: string; + + // A map of key-value pairs which will be used as query parameters for the initial HTTP handshake which will initiate the WebSocket connection. + query?: string | { [key: string]: string }; + + // (milliseconds) - This is the timeout for getting a response to a SCSocket emit event (when a callback is provided). + ackTimeout?: number; + + // (milliseconds) + connectTimeout?: number; + + // Whether or not to automatically connect the socket as soon as it is created. Default is true. + autoConnect?: boolean; + + // Whether or not to automatically reconnect the socket when it loses the connection. + autoReconnect?: boolean; + + // Valid properties are: initialDelay (milliseconds), randomness (milliseconds), multiplier (decimal; default is 1.5) and maxDelay (milliseconds). + autoReconnectOptions?: AutoReconnectOptions; + + // Whether or not a client automatically disconnects on page unload. If enabled, the client will disconnect when a user navigates away from the page. + // This can happen when a user closes the tab/window, clicks a link to leave the page, or types a new URL into the address bar. Defaults to true. + disconnectOnUnload?: boolean; + + // Turn on/off per-message deflate compression. If this is true, you need to make sure that this property is also set to true on the server-side. + // Note that this option is only relevant when running the client from Node.js. Most modern browsers will automatically use perMessageDeflate so + // you only need to turn it on from the server-side. + perMessageDeflate?: boolean; + + // Defaults to true; multiplexing allows you to reuse a socket instead of creating a second socket to the same address. + multiplex?: boolean; + + // Defaults to null (0 milliseconds); this property affects channel subscription batching; it determines the period in milliseconds for batching + // multiple subscription requests together. It only affects channels that have the batch option set to true. A value of null or 0 means that all + // subscribe or unsubscribe requests which were made within the same call stack will be batched together. This property was introduced on the + // client-side in SC version 8 (both the client and server versions need to be >= 8.0.0). Note that there is also a separate property with the + // same name which can be configured on the server. + pubSubBatchDuration?: number; + + // Whether or not to add a timestamp to the WebSocket handshake request. + timestampRequests?: boolean; + + // The query parameter name to use to hold the timestamp. + timestampParam?: string; + + // A custom engine to use for storing and loading JWT auth tokens on the client side. + authEngine?: SCAuthEngine | null; + + // The name of the JWT auth token (provided to the authEngine - By default this is the localStorage variable name); defaults to 'socketCluster.authToken'. + authTokenName?: string; + + // The type to use to represent binary on the client. Defaults to 'arraybuffer'. + binaryType?: string; + + // Set this to false during debugging - Otherwise client connection will fail when using self-signed certificates. + rejectUnauthorized?: boolean; + + // If you set this to true, any data/objects/arrays that you pass to the client socket will be cloned before being sent/queued up. If the socket + // is disconnected and you emit an event, it will be added to a queue which will be processed upon reconnection. The cloneData option is false + // by default; this means that if you emit/publish an object and that object changes somewhere else in your code before the queue is processed, + // then the changed version of that object will be sent out to the server. + cloneData?: boolean; + + // This is true by default. If you set this to false, then the socket will not automatically try to subscribe to pending subscriptions on + // connect - Instead, you will have to manually invoke the processSubscriptions callback from inside the 'connect' event handler on the client side. + // See SCSocket Client API. This gives you more fine-grained control with regards to when pending subscriptions are processed after the socket + // connection is established (or re-established). + autoSubscribeOnConnect?: boolean; + + // Lets you set a custom codec engine. This allows you to specify how data gets encoded before being sent over the wire and how it gets decoded + // once it reaches the other side. The codecEngine must be an object which exposes an encode(object) and a decode(encodedData) function. + // The encode function can return any data type - Commonly a string or a Buffer/ArrayBuffer. The decode function needs to return a JavaScript + // object which adheres to the SC protocol. The idea of using a custom codec is that it allows you to compress SC packets in any format you like + // (optimized for any use case) - By decoding these packets back into their original protocol form, SC will be able process them appropriately. + // Note that if you provide a codecEngine when creating a client socket see 'codecEngine', you will need to make sure that the server uses the + // same codec by passing the same engine to `worker.scServer.setCodecEngine(codecEngine)` when your SC worker initializes on the server side + // (see 'setCodecEngine' method here). The default codec engine used by SC is here. + codecEngine?: SCServer.SCCodecEngine | null; + + // A prefix to add to the channel names. + channelPrefix?: string | null; + + subscriptionRetryOptions?: object | null; + } + + interface AutoReconnectOptions { + initialDelay?: number; + randomness?: number; + multiplier?: number; + maxDelay?: number; + } + + interface AuthStatus { + isAuthenticated: AuthStates; + authError: Error; + } + + interface AuthStateChangeData { + oldState: AuthStates; + newState: AuthStates; + } + + interface ConnectStatus { + id: string; + pingTimeout: number; + isAuthenticated: boolean; + authToken?: object; + authError?: Error; + } + + interface SubscribeStateChangeData { + channel: string; + oldState: ChannelState; + newState: ChannelState; + subscriptionOptions: SCChannelOptions; + } + + type WatcherFunction = (data: any) => void; + type AuthStates = "authenticated" | "unauthenticated"; + type States = "connecting" | "open" | "closed"; +} diff --git a/types/socketcluster-client/socketcluster-client-tests.ts b/types/socketcluster-client/socketcluster-client-tests.ts new file mode 100644 index 0000000000..527385a5eb --- /dev/null +++ b/types/socketcluster-client/socketcluster-client-tests.ts @@ -0,0 +1,75 @@ +// Adapted from README + +import { create, destroy } from "socketcluster-client"; +import { ClientOptions } from "socketcluster-client/lib/scclientsocket"; + +const secureClientOptions: ClientOptions = { + hostname: "securedomain.com", + secure: true, + port: 443, + rejectUnauthorized: false +}; + +let socket = create(secureClientOptions); + +socket.on("connect", () => { + console.log("CONNECTED"); +}); + +// Listen to an event called 'rand' from the server +socket.on("rand", (num: any) => { + console.log("RANDOM: " + num); +}); + +const options: ClientOptions = { + path: "/socketcluster/", + port: 8000, + hostname: "127.0.0.1", + autoConnect: true, + secure: false, + rejectUnauthorized: false, + connectTimeout: 10000, // milliseconds + ackTimeout: 10000, // milliseconds + channelPrefix: null, + disconnectOnUnload: true, + multiplex: true, + autoReconnectOptions: { + initialDelay: 10000, // milliseconds + randomness: 10000, // milliseconds + multiplier: 1.5, // decimal + maxDelay: 60000 // milliseconds + }, + authEngine: null, + codecEngine: null, + subscriptionRetryOptions: {}, + query: { + yourparam: "hello" + } +}; +socket = create(options); + +socket.on("subscribe", channelname => { + console.log("subscribe:" + channelname); +}); + +socket.on("subscribeFail", channelname => { + console.log("subscribeFail:" + channelname); +}); + +socket.on("unsubscribe", channelname => { + console.log("unsubscribe:" + channelname); +}); + +socket.on("subscribeStateChange", data => { + console.log("subscribeStateChange:" + JSON.stringify(data)); +}); + +socket.on("message", data => { + console.log("message:" + data); +}); + +const channels = socket.channels; +const testChannel = channels["test"]; +const state = testChannel.getState(); + +destroy(socket); diff --git a/types/socketcluster-client/tsconfig.json b/types/socketcluster-client/tsconfig.json new file mode 100644 index 0000000000..54fc6ea8af --- /dev/null +++ b/types/socketcluster-client/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": [ + "es6" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "lib/scclientsocket.d.ts", + "socketcluster-client-tests.ts" + ] +} diff --git a/types/socketcluster-client/tslint.json b/types/socketcluster-client/tslint.json new file mode 100644 index 0000000000..f93cf8562a --- /dev/null +++ b/types/socketcluster-client/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": "dtslint/dt.json" +} diff --git a/types/socketcluster-server/index.d.ts b/types/socketcluster-server/index.d.ts new file mode 100644 index 0000000000..7466d1daed --- /dev/null +++ b/types/socketcluster-server/index.d.ts @@ -0,0 +1,15 @@ +// Type definitions for socketcluster-server 13.1 +// Project: https://github.com/SocketCluster/socketcluster-server +// Definitions by: Daniel Rose +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.4 + +import { Server } from "http"; + +export import SCServer = require("./scserver"); +export import SCServerSocket = require("./scserversocket"); + +export function listen(port?: number, options?: SCServer.SCServerOptions, listeningListener?: () => void): SCServer; +export function listen(port?: number, listeningListener?: () => void): SCServer; + +export function attach(server: Server, options?: SCServer.SCServerOptions): SCServer; diff --git a/types/socketcluster-server/scserver.d.ts b/types/socketcluster-server/scserver.d.ts new file mode 100644 index 0000000000..a7147aa2dd --- /dev/null +++ b/types/socketcluster-server/scserver.d.ts @@ -0,0 +1,315 @@ +import { EventEmitter } from "events"; +import { Secret } from "jsonwebtoken"; +import { ServerOptions } from "https"; +import { IncomingMessage, Server } from "http"; +import { SCAuthEngine } from "sc-auth"; +import { SCExchange } from "sc-broker-cluster"; +import WebSocket = require("ws"); + +import SCServerSocket = require("./scserversocket"); + +declare class SCServer extends EventEmitter { + readonly MIDDLEWARE_HANDSHAKE_WS: "handshakeWS"; + readonly MIDDLEWARE_HANDSHAKE_SC: "handshakeSC"; + readonly MIDDLEWARE_AUTHENTICATE: "authenticate"; + readonly MIDDLEWARE_SUBSCRIBE: "subscribe"; + readonly MIDDLEWARE_PUBLISH_IN: "publishIn"; + readonly MIDDLEWARE_PUBLISH_OUT: "publishOut"; + readonly MIDDLEWARE_EMIT: "emit"; + + options: SCServer.SCServerOptions; + exchange: SCExchange; + + clients: { + [id: string]: SCServerSocket; + }; + clientsCount: number; + + pendingClients: { + [id: string]: SCServerSocket; + }; + pendingClientsCount: number; + + constructor(options?: SCServer.SCServerOptions); + + on(event: "connection", listener: SCServer.connectionListenerFunction): this; + + addMiddleware(type: "handshakeWS", middlewareFn: (req: IncomingMessage, next: SCServer.nextMiddlewareFunction) => void): void; + addMiddleware(type: "handshakeSC", middlewareFn: (req: SCServer.HandshakeSCRequest, next: SCServer.nextHandshakeSCMiddlewareFunction) => void): void; + addMiddleware(type: "authenticate", middlewareFn: (req: SCServer.AuthenticateRequest, next: SCServer.nextAuthenticateMiddlewareFunction) => void): void; + addMiddleware(type: "subscribe", middlewareFn: (req: SCServer.SubscribeRequest, next: SCServer.nextMiddlewareFunction) => void): void; + addMiddleware(type: "publishIn", middlewareFn: (req: SCServer.PublishInRequest, next: SCServer.nextMiddlewareFunction) => void): void; + addMiddleware(type: "publishOut", middlewareFn: (req: SCServer.PublishOutRequest, next: SCServer.nextMiddlewareFunction) => void): void; + addMiddleware(type: "emit", middlewareFn: (req: SCServer.EmitRequest, next: SCServer.nextMiddlewareFunction) => void): void; + + setAuthEngine(authEngine: SCAuthEngine): void; + setCodecEngine(codecEngine: SCServer.SCCodecEngine): void; +} + +export = SCServer; + +declare namespace SCServer { + interface AuthToken { + [x: string]: any; + } + + interface SCServerOptions { + // The port on which to listen for outside connections/requests + port?: number; + + // Number of worker processes + workers?: number; + + // Number of broker processes + brokers?: number; + + // Should be either 'dev' or 'prod' - This affects the shutdown procedure + // when a 'SIGUSR2' signal is received by master. In 'dev', a SIGUSR2 will + // trigger an immediate shutdown of workers. In 'prod' workers will + // be terminated progressively in accordance with processTermTimeout. + environment?: string; + + // Setting this to true will cause the master process to shut down when + // it receives a SIGUSR2 signal (instead of just the workers). + // If you're using nodemon, set this to true. + killMasterOnSignal?: boolean; + + // A unique name for your app (this is used internally for + // various things such as the directory name in which to store socket + // file descriptors) - If you don't provide an appName, SC will + // generate a random one (UUID v4) + appName?: string; + + // This can be the name of an npm module or a path to a Node.js module + // to use as the WebSocket server engine. + // You can now set this to 'sc-uws' for a massive speedup of at least 2x! + wsEngine?: string; + + // An ID to associate with this specific instance of SC + // this may be useful if you are running an SC app on multiple + // hosts - You can access the instanceId from the Broker object + // (inside brokerController) - If you don't provide an instanceId, + // SC will generate a random one (UUID v4) + instanceId?: string; + + // A key which various SC processes will use to interact with + // scBroker broker processes securely, defaults to a 256 bits + // cryptographically random hex string + secretKey?: string; + + // The key which SC will use to encrypt/decrypt authTokens, defaults + // to a 256 bits cryptographically random hex string + // The default JWT algorithm used is 'HS256'. + // If you want to use RSA or ECDSA, you should provide a authPrivateKey + // and authPublicKey instead of authKey. + authKey?: Secret; + + // perMessageDeflate compression. Note that this option is passed directly to the wsEngine's + // Server object. So if you're using 'ws' as the engine, you can pass an object instead of + // a boolean. Search for perMessageDeflate here: + // https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callback + // Note that by default, per-message deflate only kicks in for messages > 1024 bytes. + perMessageDeflate?: boolean; + + // If using an RSA or ECDSA algorithm to sign the authToken, you will need + // to provide an authPrivateKey and authPublicKey in PEM format (string or Buffer). + authPrivateKey?: Secret; + authPublicKey?: Secret; + + // The default expiry for auth tokens in seconds + authDefaultExpiry?: number; + + // The algorithm to use to sign and verify JWT tokens. + authAlgorithm?: string; + + // Crash workers when an error happens - This is the most sensible default + crashWorkerOnError?: boolean; + + // Reboot workers when they crash - This is a necessity + // in production but can be turned off for debugging + rebootWorkerOnCrash?: boolean; + + // Kill/respawn a worker process if its memory consumption exceeds this + // threshold (in bytes) - If this is null (default), this behavior + // will be switched off + killWorkerMemoryThreshold?: number; + + // Can be 'http' or 'https' + protocol?: "http" | "https"; + + // This is the same as the object provided to Node.js's https server + protocolOptions?: ServerOptions; + + // A log level of 3 will log everything, 2 will show notices and errors, + // 1 will only log errors, 0 will log nothing + logLevel?: 0 | 1 | 2 | 3; + + // In milliseconds, how long a client has to connect to SC before timing out + connectTimeout?: number; + + // In milliseconds - If the socket handshake hasn't been completed before + // this timeout is reached, the new connection attempt will be terminated. + handshakeTimeout?: number; + + // In milliseconds, the timeout for calling res(err, data) when + // your emit() call expects an ACK response from the other side + // (when callback is provided to emit) + ackTimeout?: number; + + // In milliseconds, the timeout for calling res(err, data) when + // your sendToWorker, sendToBroker or sendToMaster (IPC) call + // expects an ACK response from the other process + // (when callback is provided) + ipcAckTimeout?: number; + + // In milliseconds - If the socket cannot upgrade transport + // within this period, it will stop trying + socketUpgradeTimeout?: number; + + // Origins which are allowed to connect to the real-time scServer + origins?: string; + + // The maximum number of unique channels which a single + // socket can subscribe to + socketChannelLimit?: number; + + // The interval in milliseconds on which to + // send a ping to the client to check that + // it is still alive + pingInterval?: number; + + // How many milliseconds to wait without receiving a ping + // before closing the socket + pingTimeout?: number; + + // Maximum amount of milliseconds to wait before force-killing + // a process after it was passed a 'SIGTERM' or 'SIGUSR2' signal + processTermTimeout?: number; + + // Whether or not errors from child processes (workers and brokers) + // should be passed to the current master process + propagateErrors?: boolean; + + // Whether or not warnings from child processes (workers and brokers) + // should be passed to the current master process + propagateWarnings?: number; + + // Whether or not a 'warning' event should be emitted (and logged to console) + // whenever an action is blocked by a middleware function + middlewareEmitWarnings?: number; + + // Lets you specify a host name to bind to - Defaults to + // 127.0.0.1 (localhost) + host?: string; + + // The path to a file used to bootstrap worker processes + workerController?: string; + + // The path to a file used to bootstrap broker processes + brokerController?: string; + + // The path to a file used to bootstrap the workerCluster process + workerClusterController?: string; + + // By default, SC will reboot all workers when it receives a 'SIGUSR2' signal - + // This can be used for updating workers with fresh source code in production + rebootOnSignal?: boolean; + + // If you run your master process (server.js) as super user, this option + // lets you downgrade worker and broker processes to run under + // the specified user (with fewer permissions than master) - You can provide + // a Linux UID or username + downgradeToUser?: number | string; + + // The URL path reserved by SocketCluster clients to interact with the server + path?: string; + + // The root directory in which to store your socket files in Linux. + socketRoot?: string; + + // Defaults to "rr", but can be set to "none" + schedulingPolicy?: "rr" | "none"; + + // Whether or not clients are allowed to publish messages to channels + allowClientPublish?: boolean; + + // This option is passed to the Node.js HTTP server if provided + tcpSynBacklog?: number; + + // SC keeps track of request per minutes internally - This allows you to change + // how often this gets updated + workerStatusInterval?: number; + + // This allows you to batch multiple messages together when passing them across + // message brokers. This may improve the efficiency of your pub/sub operations. + // This value is in milliseconds. 5 is generally a safe value to set this to. + pubSubBatchDuration?: number; + + // The default clustering/brokering engine (Node.js module name) which provides the + // SCWorker.exchange object and manages brokers behind the scenes. + // You shouldn't need to change this unless you want to build your own + // process clustering engine (which is difficult to do). + brokerEngine?: string; + + wsEngineServerOptions?: WebSocket.ClientOptions; + maxPayload?: number; + pingTimeoutDisabled?: boolean; + authSignAsync?: boolean; + authVerifyAsync?: boolean; + httpServer?: Server; + } + + interface SCServerSocketStatus { + id: string; + pingTimeout: number; + } + + interface HandshakeSCRequest { + socket: SCServerSocket; + } + + interface AuthenticateRequest { + socket: SCServerSocket; + authToken: AuthToken; + } + + interface SubscribeRequest { + socket: SCServerSocket; + authTokenExpiredError?: Error; + channel?: string; + waitForAuth?: boolean; + data?: any; + } + + interface PublishInRequest { + socket: SCServerSocket; + authTokenExpiredError?: Error; + channel?: string; + data?: any; + ackData?: any; + } + + interface PublishOutRequest { + socket: SCServerSocket; + channel?: string; + data?: any; + useCache?: boolean; + } + + interface EmitRequest { + socket: SCServerSocket; + authTokenExpiredError?: Error; + event: string; + data?: any; + } + + type nextMiddlewareFunction = (error?: true | string | Error) => void; + type nextHandshakeSCMiddlewareFunction = (error?: true | string | Error | null, statusCode?: number) => void; + type nextAuthenticateMiddlewareFunction = (error?: true | string | Error | null, isBadToken?: boolean) => void; + type connectionListenerFunction = (scSocket: SCServerSocket, serverSocketStatus: SCServerSocketStatus) => void; + + interface SCCodecEngine { + decode: (input: any) => any; + ncode: (object: any) => any; + } +} diff --git a/types/socketcluster-server/scserversocket.d.ts b/types/socketcluster-server/scserversocket.d.ts new file mode 100644 index 0000000000..7b32cef72c --- /dev/null +++ b/types/socketcluster-server/scserversocket.d.ts @@ -0,0 +1,43 @@ +import Emitter = require("component-emitter"); +import { IncomingMessage } from "http"; +import { SCExchange } from "sc-broker-cluster"; +import { SignOptions } from "jsonwebtoken"; +import WebSocket = require("ws"); + +import SCServer = require("./scserver"); + +declare class SCServerSocket extends Emitter { + readonly CONNECTING: "connecting"; + readonly OPEN: "open"; + readonly CLOSED: "closed"; + + readonly AUTHENTICATED: "authenticated"; + readonly UNAUTHENTICATED: "unauthenticated"; + + id: string; + request: IncomingMessage; + + remoteAddress: string; + remoteFamily: string; + remotePort: number; + + exchange: SCExchange; + + state: "connecting" | "open" | "closed"; + authState: "authenticated" | "unauthenticated"; + authToken?: SCServer.AuthToken; + + constructor(id: string, server: SCServer, socket: WebSocket); + + getState(): "connecting" | "open" | "closed"; + disconnect(code?: number, data?: any): void; + send(data: any, options: { mask?: boolean; binary?: boolean; compress?: boolean; fin?: boolean }): void; + getAuthToken(): SCServer.AuthToken; + setAuthToken(data: SCServer.AuthToken, options?: SignOptions): void; + deauthenticate(): void; + kickOut(channel?: string, message?: string, callback?: () => void): void; + subscriptions(): string[]; + isSubscribed(channel?: string): boolean; +} + +export = SCServerSocket; diff --git a/types/socketcluster-server/socketcluster-server-tests.ts b/types/socketcluster-server/socketcluster-server-tests.ts new file mode 100644 index 0000000000..3d62fe9041 --- /dev/null +++ b/types/socketcluster-server/socketcluster-server-tests.ts @@ -0,0 +1,39 @@ +// Adapted from README + +// Using with basic http(s) module (example) + +import http = require("http"); +import * as socketClusterServer from "socketcluster-server"; + +let httpServer = http.createServer(); +let scServer = socketClusterServer.attach(httpServer); + +scServer.on("connection", socket => { + // ... Handle new socket connections here +}); + +httpServer.listen(8000); + +// Using with Express (example) + +import serveStatic = require("serve-static"); +import path = require("path"); +import express = require("express"); + +const app = express(); + +app.use(serveStatic(path.resolve(__dirname, "public"))); + +httpServer = http.createServer(); + +// Attach express to our httpServer +httpServer.on("request", app); + +// Attach socketcluster-server to our httpServer +scServer = socketClusterServer.attach(httpServer); + +scServer.on("connection", socket => { + // ... Handle new socket connections here +}); + +httpServer.listen(8000); diff --git a/types/socketcluster-server/tsconfig.json b/types/socketcluster-server/tsconfig.json new file mode 100644 index 0000000000..be1a6bdcb0 --- /dev/null +++ b/types/socketcluster-server/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": [ + "es6" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "scserver.d.ts", + "scserversocket.d.ts", + "socketcluster-server-tests.ts" + ] +} diff --git a/types/socketcluster-server/tslint.json b/types/socketcluster-server/tslint.json new file mode 100644 index 0000000000..f93cf8562a --- /dev/null +++ b/types/socketcluster-server/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": "dtslint/dt.json" +} diff --git a/types/socketcluster/fsutil.d.ts b/types/socketcluster/fsutil.d.ts new file mode 100644 index 0000000000..bcfcbfc59f --- /dev/null +++ b/types/socketcluster/fsutil.d.ts @@ -0,0 +1,11 @@ +import { PathLike } from "fs"; + +export function fileExists(filePath: PathLike, callback: (exists: boolean) => void): void; + +export function waitForFile( + filePath: PathLike, + checkInterval: number, + startTime: number, + maxWaitDuration: number, + timeoutErrorMessage?: string +): Promise; diff --git a/types/socketcluster/index.d.ts b/types/socketcluster/index.d.ts new file mode 100644 index 0000000000..0ec8485cfa --- /dev/null +++ b/types/socketcluster/index.d.ts @@ -0,0 +1,84 @@ +// Type definitions for socketcluster 14.0 +// Project: https://github.com/SocketCluster/socketcluster +// Definitions by: Daniel Rose +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.4 + +import { EventEmitter } from "events"; +import { SCServer } from "socketcluster-server"; +import { ChildProcess } from "child_process"; + +interface WorkerStartInfo { + id: number; + pid: number; + respawn: boolean; +} + +interface WorkerClusterStartInfo { + pid: number; + childProcess: ChildProcess; +} + +interface WorkerClusterReadyInfo { + pid: number; + childProcess: ChildProcess; +} + +interface WorkerClusterExitInfo { + pid: number; + code: number; + signal: string; + childProcess: ChildProcess; +} + +export = SocketCluster; + +declare class SocketCluster extends EventEmitter { + readonly EVENT_FAIL: "fail"; + readonly EVENT_WARNING: "warning"; + readonly EVENT_READY: "ready"; + readonly EVENT_WORKER_START: "workerStart"; + readonly EVENT_WORKER_EXIT: "workerExit"; + readonly EVENT_BROKER_START: "brokerStart"; + readonly EVENT_BROKER_EXIT: "brokerExit"; + readonly EVENT_WORKER_CLUSTER_START: "workerClusterStart"; + readonly EVENT_WORKER_CLUSTER_READY: "workerClusterReady"; + readonly EVENT_WORKER_CLUSTER_EXIT: "workerClusterExit"; + + options: SCServer.SCServerOptions; + + constructor(options?: SCServer.SCServerOptions); + + on(event: "fail", listener: (err: Error) => void): this; + on(event: "warning", listener: (warning: Error) => void): this; + on(event: "ready", listener: () => void): this; + on(event: "workerStart", listener: (workerInfo: WorkerStartInfo) => void): this; + on(event: "workerExit", listener: (workerInfo: SocketCluster.WorkerExitInfo) => void): this; + on(event: "brokerStart", listener: (brokerInfo: SocketCluster.BrokerStartInfo) => void): this; + on(event: "brokerExit", listener: (brokerInfo: SocketCluster.BrokerExitInfo) => void): this; + on(event: "workerClusterStart", listener: (workerClusterInfo: WorkerClusterStartInfo) => void): this; + on(event: "workerClusterReady", listener: (workerClusterInfo: WorkerClusterReadyInfo) => void): this; + on(event: "workerClusterExit", listener: (workerClusterInfo: WorkerClusterExitInfo) => void): this; +} + +declare namespace SocketCluster { + interface WorkerExitInfo { + id: number; + pid: number; + code: number; + signal: string; + } + + interface BrokerStartInfo { + id: number; + pid: number; + respawn: boolean; + } + + interface BrokerExitInfo { + id: number; + pid: number; + code: number; + signal: string; + } +} diff --git a/types/socketcluster/scbroker.d.ts b/types/socketcluster/scbroker.d.ts new file mode 100644 index 0000000000..461801aa63 --- /dev/null +++ b/types/socketcluster/scbroker.d.ts @@ -0,0 +1,3 @@ +import SCBroker = require("sc-broker-cluster/scbroker"); + +export = SCBroker; diff --git a/types/socketcluster/scworker.d.ts b/types/socketcluster/scworker.d.ts new file mode 100644 index 0000000000..48502692be --- /dev/null +++ b/types/socketcluster/scworker.d.ts @@ -0,0 +1,63 @@ +import { EventEmitter } from "events"; +import { Server as httpServer } from "http"; +import { Server as httpsServer } from "https"; +import { SCServer, SCServerSocket } from "socketcluster-server"; +import { SCAuthEngine } from "sc-auth"; +import { SCExchange } from "sc-broker-cluster"; + +export = SCWorker; + +type middlewareFunction = (options: SCServer.SCServerOptions, next: (error?: string | Error) => void) => void; + +declare class SCWorker extends EventEmitter { + readonly EVENT_ERROR: "error"; + readonly EVENT_WARNING: "warning"; + readonly EVENT_EXIT: "exit"; + readonly EVENT_READY: "ready"; + readonly EVENT_CONNECTION: "connection"; + + readonly MIDDLEWARE_START: "start"; + + id: number; + isLeader: boolean; + options: SCServer.SCServerOptions; + httpServer: httpServer | httpsServer; + scServer: SCServer; + exchange: SCExchange; + auth: SCAuthEngine; + + constructor(options?: SCServer.SCServerOptions); + + run(): void; + + getSCServer(): SCServer; + getHTTPServer(): httpServer | httpsServer; + getSocketPath(): string; + + setAuthEngine(authEngine: SCAuthEngine): void; + setCodecEngine(codecEngine: SCServer.SCCodecEngine): void; + + open(): void; + close(callback?: () => void): void; + + addMiddleware(type: "start", middlewareFn: middlewareFunction): void; + removeMiddleware(type: "start", middlewareFn: middlewareFunction): void; + + startHTTPServer(): void; + start(): Promise; + + getStatus(): { + clientCount: any; + httpRPM: number; + wsRPM: number; + }; + + sendToMaster(data: any, callback: (err: Error | null, data: any) => void): void; + respondToMaster(err: Error | null, data: any, rid: number): void; + + on(event: "connection", listener: (scSocket: SCServerSocket) => void): this; + on(event: "ready", listener: () => void): this; + on(event: "error", listener: (err: Error) => void): this; + on(event: "warning", listener: (warning: Error) => void): this; + on(event: "masterMessage", listener: (data: any, respond: (err: Error | null, responseData: any) => void) => void): this; +} diff --git a/types/socketcluster/socketcluster-tests.ts b/types/socketcluster/socketcluster-tests.ts new file mode 100644 index 0000000000..85ad9c3d05 --- /dev/null +++ b/types/socketcluster/socketcluster-tests.ts @@ -0,0 +1,76 @@ +import * as fsutil from "socketcluster/fsutil"; +import SocketCluster = require("socketcluster"); +import { SCServer } from "socketcluster-server"; +import { ChildProcess } from "child_process"; + +//////////////////////////////////////////////////// +/// SocketCluster tests +//////////////////////////////////////////////////// + +{ + const options: SCServer.SCServerOptions = { port: 80 }; + + let sc = new SocketCluster(); + sc = new SocketCluster(options); + sc.options = { environment: "prod" }; + + sc.on(sc.EVENT_FAIL, err => { + const error: Error = err; + }); + sc.on(sc.EVENT_WARNING, warning => { + const warn: Error = warning; + }); + + sc.on(sc.EVENT_READY, () => {}); + + sc.on(sc.EVENT_WORKER_START, workerInfo => { + const id: number = workerInfo.id; + const pid: number = workerInfo.pid; + const respawn: boolean = workerInfo.respawn; + }); + sc.on(sc.EVENT_WORKER_EXIT, workerInfo => { + const id: number = workerInfo.id; + const pid: number = workerInfo.pid; + const code: number = workerInfo.code; + const signal: string = workerInfo.signal; + }); + + sc.on(sc.EVENT_BROKER_START, brokerInfo => { + const id: number = brokerInfo.id; + const pid: number = brokerInfo.pid; + const respawn: boolean = brokerInfo.respawn; + }); + sc.on(sc.EVENT_BROKER_EXIT, brokerInfo => { + const id: number = brokerInfo.id; + const pid: number = brokerInfo.pid; + const code: number = brokerInfo.code; + const signal: string = brokerInfo.signal; + }); + + sc.on(sc.EVENT_WORKER_CLUSTER_START, workerClusterInfo => { + const pid: number = workerClusterInfo.pid; + const childProcess: ChildProcess = workerClusterInfo.childProcess; + }); + sc.on(sc.EVENT_WORKER_CLUSTER_READY, workerClusterInfo => { + const pid: number = workerClusterInfo.pid; + const childProcess: ChildProcess = workerClusterInfo.childProcess; + }); + sc.on(sc.EVENT_WORKER_CLUSTER_EXIT, workerClusterInfo => { + const pid: number = workerClusterInfo.pid; + const code: number = workerClusterInfo.code; + const signal: string = workerClusterInfo.signal; + const childProcess: ChildProcess = workerClusterInfo.childProcess; + }); +} + +//////////////////////////////////////////////////// +/// fsutil tests +//////////////////////////////////////////////////// + +{ + fsutil.fileExists("/path/to/folder", err => {}); + fsutil.fileExists(Buffer.from(""), err => {}); + + const pathPromise: Promise = fsutil.waitForFile("/path/to/folder", 100, 0, 100); + const bufferPromise: Promise = fsutil.waitForFile(Buffer.from(""), 0, 0, 0, "timeout"); +} diff --git a/types/socketcluster/tsconfig.json b/types/socketcluster/tsconfig.json new file mode 100644 index 0000000000..1a0267f5f0 --- /dev/null +++ b/types/socketcluster/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": [ + "es6" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "fsutil.d.ts", + "scbroker.d.ts", + "scworker.d.ts", + "socketcluster-tests.ts" + ] +} diff --git a/types/socketcluster/tslint.json b/types/socketcluster/tslint.json new file mode 100644 index 0000000000..f93cf8562a --- /dev/null +++ b/types/socketcluster/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": "dtslint/dt.json" +}