Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

serum-vial

Package Overview
Dependencies
Maintainers
1
Versions
99
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

serum-vial - npm Package Compare versions

Comparing version 0.6.2 to 0.7.0

1

dist/boot_server.d.ts
import { SerumMarket } from './types';
export declare function bootServer({ port, nodeEndpoint, validateL3Diffs, minionsCount, markets, commitment }: BootOptions): Promise<void>;
export declare function stopServer(): Promise<void>;
declare type BootOptions = {

@@ -4,0 +5,0 @@ port: number;

@@ -6,3 +6,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.bootServer = void 0;
exports.stopServer = exports.bootServer = void 0;
const os_1 = __importDefault(require("os"));

@@ -70,2 +70,7 @@ const path_1 = __importDefault(require("path"));

exports.bootServer = bootServer;
async function stopServer() {
helpers_1.cleanupChannel.postMessage('cleanup');
await helpers_1.wait(10 * 1000);
}
exports.stopServer = stopServer;
//# sourceMappingURL=boot_server.js.map

6

dist/consts.d.ts
export declare const OPS: readonly ["subscribe", "unsubscribe"];
export declare const CHANNELS: readonly ["level3", "level2", "level1", "trades"];
declare const TRADES_MESSAGE_TYPES: readonly ["trade"];
declare const LEVEL1_MESSAGE_TYPES: readonly ["quote", "trade"];
declare const LEVEL2_MESSAGE_TYPES: readonly ["l2snapshot", "l2update", "trade"];
declare const TRADES_MESSAGE_TYPES: readonly ["recent_trades", "trade"];
declare const LEVEL1_MESSAGE_TYPES: readonly ["recent_trades", "trade", "quote"];
declare const LEVEL2_MESSAGE_TYPES: readonly ["l2snapshot", "l2update", "recent_trades", "trade"];
declare const LEVEL3_MESSAGE_TYPES: readonly ["l3snapshot", "open", "fill", "change", "done"];

@@ -7,0 +7,0 @@ export declare const MESSAGE_TYPES_PER_CHANNEL: {

@@ -6,5 +6,5 @@ "use strict";

exports.CHANNELS = ['level3', 'level2', 'level1', 'trades'];
const TRADES_MESSAGE_TYPES = ['trade'];
const LEVEL1_MESSAGE_TYPES = ['quote', 'trade'];
const LEVEL2_MESSAGE_TYPES = ['l2snapshot', 'l2update', 'trade'];
const TRADES_MESSAGE_TYPES = ['recent_trades', 'trade'];
const LEVEL1_MESSAGE_TYPES = ['recent_trades', 'trade', 'quote'];
const LEVEL2_MESSAGE_TYPES = ['l2snapshot', 'l2update', 'recent_trades', 'trade'];
const LEVEL3_MESSAGE_TYPES = ['l3snapshot', 'open', 'fill', 'change', 'done'];

@@ -11,0 +11,0 @@ exports.MESSAGE_TYPES_PER_CHANNEL = {

@@ -18,2 +18,3 @@ import { Market } from '@project-serum/serum';

private _zeroWithPrecision;
private readonly _recentTrades;
constructor(_options: {

@@ -20,0 +21,0 @@ readonly symbol: string;

@@ -5,2 +5,3 @@ "use strict";

const serum_1 = require("@project-serum/serum");
const helpers_1 = require("./helpers");
const logger_1 = require("./logger");

@@ -22,2 +23,3 @@ // DataMapper maps bids, asks and evenQueue accounts data to normalized messages

this._currentQuote = undefined;
this._recentTrades = new helpers_1.CircularBuffer(100);
this._mapToL2Level = (level) => {

@@ -191,2 +193,10 @@ const price = this._options.market.priceLotsToNumber(level[0]).toFixed(this._options.priceDecimalPlaces);

yield this._putInEnvelope(tradeMessage, true);
this._recentTrades.append(tradeMessage);
const recentTradesMessage = {
type: 'recent_trades',
symbol: this._options.symbol,
timestamp,
trades: [...this._recentTrades.items()]
};
yield this._putInEnvelope(recentTradesMessage, false);
}

@@ -193,0 +203,0 @@ }

@@ -13,3 +13,3 @@ import { SerumMarket } from './types';

append(value: T): T | undefined;
items(): Generator<T | undefined, void, unknown>;
items(): Generator<NonNullable<T>, void, unknown>;
get count(): number;

@@ -22,2 +22,3 @@ clear(): void;

export declare const serumMarketsChannel: BroadcastChannel;
export declare const cleanupChannel: BroadcastChannel;
export declare function executeAndRetry<T>(operation: (attempt: number) => Promise<T>, { maxRetries }: {

@@ -24,0 +25,0 @@ maxRetries: number;

@@ -6,3 +6,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.getDefaultMarkets = exports.executeAndRetry = exports.serumMarketsChannel = exports.serumDataChannel = exports.serumProducerReadyChannel = exports.minionReadyChannel = exports.CircularBuffer = exports.decimalPlaces = exports.batch = exports.getAllowedValuesText = exports.getDidYouMean = exports.wait = void 0;
exports.getDefaultMarkets = exports.executeAndRetry = exports.cleanupChannel = exports.serumMarketsChannel = exports.serumDataChannel = exports.serumProducerReadyChannel = exports.minionReadyChannel = exports.CircularBuffer = exports.decimalPlaces = exports.batch = exports.getAllowedValuesText = exports.getDidYouMean = exports.wait = void 0;
const serum_1 = require("@project-serum/serum");

@@ -89,2 +89,3 @@ const didyoumean2_1 = __importDefault(require("didyoumean2"));

exports.serumMarketsChannel = new BroadcastChannel('SerumMarkets');
exports.cleanupChannel = new BroadcastChannel('Cleanup');
async function executeAndRetry(operation, { maxRetries }) {

@@ -91,0 +92,0 @@ let attempts = 0;

@@ -1,2 +0,2 @@

export { bootServer } from './boot_server';
export { bootServer, stopServer } from './boot_server';
export { logger } from './logger';

@@ -3,0 +3,0 @@ export { getDefaultMarkets } from './helpers';

@@ -13,5 +13,6 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.getDefaultMarkets = exports.logger = exports.bootServer = void 0;
exports.getDefaultMarkets = exports.logger = exports.stopServer = exports.bootServer = void 0;
var boot_server_1 = require("./boot_server");
Object.defineProperty(exports, "bootServer", { enumerable: true, get: function () { return boot_server_1.bootServer; } });
Object.defineProperty(exports, "stopServer", { enumerable: true, get: function () { return boot_server_1.stopServer; } });
var logger_1 = require("./logger");

@@ -18,0 +19,0 @@ Object.defineProperty(exports, "logger", { enumerable: true, get: function () { return logger_1.logger; } });

@@ -52,28 +52,5 @@ "use strict";

this._l3SnapshotsSerialized = {};
this._recentTrades = {};
this._recentTradesSerialized = {};
this._quotesSerialized = {};
this._listRecentTrades = async (res, req) => {
res.onAborted(() => {
res.aborted = true;
});
const marketName = decodeURIComponent(req.getParameter(0));
const { isValid, error } = this._validateMarketName(marketName);
if (isValid === false) {
res.writeHeader('content-type', 'application/json');
res.writeStatus('400');
res.end(JSON.stringify({ error }));
return;
}
let serializedRecentTrades = this._recentTradesSerialized[marketName];
if (serializedRecentTrades === undefined) {
const recentTrades = this._recentTrades[marketName] !== undefined ? [...this._recentTrades[marketName].items()] : [];
recentTrades.reverse();
serializedRecentTrades = `[${recentTrades.join(',')}]`;
}
if (!res.aborted) {
res.writeHeader('content-type', 'application/json');
res.end(serializedRecentTrades);
}
};
this._listenSocket = undefined;
this._cachedListMarketsResponse = undefined;

@@ -136,4 +113,3 @@ //async based on https://github.com/uNetworking/uWebSockets.js/blob/master/examples/AsyncFunction.js

})
.get(`${apiPrefix}/markets`, this._listMarkets)
.get(`${apiPrefix}/recent-trades/:market`, this._listRecentTrades);
.get(`${apiPrefix}/markets`, this._listMarkets);
}

@@ -144,2 +120,3 @@ async start(port) {

if (socket) {
this._listenSocket = socket;
logger_1.logger.log('info', `Listening on port ${port}`, meta);

@@ -156,2 +133,7 @@ resolve();

}
async stop() {
if (this._listenSocket !== undefined) {
uWebSockets_js_1.us_listen_socket_close(this._listenSocket);
}
}
initMarketsCache(cachedResponse) {

@@ -176,9 +158,2 @@ this._cachedListMarketsResponse = cachedResponse;

}
if (message.type === 'trade') {
if (this._recentTrades[message.symbol] === undefined) {
this._recentTrades[message.symbol] = new helpers_1.CircularBuffer(100);
}
this._recentTrades[message.symbol].append(message.payload);
this._recentTradesSerialized[message.symbol] = undefined;
}
if (message.publish) {

@@ -231,2 +206,17 @@ this._server.publish(topic, message.payload);

ws.subscribe(topic);
if (type === 'recent_trades') {
const recentTrades = this._recentTradesSerialized[market];
if (recentTrades !== undefined) {
ws.send(recentTrades);
}
else {
const emptyRecentTradesMessage = {
type: 'recent_trades',
symbol: market,
timestamp: new Date().toISOString(),
trades: []
};
ws.send(JSON.stringify(emptyRecentTradesMessage));
}
}
if (type === 'quote') {

@@ -270,14 +260,2 @@ const quote = this._quotesSerialized[market];

}
_validateMarketName(marketName) {
if (this._marketNames.includes(marketName) === false) {
const error = `Invalid market name provided: '${marketName}'.${helpers_1.getDidYouMean(marketName, this._marketNames)} ${helpers_1.getAllowedValuesText(this._marketNames)}`;
return {
isValid: false,
error
};
}
return {
isValid: true
};
}
_validateRequestPayload(message) {

@@ -344,2 +322,5 @@ let payload;

});
helpers_1.cleanupChannel.onmessage = async () => {
await minion.stop();
};
//# sourceMappingURL=minion.js.map

@@ -16,2 +16,7 @@ import { Op, Channel, MessageType } from './consts';

}
export interface RecentTrades extends Message {
readonly type: 'recent_trades';
readonly symbol: string;
readonly trades: Trade[];
}
export interface DataMessage extends Message {

@@ -18,0 +23,0 @@ readonly symbol: string;

{
"name": "serum-vial",
"version": "0.6.2",
"version": "0.7.0",
"engines": {

@@ -16,3 +16,3 @@ "node": ">=15"

"precommit": "lint-staged",
"test": "jest --runInBand --forceExit",
"test": "npm run build && jest --forceExit",
"prepare": "npm run build",

@@ -19,0 +19,0 @@ "start:debug": "npm run build && node ./bin/serum-vial.js --log-level=debug",

import os from 'os'
import path from 'path'
import { Worker } from 'worker_threads'
import { minionReadyChannel, serumProducerReadyChannel, wait } from './helpers'
import { cleanupChannel, minionReadyChannel, serumProducerReadyChannel, wait } from './helpers'
import { logger } from './logger'

@@ -93,2 +93,8 @@ import { SerumMarket } from './types'

export async function stopServer() {
cleanupChannel.postMessage('cleanup')
await wait(10 * 1000)
}
type BootOptions = {

@@ -95,0 +101,0 @@ port: number

export const OPS = ['subscribe', 'unsubscribe'] as const
export const CHANNELS = ['level3', 'level2', 'level1', 'trades'] as const
const TRADES_MESSAGE_TYPES = ['trade'] as const
const LEVEL1_MESSAGE_TYPES = ['quote', 'trade'] as const
const LEVEL2_MESSAGE_TYPES = ['l2snapshot', 'l2update', 'trade'] as const
const TRADES_MESSAGE_TYPES = ['recent_trades', 'trade'] as const
const LEVEL1_MESSAGE_TYPES = ['recent_trades', 'trade', 'quote'] as const
const LEVEL2_MESSAGE_TYPES = ['l2snapshot', 'l2update', 'recent_trades', 'trade'] as const
const LEVEL3_MESSAGE_TYPES = ['l3snapshot', 'open', 'fill', 'change', 'done'] as const

@@ -8,0 +8,0 @@

@@ -5,2 +5,3 @@ import { EVENT_QUEUE_LAYOUT, Market, Orderbook, getLayoutVersion } from '@project-serum/serum'

import BN from 'bn.js'
import { CircularBuffer } from './helpers'
import { logger } from './logger'

@@ -21,2 +22,3 @@ import { AccountsNotificationPayload } from './rpc_client'

Quote,
RecentTrades,
Trade

@@ -57,2 +59,4 @@ } from './types'

private readonly _recentTrades: CircularBuffer<Trade> = new CircularBuffer(100)
constructor(

@@ -250,2 +254,13 @@ private readonly _options: {

yield this._putInEnvelope(tradeMessage, true)
this._recentTrades.append(tradeMessage)
const recentTradesMessage: RecentTrades = {
type: 'recent_trades',
symbol: this._options.symbol,
timestamp,
trades: [...this._recentTrades.items()]
}
yield this._putInEnvelope(recentTradesMessage, false)
}

@@ -532,3 +547,3 @@ }

private _putInEnvelope(message: DataMessage, publish: boolean) {
private _putInEnvelope(message: DataMessage | RecentTrades, publish: boolean) {
const envelope: MessageEnvelope = {

@@ -535,0 +550,0 @@ type: message.type,

@@ -73,3 +73,3 @@ import { MARKETS } from '@project-serum/serum'

const index = (this._index + i) % this._buffer.length
yield this._buffer[index]
yield this._buffer[index]!
}

@@ -94,2 +94,3 @@ }

export const serumMarketsChannel = new BroadcastChannel('SerumMarkets') as BroadcastChannel
export const cleanupChannel = new BroadcastChannel('Cleanup') as BroadcastChannel

@@ -96,0 +97,0 @@ export async function executeAndRetry<T>(

@@ -1,4 +0,4 @@

export { bootServer } from './boot_server'
export { bootServer, stopServer } from './boot_server'
export { logger } from './logger'
export { getDefaultMarkets } from './helpers'
export * from './types'
import { Market, getLayoutVersion } from '@project-serum/serum'
import { Connection, PublicKey } from '@solana/web3.js'
import { App, SSLApp, HttpRequest, HttpResponse, SHARED_COMPRESSOR, TemplatedApp, WebSocket } from 'uWebSockets.js'
import {
App,
SSLApp,
HttpResponse,
SHARED_COMPRESSOR,
TemplatedApp,
WebSocket,
us_listen_socket_close
} from 'uWebSockets.js'
import { isMainThread, threadId, workerData } from 'worker_threads'
import { CHANNELS, MESSAGE_TYPES_PER_CHANNEL, OPS } from './consts'
import {
CircularBuffer,
cleanupChannel,
getAllowedValuesText,

@@ -16,3 +24,3 @@ getDidYouMean,

import { MessageEnvelope } from './serum_producer'
import { ErrorResponse, SerumListMarketItem, SerumMarket, SubRequest, SuccessResponse } from './types'
import { ErrorResponse, RecentTrades, SerumListMarketItem, SerumMarket, SubRequest, SuccessResponse } from './types'

@@ -68,6 +76,6 @@ const meta = {

private readonly _l3SnapshotsSerialized: { [symbol: string]: string } = {}
private readonly _recentTrades: { [symbol: string]: CircularBuffer<string> } = {}
private readonly _recentTradesSerialized: { [symbol: string]: string | undefined } = {}
private readonly _recentTradesSerialized: { [symbol: string]: string } = {}
private readonly _quotesSerialized: { [symbol: string]: string } = {}
private readonly _marketNames: string[]
private _listenSocket: any | undefined = undefined

@@ -101,3 +109,2 @@ constructor(private readonly _nodeEndpoint: string, private readonly _markets: SerumMarket[]) {

.get(`${apiPrefix}/markets`, this._listMarkets)
.get(`${apiPrefix}/recent-trades/:market`, this._listRecentTrades)
}

@@ -109,2 +116,3 @@

if (socket) {
this._listenSocket = socket
logger.log('info', `Listening on port ${port}`, meta)

@@ -121,31 +129,6 @@ resolve()

private _listRecentTrades = async (res: HttpResponse, req: HttpRequest) => {
res.onAborted(() => {
res.aborted = true
})
const marketName = decodeURIComponent(req.getParameter(0))
const { isValid, error } = this._validateMarketName(marketName)
if (isValid === false) {
res.writeHeader('content-type', 'application/json')
res.writeStatus('400')
res.end(JSON.stringify({ error }))
return
public async stop() {
if (this._listenSocket !== undefined) {
us_listen_socket_close(this._listenSocket)
}
let serializedRecentTrades = this._recentTradesSerialized[marketName]
if (serializedRecentTrades === undefined) {
const recentTrades =
this._recentTrades[marketName] !== undefined ? [...this._recentTrades[marketName]!.items()] : []
recentTrades.reverse()
serializedRecentTrades = `[${recentTrades.join(',')}]`
}
if (!res.aborted) {
res.writeHeader('content-type', 'application/json')
res.end(serializedRecentTrades)
}
}

@@ -223,11 +206,2 @@

if (message.type === 'trade') {
if (this._recentTrades[message.symbol] === undefined) {
this._recentTrades[message.symbol] = new CircularBuffer(100)
}
this._recentTrades[message.symbol]!.append(message.payload)
this._recentTradesSerialized[message.symbol] = undefined
}
if (message.publish) {

@@ -294,2 +268,18 @@ this._server.publish(topic, message.payload)

if (type === 'recent_trades') {
const recentTrades = this._recentTradesSerialized[market]
if (recentTrades !== undefined) {
ws.send(recentTrades)
} else {
const emptyRecentTradesMessage: RecentTrades = {
type: 'recent_trades',
symbol: market,
timestamp: new Date().toISOString(),
trades: []
}
ws.send(JSON.stringify(emptyRecentTradesMessage))
}
}
if (type === 'quote') {

@@ -337,20 +327,2 @@ const quote = this._quotesSerialized[market]

private _validateMarketName(marketName: string) {
if (this._marketNames.includes(marketName) === false) {
const error = `Invalid market name provided: '${marketName}'.${getDidYouMean(
marketName,
this._marketNames
)} ${getAllowedValuesText(this._marketNames)}`
return {
isValid: false,
error
}
}
return {
isValid: true
}
}
private _validateRequestPayload(message: Buffer) {

@@ -433,1 +405,5 @@ let payload

})
cleanupChannel.onmessage = async () => {
await minion.stop()
}

@@ -20,2 +20,8 @@ import { Op, Channel, MessageType } from './consts'

export interface RecentTrades extends Message {
readonly type: 'recent_trades'
readonly symbol: string
readonly trades: Trade[]
}
export interface DataMessage extends Message {

@@ -22,0 +28,0 @@ readonly symbol: string

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc