@stryke-xyz/premarket-sdk 1.2.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/cjs/config/index.js +3 -3
  2. package/dist/cjs/package.json +1 -1
  3. package/dist/cjs/sync/clients/activity-client.js +325 -454
  4. package/dist/cjs/sync/clients/order-client.js +609 -429
  5. package/dist/esm/config/index.js +3 -3
  6. package/dist/esm/package.json +1 -1
  7. package/dist/esm/sync/clients/activity-client.js +325 -454
  8. package/dist/esm/sync/clients/order-client.js +609 -429
  9. package/dist/types/sync/clients/activity-client.d.ts +39 -32
  10. package/dist/types/sync/clients/order-client.d.ts +79 -58
  11. package/dist/types/sync/index.d.ts +2 -2
  12. package/package.json +58 -58
  13. package/dist/cjs/api/README.md +0 -296
  14. package/dist/cjs/config/README.md +0 -112
  15. package/dist/cjs/exchange/README.md +0 -280
  16. package/dist/cjs/registry/README.md +0 -150
  17. package/dist/cjs/shared/README.md +0 -235
  18. package/dist/cjs/shared/utils.js +0 -1
  19. package/dist/cjs/sync/README.md +0 -215
  20. package/dist/cjs/sync/clients/base-client.js +0 -518
  21. package/dist/cjs/sync/redis-ws-client.js +0 -235
  22. package/dist/cjs/utils/README.md +0 -89
  23. package/dist/cjs/vault/README.md +0 -268
  24. package/dist/esm/api/README.md +0 -296
  25. package/dist/esm/config/README.md +0 -112
  26. package/dist/esm/exchange/README.md +0 -280
  27. package/dist/esm/registry/README.md +0 -150
  28. package/dist/esm/shared/README.md +0 -235
  29. package/dist/esm/shared/utils.js +0 -0
  30. package/dist/esm/sync/README.md +0 -215
  31. package/dist/esm/sync/clients/base-client.js +0 -508
  32. package/dist/esm/sync/redis-ws-client.js +0 -225
  33. package/dist/esm/utils/README.md +0 -89
  34. package/dist/esm/vault/README.md +0 -268
  35. package/dist/types/shared/utils.d.ts +0 -0
  36. package/dist/types/sync/clients/base-client.d.ts +0 -56
  37. package/dist/types/sync/redis-ws-client.d.ts +0 -21
@@ -24,63 +24,70 @@ export interface OrderFillEvent {
24
24
  /** Blockchain timestamp (seconds since epoch, null for user channel) */
25
25
  timestamp: string | null;
26
26
  }
27
+ export interface OrderUpdateEvent {
28
+ type: "fill" | "order_update";
29
+ orderHash: string;
30
+ marketId?: string;
31
+ tokenId?: string;
32
+ status?: string;
33
+ remainingAmount?: string;
34
+ [extra: string]: unknown;
35
+ }
27
36
  export interface ActivityClientConfig {
28
37
  wsUrl: string;
29
- /** Subscribe to fills for this market (orders_matched:marketId) */
30
- marketId?: string;
31
- /** Subscribe to fills for this user address (user_info:address) */
32
- userAddress?: string;
33
38
  heartbeatIntervalMs?: number;
34
39
  heartbeatTimeoutMs?: number;
35
- maxReconnectAttempts?: number;
36
- initialReconnectDelayMs?: number;
37
40
  maxReconnectDelayMs?: number;
41
+ initialReconnectDelayMs?: number;
38
42
  }
43
+ type FillCallback = (event: OrderFillEvent) => void;
44
+ type OrderUpdateCallback = (event: OrderUpdateEvent) => void;
39
45
  /**
40
- * Client for activity streams: order fills per market (orders_matched) and per user (user_info).
41
- * Connects to the same worker as MarketDepthSyncClient; use WORKER_MODES that include "activity".
46
+ * Multi-market, multi-user activity sync client.
42
47
  *
43
- * No ordering or gap handling — we accept every order_fill message as it arrives.
48
+ * One WebSocket handles all subscriptions. Use:
49
+ * - subscribeMarket(marketId) / unsubscribeMarket(marketId) for fill streams
50
+ * - subscribeUser(address) / unsubscribeUser(address) for user order updates
51
+ *
52
+ * All subscriptions are re-sent automatically on reconnect.
44
53
  */
45
54
  export declare class ActivitySyncClient {
46
55
  private ws;
47
56
  private config;
48
57
  private status;
49
- private fillListeners;
50
- private userFillListeners;
51
- private marketFillListeners;
52
- private statusListeners;
53
58
  private shouldBeConnected;
54
59
  private reconnectAttempts;
55
60
  private reconnectTimeoutId;
56
61
  private heartbeatIntervalId;
57
62
  private heartbeatTimeoutId;
58
- private lastPongTime;
59
- private visibilityChangeHandler;
63
+ /** Active market subscriptions: marketId → Set of callbacks */
64
+ private marketListeners;
65
+ /** Active user subscriptions: address → Set of callbacks */
66
+ private userListeners;
67
+ /** Generic fill listeners (all markets) */
68
+ private fillListeners;
69
+ /** Status listeners */
70
+ private statusListeners;
60
71
  constructor(config: ActivityClientConfig);
61
- /** Connects to the activity websocket and subscribes to market and/or user channels. */
62
72
  connect(): Promise<void>;
73
+ disconnect(): void;
74
+ getStatus(): SyncStatus;
75
+ isSynced(): boolean;
76
+ subscribeMarket(marketId: string, callback: FillCallback): () => void;
77
+ subscribeUser(address: string, callback: OrderUpdateCallback): () => void;
78
+ /** Fires for every fill event regardless of market or user channel. */
79
+ onFill(callback: FillCallback): () => void;
80
+ onStatus(callback: (s: SyncStatus) => void): () => void;
81
+ private send;
82
+ private resubscribeAll;
83
+ private handleMessage;
84
+ private normalizeFill;
63
85
  private startHeartbeat;
64
86
  private stopHeartbeat;
65
87
  private clearHeartbeatTimeout;
66
88
  private clearReconnectTimeout;
67
- private setupVisibilityChangeHandler;
68
- private removeVisibilityChangeHandler;
69
- private checkConnectionHealth;
70
89
  private handleConnectionLost;
71
90
  private scheduleReconnect;
72
91
  private setStatus;
73
- getStatus(): SyncStatus;
74
- /** Returns true once the websocket has an active subscription. */
75
- isSynced(): boolean;
76
- /** Registers a listener for connection lifecycle updates. */
77
- onStatus(callback: (status: SyncStatus) => void): () => void;
78
- /** Subscribes to all normalized fill events regardless of source channel. */
79
- onOrderFill(callback: (event: OrderFillEvent) => void): () => void;
80
- /** Subscribe to fills from user_info channel only (user's orders being filled) */
81
- onUserFill(callback: (event: OrderFillEvent) => void): () => void;
82
- /** Subscribe to fills from orders_matched channel only (market activity) */
83
- onMarketFill(callback: (event: OrderFillEvent) => void): () => void;
84
- /** Closes the websocket, unsubscribes active channels, and stops reconnects. */
85
- disconnect(): Promise<void>;
86
92
  }
93
+ export {};
@@ -3,6 +3,11 @@ export interface DepthLevel {
3
3
  price: string;
4
4
  depth: string;
5
5
  }
6
+ /** A market + its token IDs to subscribe to. */
7
+ export interface MarketSpec {
8
+ marketId: string;
9
+ tokenIds: string[];
10
+ }
6
11
  /** Current depth state for a token within a market subscription. */
7
12
  export interface TokenDepthSnapshot {
8
13
  tokenId: string;
@@ -32,11 +37,17 @@ export interface DepthUpdate {
32
37
  startSeq: number;
33
38
  endSeq: number;
34
39
  }
35
- /** Configuration for the market depth websocket client. */
40
+ /**
41
+ * Configuration for the market depth websocket client.
42
+ *
43
+ * Supports multiple markets over a single WebSocket connection.
44
+ * Markets can be added/removed dynamically via subscribeMarket / unsubscribeMarket
45
+ * without closing the connection.
46
+ */
36
47
  export interface MarketDepthClientConfig {
37
48
  wsUrl: string;
38
- marketId: string;
39
- tokenIds: string[];
49
+ /** Initial market subscriptions. More can be added later via subscribeMarket(). */
50
+ markets?: MarketSpec[];
40
51
  /** Heartbeat interval in ms (default: 30000) */
41
52
  heartbeatIntervalMs?: number;
42
53
  /** Heartbeat timeout - if no pong received within this time, reconnect (default: 10000) */
@@ -48,25 +59,42 @@ export interface MarketDepthClientConfig {
48
59
  /** Max reconnect delay in ms (default: 30000) */
49
60
  maxReconnectDelayMs?: number;
50
61
  }
51
- interface TokenDepthState {
52
- bids: Map<string, string>;
53
- asks: Map<string, string>;
54
- bestBid: string | null;
55
- bestAsk: string | null;
56
- lastPrice: string | null;
57
- seq: number;
62
+ /** @deprecated Use MarketDepthClientConfig with markets[] instead of marketId+tokenIds. */
63
+ export interface LegacyMarketDepthClientConfig extends MarketDepthClientConfig {
64
+ marketId?: string;
65
+ tokenIds?: string[];
58
66
  }
59
67
  /**
60
- * Client for syncing orderbook depth data for multiple tokens in a market.
61
- * Seq is per market+token (gapless, monotonic). Each token tracks its own seq for dedup and gap detection.
68
+ * Client for syncing orderbook depth data for one or more markets over a
69
+ * single persistent WebSocket connection.
70
+ *
71
+ * Usage:
72
+ * const client = new MarketDepthSyncClient({ wsUrl: "wss://..." });
73
+ * await client.connect();
74
+ *
75
+ * // Subscribe to markets dynamically (e.g. when they scroll into view)
76
+ * client.subscribeMarket("5", ["0xabc..."]);
77
+ *
78
+ * // Unsubscribe without closing the connection (e.g. scrolled out of view)
79
+ * client.unsubscribeMarket("5");
80
+ *
81
+ * // Listen for updates
82
+ * const offDelta = client.onDelta((marketId, update) => { ... });
83
+ * const offSnap = client.onSnapshot((marketId, snapshots) => { ... });
84
+ *
85
+ * // Full disconnect (app teardown)
86
+ * await client.disconnect();
62
87
  */
63
88
  export declare class MarketDepthSyncClient {
64
89
  private ws;
65
90
  private config;
66
91
  private status;
67
92
  private tokenStates;
68
- private frameQueue;
69
- private isProcessing;
93
+ private activeSubscriptions;
94
+ private tokenToMarket;
95
+ private syncedMarkets;
96
+ private frameQueues;
97
+ private processingMarkets;
70
98
  private statusListeners;
71
99
  private snapshotListeners;
72
100
  private deltaListeners;
@@ -77,9 +105,44 @@ export declare class MarketDepthSyncClient {
77
105
  private heartbeatTimeoutId;
78
106
  private lastPongTime;
79
107
  private visibilityChangeHandler;
80
- constructor(config: MarketDepthClientConfig);
81
- /** Connects to the market depth websocket and hydrates token snapshots. */
108
+ constructor(config: LegacyMarketDepthClientConfig);
109
+ /** Open the WebSocket connection and subscribe to all configured markets. */
82
110
  connect(): Promise<void>;
111
+ /**
112
+ * Subscribe to a market's depth. If the WebSocket is already open, sends the
113
+ * `subscribe_market` message immediately. Otherwise, the subscription is queued
114
+ * and sent when the connection opens. Calling this for an already-subscribed
115
+ * market re-requests a fresh snapshot.
116
+ */
117
+ subscribeMarket(marketId: string, tokenIds: string[]): void;
118
+ /**
119
+ * Unsubscribe from a market. Sends `unsubscribe_market` to the server and
120
+ * clears local state for that market's tokens. The WebSocket connection is
121
+ * kept open for other subscriptions.
122
+ */
123
+ unsubscribeMarket(marketId: string): void;
124
+ /** Fully disconnect and stop reconnecting. */
125
+ disconnect(): Promise<void>;
126
+ getStatus(): SyncStatus;
127
+ isSynced(): boolean;
128
+ isMarketSynced(marketId: string): boolean;
129
+ getBids(tokenId: string): DepthLevel[];
130
+ getAsks(tokenId: string): DepthLevel[];
131
+ getBestBid(tokenId: string): string | null;
132
+ getBestAsk(tokenId: string): string | null;
133
+ getLastPrice(tokenId: string): string | null;
134
+ onSnapshot(listener: (marketId: string, snapshots: TokenDepthSnapshot[]) => void): () => void;
135
+ onDelta(listener: (marketId: string, update: DepthUpdate) => void): () => void;
136
+ onStatus(listener: (status: SyncStatus) => void): () => void;
137
+ private _sendSubscribeMarket;
138
+ private handleSubscribedMarket;
139
+ private handleDepthUpdate;
140
+ private handleMarketStateUpdate;
141
+ private handleLastPriceUpdate;
142
+ private emitOutOfBandUpdate;
143
+ private processFrameQueue;
144
+ private applyLevel;
145
+ private setStatus;
83
146
  private setupVisibilityChangeHandler;
84
147
  private removeVisibilityChangeHandler;
85
148
  private checkConnectionHealth;
@@ -90,46 +153,4 @@ export declare class MarketDepthSyncClient {
90
153
  private scheduleReconnect;
91
154
  private clearReconnectTimeout;
92
155
  private performReconnect;
93
- private handleSubscribedMarket;
94
- private handleDepthUpdate;
95
- private handleMarketStateUpdate;
96
- private handleLastPriceUpdate;
97
- /** Emit a delta with empty levels for events that mutate side-state but no levels (market_state, last_price). */
98
- private emitOutOfBandUpdate;
99
- private processFrameQueue;
100
- private applyLevel;
101
- private setStatus;
102
- /** Returns the current connection lifecycle state. */
103
- getStatus(): SyncStatus;
104
- /** Returns true once initial depth snapshots have been received. */
105
- isSynced(): boolean;
106
- /** Returns all token ids currently tracked by the client. */
107
- getTokenIds(): string[];
108
- /** Returns raw internal token state for advanced integrations. */
109
- getTokenState(tokenId: string): TokenDepthState | undefined;
110
- /** Returns the current bid ladder for a token, sorted from highest to lowest price. */
111
- getBids(tokenId: string): DepthLevel[];
112
- /** Returns the current ask ladder for a token, sorted from lowest to highest price. */
113
- getAsks(tokenId: string): DepthLevel[];
114
- /** Returns the best bid price for a token, if known. */
115
- getBestBid(tokenId: string): string | null;
116
- /** Returns the best ask price for a token, if known. */
117
- getBestAsk(tokenId: string): string | null;
118
- /** Returns the latest trade price tracked for a token, if any. */
119
- getLastPrice(tokenId: string): string | null;
120
- /** Returns the latest applied sequence id for a token. */
121
- getSeq(tokenId: string): number;
122
- /** Returns the current bid-ask spread for a token when both sides are available. */
123
- getSpread(tokenId: string): number | null;
124
- /** Returns the depth resting at one exact price level on a given side. */
125
- getDepthAtPrice(tokenId: string, side: "bid" | "ask", price: string): string | null;
126
- /** Registers a listener for connection lifecycle updates. */
127
- onStatus(callback: (status: SyncStatus) => void): () => void;
128
- /** Registers a listener that receives full snapshots for all subscribed tokens. */
129
- onSnapshot(callback: (snapshots: TokenDepthSnapshot[]) => void): () => void;
130
- /** Registers a listener for normalized incremental depth updates. */
131
- onDelta(callback: (marketId: string, update: DepthUpdate) => void): () => void;
132
- /** Closes the websocket and stops automatic reconnection attempts. */
133
- disconnect(): Promise<void>;
134
156
  }
135
- export {};
@@ -1,5 +1,5 @@
1
1
  export { MarketDepthSyncClient } from "./clients/order-client.js";
2
2
  export { ActivitySyncClient } from "./clients/activity-client.js";
3
- export type { DepthLevel, TokenDepthSnapshot, DepthLevelUpdate, DepthUpdate, MarketDepthClientConfig, } from "./clients/order-client.js";
4
- export type { OrderFillEvent, ActivityClientConfig, } from "./clients/activity-client.js";
3
+ export type { DepthLevel, MarketSpec, TokenDepthSnapshot, DepthLevelUpdate, DepthUpdate, MarketDepthClientConfig, } from "./clients/order-client.js";
4
+ export type { OrderFillEvent, OrderUpdateEvent, ActivityClientConfig, } from "./clients/activity-client.js";
5
5
  export type { SyncStatus } from "./types.js";
package/package.json CHANGED
@@ -1,60 +1,60 @@
1
1
  {
2
- "name": "@stryke-xyz/premarket-sdk",
3
- "version": "1.2.1",
4
- "type": "module",
5
- "module": "dist/esm/index.js",
6
- "main": "dist/cjs/index.js",
7
- "types": "dist/types/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/types/index.d.ts",
11
- "import": "./dist/esm/index.js",
12
- "require": "./dist/cjs/index.js",
13
- "node": "./dist/cjs/index.js",
14
- "default": "./dist/esm/index.js"
15
- }
16
- },
17
- "files": [
18
- "dist"
19
- ],
20
- "scripts": {
21
- "build": "npm run build:esm && npm run build:cjs && npm run build:types",
22
- "build:esm": "swc --config-file esm.swcrc ./src -d dist/esm --strip-leading-paths --copy-files && find dist/esm -name '*.spec.*' -delete && node -e 'const pkg = require(\"./package.json\"); require(\"fs\").writeFileSync(\"dist/esm/package.json\", JSON.stringify({name: pkg.name, version: pkg.version, type: \"module\"}))'",
23
- "build:cjs": "swc --config-file cjs.swcrc ./src -d dist/cjs --strip-leading-paths --copy-files && find dist/cjs -name '*.spec.*' -delete && node -e 'const pkg = require(\"./package.json\"); require(\"fs\").writeFileSync(\"dist/cjs/package.json\", JSON.stringify({name: pkg.name, version: pkg.version, type: \"commonjs\"}))'",
24
- "build:types": "tsc --project tsconfig.types.json && find dist -name '*.tsbuildinfo' -delete",
25
- "test": "bun test src",
26
- "typecheck": "tsc --noEmit --project tsconfig.json",
27
- "test:e2e": "bun test test/e2e/index.test.ts",
28
- "fill-orderbook": "bun run scripts/fill-orderbook.ts"
29
- },
30
- "dependencies": {
31
- "viem": "^2.7.0"
32
- },
33
- "devDependencies": {
34
- "@swc/cli": "0.7.7",
35
- "@swc/core": "^1.13.3",
36
- "@swc/jest": "^0.2.39",
37
- "@types/jest": "^30.0.0",
38
- "@types/node": "^22.17.0",
39
- "@typescript-eslint/eslint-plugin": "~8.20.0",
40
- "@typescript-eslint/parser": "~8.20.0",
41
- "axios": "^1.12.0",
42
- "eslint": "^9.32.0",
43
- "eslint-config-prettier": "~10.1.8",
44
- "eslint-config-standard": "^17.1.0",
45
- "eslint-import-resolver-typescript": "3.7.0",
46
- "eslint-plugin-import": "~2.31.0",
47
- "eslint-plugin-n": "^17.21.3",
48
- "eslint-plugin-prettier": "^5.5.4",
49
- "eslint-plugin-promise": "^7.2.1",
50
- "eslint-plugin-unused-imports": "^4.1.4",
51
- "generate-changelog": "1.8.0",
52
- "jest": "^30.0.5",
53
- "prettier": "^3.6.2",
54
- "testcontainers": "^11.5.1",
55
- "tsdoc-markdown": "^1.4.1",
56
- "tslib": "2.8.1",
57
- "typescript": "5.8.3",
58
- "bun-types": "^1.0.0"
59
- }
2
+ "name": "@stryke-xyz/premarket-sdk",
3
+ "version": "1.2.2",
4
+ "type": "module",
5
+ "module": "dist/esm/index.js",
6
+ "main": "dist/cjs/index.js",
7
+ "types": "dist/types/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/types/index.d.ts",
11
+ "import": "./dist/esm/index.js",
12
+ "require": "./dist/cjs/index.js",
13
+ "node": "./dist/cjs/index.js",
14
+ "default": "./dist/esm/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "scripts": {
21
+ "build": "npm run build:esm && npm run build:cjs && npm run build:types",
22
+ "build:esm": "swc --config-file esm.swcrc ./src -d dist/esm --strip-leading-paths --copy-files && find dist/esm -name '*.spec.*' -delete && node -e 'const pkg = require(\"./package.json\"); require(\"fs\").writeFileSync(\"dist/esm/package.json\", JSON.stringify({name: pkg.name, version: pkg.version, type: \"module\"}))'",
23
+ "build:cjs": "swc --config-file cjs.swcrc ./src -d dist/cjs --strip-leading-paths --copy-files && find dist/cjs -name '*.spec.*' -delete && node -e 'const pkg = require(\"./package.json\"); require(\"fs\").writeFileSync(\"dist/cjs/package.json\", JSON.stringify({name: pkg.name, version: pkg.version, type: \"commonjs\"}))'",
24
+ "build:types": "tsc --project tsconfig.types.json && find dist -name '*.tsbuildinfo' -delete",
25
+ "test": "bun test src",
26
+ "typecheck": "tsc --noEmit --project tsconfig.json",
27
+ "test:e2e": "bun test test/e2e/index.test.ts",
28
+ "fill-orderbook": "bun run scripts/fill-orderbook.ts"
29
+ },
30
+ "dependencies": {
31
+ "viem": "^2.7.0"
32
+ },
33
+ "devDependencies": {
34
+ "@swc/cli": "0.7.7",
35
+ "@swc/core": "^1.13.3",
36
+ "@swc/jest": "^0.2.39",
37
+ "@types/jest": "^30.0.0",
38
+ "@types/node": "^22.17.0",
39
+ "@typescript-eslint/eslint-plugin": "~8.20.0",
40
+ "@typescript-eslint/parser": "~8.20.0",
41
+ "axios": "^1.12.0",
42
+ "eslint": "^9.32.0",
43
+ "eslint-config-prettier": "~10.1.8",
44
+ "eslint-config-standard": "^17.1.0",
45
+ "eslint-import-resolver-typescript": "3.7.0",
46
+ "eslint-plugin-import": "~2.31.0",
47
+ "eslint-plugin-n": "^17.21.3",
48
+ "eslint-plugin-prettier": "^5.5.4",
49
+ "eslint-plugin-promise": "^7.2.1",
50
+ "eslint-plugin-unused-imports": "^4.1.4",
51
+ "generate-changelog": "1.8.0",
52
+ "jest": "^30.0.5",
53
+ "prettier": "^3.6.2",
54
+ "testcontainers": "^11.5.1",
55
+ "tsdoc-markdown": "^1.4.1",
56
+ "tslib": "2.8.1",
57
+ "typescript": "5.8.3",
58
+ "bun-types": "^1.0.0"
59
+ }
60
60
  }