shoonya-sdk 1.3.3 → 1.5.0

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.
@@ -0,0 +1,70 @@
1
+ const { existsSync, readdirSync } = require("node:fs");
2
+ const { homedir } = require("node:os");
3
+ const { join } = require("node:path");
4
+
5
+ function resolveChromeExecutablePath() {
6
+ const envPath = process.env.PUPPETEER_EXECUTABLE_PATH;
7
+ if (envPath && existsSync(envPath)) {
8
+ return envPath;
9
+ }
10
+
11
+ const chromeCacheRoot = join(homedir(), ".cache", "puppeteer", "chrome");
12
+ if (!existsSync(chromeCacheRoot)) {
13
+ return undefined;
14
+ }
15
+
16
+ const builds = readdirSync(chromeCacheRoot).sort((a, b) =>
17
+ b.localeCompare(a, undefined, { numeric: true })
18
+ );
19
+
20
+ const executableCandidates = [
21
+ ["chrome-linux64", "chrome"],
22
+ [
23
+ "chrome-mac",
24
+ "Google Chrome for Testing.app",
25
+ "Contents",
26
+ "MacOS",
27
+ "Google Chrome for Testing",
28
+ ],
29
+ [
30
+ "chrome-mac-x64",
31
+ "Google Chrome for Testing.app",
32
+ "Contents",
33
+ "MacOS",
34
+ "Google Chrome for Testing",
35
+ ],
36
+ [
37
+ "chrome-mac-arm64",
38
+ "Google Chrome for Testing.app",
39
+ "Contents",
40
+ "MacOS",
41
+ "Google Chrome for Testing",
42
+ ],
43
+ ["chrome-win64", "chrome.exe"],
44
+ ["chrome-win32", "chrome.exe"],
45
+ ];
46
+
47
+ for (const build of builds) {
48
+ for (const candidate of executableCandidates) {
49
+ const executablePath = join(chromeCacheRoot, build, ...candidate);
50
+ if (existsSync(executablePath)) {
51
+ return executablePath;
52
+ }
53
+ }
54
+ }
55
+
56
+ return undefined;
57
+ }
58
+
59
+ /** @type {import('puppeteer').Configuration} */
60
+ module.exports = {
61
+ cacheDirectory: join(homedir(), ".cache", "puppeteer"),
62
+ defaultBrowser: "chrome",
63
+ executablePath: resolveChromeExecutablePath(),
64
+ chrome: {
65
+ skipDownload: true,
66
+ },
67
+ firefox: {
68
+ skipDownload: true,
69
+ },
70
+ };
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Shoonya SDK
2
2
 
3
- Wrapper around Shoonya API
3
+ Wrapper around Shoonya REST + WebSocket APIs.
4
4
 
5
5
  ## Installation
6
6
 
@@ -15,58 +15,111 @@ yarn add shoonya-sdk
15
15
  pnpm add shoonya-sdk
16
16
  ```
17
17
 
18
- ## Getting Started
18
+ ## Credentials
19
19
 
20
- ### Using both WebsocketClient and RestClient
20
+ Current auth flow uses Shoonya OAuth code exchange (`GenAcsTok`) under the hood.
21
+
22
+ `RestClient` / `WebsocketClient` credentials:
23
+
24
+ ```ts
25
+ {
26
+ userId: "FAxxxxx",
27
+ password: "your-login-password",
28
+ twoFa: "your-totp-seed",
29
+ apiKey: "your-secret-code", // from Shoonya API page
30
+ clientId?: "FAxxxxx_U", // optional, defaults to `${userId}_U`
31
+ accountId?: "FAxxxxx", // optional
32
+ vendorCode?: "FAxxxxx_U", // optional
33
+ imei?: "api" // optional
34
+ }
35
+ ```
36
+
37
+ ## Quick Start
21
38
 
22
39
  ```ts
23
40
  import { RestClient, WebsocketClient } from "shoonya-sdk";
24
41
 
42
+ const credentials = {
43
+ userId: process.env.SHOONYA_USER_ID!,
44
+ password: process.env.SHOONYA_USER_PASSWORD!,
45
+ twoFa: process.env.SHOONYA_TWO_FA!,
46
+ apiKey: process.env.SHOONYA_API_KEY!,
47
+ };
48
+
25
49
  const restClient = new RestClient(credentials, { logging: true });
26
- const wsClient = new WebsocketClient({ logging: true }); // No need to pass credential here
50
+ const wsClient = new WebsocketClient({ logging: true });
27
51
 
28
- const userDetail = await restClient.getUserDetails();
29
- console.log(`Logged in as ${userDetail.actid}`);
52
+ console.log(await restClient.getAccountLimits());
30
53
 
54
+ wsClient.on("open", () => console.log("socket opened"));
31
55
  wsClient.on("connected", () => {
32
- wsClient.subscribe("NSE|26009"); // Bank Nifty
33
- });
34
-
35
- wsClient.on("priceUpdate", (data) => {
36
- console.log(data);
56
+ console.log("ws connected");
57
+ wsClient.subscribe("NSE|26000", "Touchline");
37
58
  });
59
+ wsClient.on("subscribed", (token) => console.log("subscribed", token));
60
+ wsClient.on("priceUpdate", (data) => console.log("tick", data));
61
+ wsClient.on("error", (err) => console.error("ws error", err.message));
62
+ wsClient.on("close", () => console.log("ws closed"));
38
63
 
39
64
  wsClient.connect();
40
65
  ```
41
66
 
42
- ### Only using WebsocketClient
67
+ `RestClient` options:
43
68
 
44
69
  ```ts
45
- import { WebsocketClient } from "shoonya-sdk";
46
-
47
- const wsClient = new WebsocketClient({
48
- cred: {
49
- // now you need to pass the credentials here
50
- },
70
+ new RestClient(credentials, {
51
71
  logging: true,
72
+ // baseUrl: "https://api.shoonya.com/NorenWClientAPI/",
73
+ // Optional: set true only if your endpoint expects Bearer header.
74
+ sendBearerAuthHeader: false,
52
75
  });
76
+ ```
53
77
 
54
- wsClient.on("connected", () => {
55
- wsClient.subscribe(["NSE|26009", "NSE|26000"]); // Bank Nifty and Nifty 50
56
- });
78
+ ## WebSocket Behavior
57
79
 
58
- wsClient.on("priceUpdate", (data) => {
59
- console.log(data);
60
- });
80
+ - Primary profile: `wss://api.shoonya.com/NorenWSAPI/` with OAuth handshake (`t: "a"`, `accesstoken`)
81
+ - Connect acknowledgement supports both `ak` and `ck`
82
+ - Optional compatibility fallback to legacy WSTP is available
83
+ - Auto reconnect, token refresh, heartbeat, and resubscribe are built in
61
84
 
62
- wsClient.connect();
85
+ `WebsocketClient` options:
86
+
87
+ ```ts
88
+ new WebsocketClient({
89
+ logging: true,
90
+ reconnectInterval: 1000,
91
+ maxRetryAttempt: 3,
92
+ heartbeatInterval: 15000,
93
+ connectAckTimeoutMs: 12000,
94
+ postConnectAckDelayMs: 3000,
95
+ enableLegacyFallback: true,
96
+ enableOauthWstpFallback: false,
97
+ dailyRefreshTime: "09:13+05:30",
98
+ });
63
99
  ```
64
100
 
101
+ ## Environment Variables
102
+
103
+ - `SHOONYA_USER_ID`
104
+ - `SHOONYA_USER_PASSWORD`
105
+ - `SHOONYA_TWO_FA`
106
+ - `SHOONYA_API_KEY`
107
+ - `SHOONYA_VENDOR_CODE` (optional)
108
+ - `SHOONYA_IMEI` (optional)
109
+
110
+ ## Puppeteer/Chrome Config
111
+
112
+ OAuth code generation uses Puppeteer.
113
+
114
+ - `.puppeteerrc.cjs` auto-detects installed Chrome from `~/.cache/puppeteer/chrome`
115
+ - Optional override: `PUPPETEER_EXECUTABLE_PATH`
116
+ - Optional sandbox toggle for server/CI: `PUPPETEER_NO_SANDBOX=true` (or `CI=true`)
117
+ - Optional auth automation speed: `SHOONYA_AUTH_SLOWMO_MS` (default `5`)
118
+
65
119
  ## Features
66
120
 
67
- - Auto Reconnect On Failures
68
- - Auto Refresh Access Token When it is expired
69
- - Sync Credentials and Tokens between Rest and WS Clients
70
- - Reconnect with Shoonya WS at fixed time interval, which is configurable
71
- - Configurable heartbeat timer to keep connection alive
72
- - and more...
121
+ - OAuth-based token exchange (`GenAcsTok`)
122
+ - REST requests send `jKey` in body by default (optional Bearer header via `sendBearerAuthHeader`)
123
+ - WSAPI-first WebSocket flow with fallback support
124
+ - Auto reconnect and token refresh
125
+ - Configurable daily reconnect, heartbeat, and ack timeout