zklighter-perps 1.0.302 → 1.0.304
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.
- package/.openapi-generator/FILES +2 -0
- package/README.md +35 -71
- package/apis/StockfinancialsApi.ts +2 -2
- package/models/StockFinancial.ts +15 -0
- package/models/StockFinancialDividendEvent.ts +153 -0
- package/models/StockFinancialDividends.ts +85 -0
- package/models/TvSymbolInfo.ts +2 -2
- package/models/index.ts +2 -0
- package/openapi.json +88 -3
- package/package.json +7 -2
- package/.circleci/config.yml +0 -291
- package/.circleci/openapi_postprocess.py +0 -366
package/.openapi-generator/FILES
CHANGED
|
@@ -259,6 +259,8 @@ models/Status.ts
|
|
|
259
259
|
models/StockBalanceSheet.ts
|
|
260
260
|
models/StockCashFlowStatement.ts
|
|
261
261
|
models/StockFinancial.ts
|
|
262
|
+
models/StockFinancialDividendEvent.ts
|
|
263
|
+
models/StockFinancialDividends.ts
|
|
262
264
|
models/StockFinancialEarnings.ts
|
|
263
265
|
models/StockFinancialEarningsEvent.ts
|
|
264
266
|
models/StockFinancialHistoricalEarning.ts
|
package/README.md
CHANGED
|
@@ -1,86 +1,50 @@
|
|
|
1
|
-
# zklighter-perps
|
|
1
|
+
# zklighter-perps
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
TypeScript client for the Lighter Perps REST API, published to npm as
|
|
4
4
|
[`zklighter-perps`](https://www.npmjs.com/package/zklighter-perps).
|
|
5
5
|
|
|
6
|
-
The
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
consumers compile it themselves.
|
|
6
|
+
The client is generated from the backend's OpenAPI spec with
|
|
7
|
+
[OpenAPI Generator](https://openapi-generator.tech) (`typescript-fetch`). It
|
|
8
|
+
ships raw `.ts` (`"main": "index.ts"`), so your bundler or `tsc` compiles it
|
|
9
|
+
along with your own code.
|
|
11
10
|
|
|
12
|
-
##
|
|
11
|
+
## Install
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
1. **`update_openapi`** — clones `zklighter-perps`, runs `goctl-swagger` to emit
|
|
18
|
-
the raw `openapi.json`, and persists it. This job no longer transforms the
|
|
19
|
-
spec; it only generates and persists it.
|
|
20
|
-
2. **`openapi_postprocess`** — runs
|
|
21
|
-
[`.circleci/openapi_postprocess.py`](.circleci/openapi_postprocess.py), the
|
|
22
|
-
**single source of truth** for all spec fixups (see below).
|
|
23
|
-
3. **`update_ts_sdk`** — runs the OpenAPI Generator on the post-processed spec,
|
|
24
|
-
bumps the package version, and opens a PR.
|
|
25
|
-
|
|
26
|
-
The `update_npm_package` workflow runs on `main`:
|
|
13
|
+
```bash
|
|
14
|
+
npm install zklighter-perps
|
|
15
|
+
```
|
|
27
16
|
|
|
28
|
-
|
|
29
|
-
[`tsconfig.json`](tsconfig.json)). Runs on every branch, including the
|
|
30
|
-
timestamped branches opened by `update_ts_sdk`, so a regenerated SDK that
|
|
31
|
-
would fail to compile in a consumer (e.g. `perps-fe`) is caught on its PR.
|
|
32
|
-
- **`update_npm_package`** — publishes to npm (requires `typecheck` to pass;
|
|
33
|
-
`main` only).
|
|
34
|
-
- **`publish_prerelease`** — on non-`main` branches with an open PR, publishes
|
|
35
|
-
a prerelease version (`0.<PR>.0-<actor>.<sha>.<branch>`, npm dist-tag =
|
|
36
|
-
branch name) and posts/updates a PR comment with the exact version to drop
|
|
37
|
-
into a consumer's `package.json`, mirroring the prerelease flow in
|
|
38
|
-
`zklighter-react-store`.
|
|
17
|
+
## Usage
|
|
39
18
|
|
|
40
|
-
|
|
19
|
+
```ts
|
|
20
|
+
import { Configuration, OrderApi } from 'zklighter-perps'
|
|
41
21
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
(Historically some of these fixes were inline `jq`/`sed` commands in the
|
|
46
|
-
`update_openapi` job; they have been consolidated into the script so the logic
|
|
47
|
-
is in a single, testable file.)
|
|
22
|
+
const orderApi = new OrderApi(
|
|
23
|
+
new Configuration({ basePath: 'https://mainnet.zklighter.elliot.ai' }),
|
|
24
|
+
)
|
|
48
25
|
|
|
49
|
-
|
|
26
|
+
const orderBooks = await orderApi.orderBooks()
|
|
27
|
+
```
|
|
50
28
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
Generator cannot process.
|
|
56
|
-
3. **Mirror `summary` into `description`** — preserves the original
|
|
57
|
-
human-readable text as the generated doc comment before `summary` is
|
|
58
|
-
overwritten in step 8.
|
|
59
|
-
4. **Seed `summary` from `operationId`** — normalizes naming before step 8.
|
|
60
|
-
5. **Add a documented `400` response** referencing `ResultCode` to every
|
|
61
|
-
operation, so the SDK models the standard error shape.
|
|
62
|
-
6. **Model the `types` parameter as a byte array** (`array` of `uint8`) instead
|
|
63
|
-
of the non-standard scalar the spec declares.
|
|
64
|
-
7. **Remove placeholder `"-"` enum/array values** that aren't real values.
|
|
65
|
-
8. **Derive stable, path-based `operationId`/`summary`** (e.g.
|
|
66
|
-
`/api/v1/account` → `account`) so generated method names are predictable.
|
|
67
|
-
9. **Inline non-standard `int16`/`float64`/map `$ref`s** (`int16`, `float64`,
|
|
68
|
-
`mapint16string`, `mapstringfloat64`) — these are not standard OpenAPI and
|
|
69
|
-
make the generator emit broken model references.
|
|
70
|
-
10. **Move array-level `enum` into `items`** — correct placement for array
|
|
71
|
-
schemas.
|
|
72
|
-
11. **Make the `transfer/history` `type` param an array** of enum strings.
|
|
73
|
-
12. **Trim over-eager `required` fields** — the backend marks fields required
|
|
74
|
-
that are actually optional in responses; we relax them so deserialization
|
|
75
|
-
doesn't reject valid payloads.
|
|
29
|
+
Every API group has a class in [`apis/`](apis) (`AccountApi`, `OrderApi`,
|
|
30
|
+
`TransactionApi`, ...) and every request/response type lives in
|
|
31
|
+
[`models/`](models). `basePath` defaults to mainnet; pass the testnet URL to
|
|
32
|
+
target testnet. Endpoints that need authentication take an `auth` parameter.
|
|
76
33
|
|
|
77
|
-
##
|
|
34
|
+
## Development
|
|
78
35
|
|
|
79
36
|
```bash
|
|
80
|
-
npm install
|
|
81
|
-
npm run typecheck
|
|
37
|
+
npm install # also wires the git hooks (.githooks)
|
|
38
|
+
npm run typecheck # tsc --noEmit, the same check CI runs
|
|
39
|
+
npm run scan:secrets
|
|
82
40
|
```
|
|
83
41
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
42
|
+
`index.ts`, `runtime.ts`, `apis/` and `models/` are generated. Do not edit
|
|
43
|
+
them by hand; they are overwritten on the next regeneration. Regeneration,
|
|
44
|
+
spec post-processing and npm publishing all run in CircleCI and are documented
|
|
45
|
+
in [`.circleci/README.md`](.circleci/README.md).
|
|
46
|
+
|
|
47
|
+
A pre-commit hook scans staged files for secrets, and `npm publish` runs the
|
|
48
|
+
same scan over the whole package before uploading. Both use
|
|
49
|
+
[secretlint](https://github.com/secretlint/secretlint) with the recommended
|
|
50
|
+
preset; exclusions go in `.secretlintignore`.
|
|
@@ -36,7 +36,7 @@ export interface StockFinancialsRequest {
|
|
|
36
36
|
export class StockfinancialsApi extends runtime.BaseAPI {
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
|
-
* Get stock financials. Returns stock_financial for a single market_id, or stock_financials for every stock market when market_id is omitted. fields narrows the response to a subset of currency, exchange, industry, sector, country, market_cap, next_earnings; omit it to get the full record, which requires market_id.
|
|
39
|
+
* Get stock financials. Returns stock_financial for a single market_id, or stock_financials for every stock market when market_id is omitted. fields narrows the response to a subset of currency, exchange, industry, sector, country, market_cap, next_earnings, next_dividend; omit it to get the full record, which requires market_id.
|
|
40
40
|
* stockFinancials
|
|
41
41
|
*/
|
|
42
42
|
async stockFinancialsRaw(requestParameters: StockFinancialsRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<RespStockFinancials>> {
|
|
@@ -63,7 +63,7 @@ export class StockfinancialsApi extends runtime.BaseAPI {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
/**
|
|
66
|
-
* Get stock financials. Returns stock_financial for a single market_id, or stock_financials for every stock market when market_id is omitted. fields narrows the response to a subset of currency, exchange, industry, sector, country, market_cap, next_earnings; omit it to get the full record, which requires market_id.
|
|
66
|
+
* Get stock financials. Returns stock_financial for a single market_id, or stock_financials for every stock market when market_id is omitted. fields narrows the response to a subset of currency, exchange, industry, sector, country, market_cap, next_earnings, next_dividend; omit it to get the full record, which requires market_id.
|
|
67
67
|
* stockFinancials
|
|
68
68
|
*/
|
|
69
69
|
async stockFinancials(requestParameters: StockFinancialsRequest = {}, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<RespStockFinancials> {
|
package/models/StockFinancial.ts
CHANGED
|
@@ -25,6 +25,12 @@ import {
|
|
|
25
25
|
StockFinancialProfileFromJSONTyped,
|
|
26
26
|
StockFinancialProfileToJSON,
|
|
27
27
|
} from './StockFinancialProfile';
|
|
28
|
+
import type { StockFinancialDividends } from './StockFinancialDividends';
|
|
29
|
+
import {
|
|
30
|
+
StockFinancialDividendsFromJSON,
|
|
31
|
+
StockFinancialDividendsFromJSONTyped,
|
|
32
|
+
StockFinancialDividendsToJSON,
|
|
33
|
+
} from './StockFinancialDividends';
|
|
28
34
|
import type { StockFinancialEarnings } from './StockFinancialEarnings';
|
|
29
35
|
import {
|
|
30
36
|
StockFinancialEarningsFromJSON,
|
|
@@ -56,6 +62,12 @@ export interface StockFinancial {
|
|
|
56
62
|
* @memberof StockFinancial
|
|
57
63
|
*/
|
|
58
64
|
earnings: StockFinancialEarnings;
|
|
65
|
+
/**
|
|
66
|
+
*
|
|
67
|
+
* @type {StockFinancialDividends}
|
|
68
|
+
* @memberof StockFinancial
|
|
69
|
+
*/
|
|
70
|
+
dividends: StockFinancialDividends;
|
|
59
71
|
/**
|
|
60
72
|
*
|
|
61
73
|
* @type {StockFinancialStatements}
|
|
@@ -71,6 +83,7 @@ export function instanceOfStockFinancial(value: object): value is StockFinancial
|
|
|
71
83
|
if (!('market_id' in value) || value['market_id'] === undefined) return false;
|
|
72
84
|
if (!('profile' in value) || value['profile'] === undefined) return false;
|
|
73
85
|
if (!('earnings' in value) || value['earnings'] === undefined) return false;
|
|
86
|
+
if (!('dividends' in value) || value['dividends'] === undefined) return false;
|
|
74
87
|
if (!('statements' in value) || value['statements'] === undefined) return false;
|
|
75
88
|
return true;
|
|
76
89
|
}
|
|
@@ -88,6 +101,7 @@ export function StockFinancialFromJSONTyped(json: any, ignoreDiscriminator: bool
|
|
|
88
101
|
'market_id': json['market_id'],
|
|
89
102
|
'profile': StockFinancialProfileFromJSON(json['profile']),
|
|
90
103
|
'earnings': StockFinancialEarningsFromJSON(json['earnings']),
|
|
104
|
+
'dividends': StockFinancialDividendsFromJSON(json['dividends']),
|
|
91
105
|
'statements': StockFinancialStatementsFromJSON(json['statements']),
|
|
92
106
|
};
|
|
93
107
|
}
|
|
@@ -101,6 +115,7 @@ export function StockFinancialToJSON(value?: StockFinancial | null): any {
|
|
|
101
115
|
'market_id': value['market_id'],
|
|
102
116
|
'profile': StockFinancialProfileToJSON(value['profile']),
|
|
103
117
|
'earnings': StockFinancialEarningsToJSON(value['earnings']),
|
|
118
|
+
'dividends': StockFinancialDividendsToJSON(value['dividends']),
|
|
104
119
|
'statements': StockFinancialStatementsToJSON(value['statements']),
|
|
105
120
|
};
|
|
106
121
|
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
|
6
|
+
*
|
|
7
|
+
* The version of the OpenAPI document:
|
|
8
|
+
*
|
|
9
|
+
*
|
|
10
|
+
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
|
11
|
+
* https://openapi-generator.tech
|
|
12
|
+
* Do not edit the class manually.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { mapValues } from '../runtime';
|
|
16
|
+
/**
|
|
17
|
+
*
|
|
18
|
+
* @export
|
|
19
|
+
* @interface StockFinancialDividendEvent
|
|
20
|
+
*/
|
|
21
|
+
export interface StockFinancialDividendEvent {
|
|
22
|
+
/**
|
|
23
|
+
*
|
|
24
|
+
* @type {string}
|
|
25
|
+
* @memberof StockFinancialDividendEvent
|
|
26
|
+
*/
|
|
27
|
+
source: StockFinancialDividendEventSourceEnum;
|
|
28
|
+
/**
|
|
29
|
+
*
|
|
30
|
+
* @type {string}
|
|
31
|
+
* @memberof StockFinancialDividendEvent
|
|
32
|
+
*/
|
|
33
|
+
ex_date: string;
|
|
34
|
+
/**
|
|
35
|
+
*
|
|
36
|
+
* @type {string}
|
|
37
|
+
* @memberof StockFinancialDividendEvent
|
|
38
|
+
*/
|
|
39
|
+
record_date: string;
|
|
40
|
+
/**
|
|
41
|
+
*
|
|
42
|
+
* @type {string}
|
|
43
|
+
* @memberof StockFinancialDividendEvent
|
|
44
|
+
*/
|
|
45
|
+
payment_date: string;
|
|
46
|
+
/**
|
|
47
|
+
*
|
|
48
|
+
* @type {string}
|
|
49
|
+
* @memberof StockFinancialDividendEvent
|
|
50
|
+
*/
|
|
51
|
+
declaration_date: string;
|
|
52
|
+
/**
|
|
53
|
+
*
|
|
54
|
+
* @type {number}
|
|
55
|
+
* @memberof StockFinancialDividendEvent
|
|
56
|
+
*/
|
|
57
|
+
amount: number;
|
|
58
|
+
/**
|
|
59
|
+
*
|
|
60
|
+
* @type {number}
|
|
61
|
+
* @memberof StockFinancialDividendEvent
|
|
62
|
+
*/
|
|
63
|
+
adj_amount: number;
|
|
64
|
+
/**
|
|
65
|
+
*
|
|
66
|
+
* @type {string}
|
|
67
|
+
* @memberof StockFinancialDividendEvent
|
|
68
|
+
*/
|
|
69
|
+
frequency: string;
|
|
70
|
+
/**
|
|
71
|
+
*
|
|
72
|
+
* @type {string}
|
|
73
|
+
* @memberof StockFinancialDividendEvent
|
|
74
|
+
*/
|
|
75
|
+
currency: string;
|
|
76
|
+
/**
|
|
77
|
+
*
|
|
78
|
+
* @type {string}
|
|
79
|
+
* @memberof StockFinancialDividendEvent
|
|
80
|
+
*/
|
|
81
|
+
status: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @export
|
|
87
|
+
*/
|
|
88
|
+
export const StockFinancialDividendEventSourceEnum = {
|
|
89
|
+
Fmp: 'fmp',
|
|
90
|
+
Robinhood: 'robinhood'
|
|
91
|
+
} as const;
|
|
92
|
+
export type StockFinancialDividendEventSourceEnum = typeof StockFinancialDividendEventSourceEnum[keyof typeof StockFinancialDividendEventSourceEnum];
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Check if a given object implements the StockFinancialDividendEvent interface.
|
|
97
|
+
*/
|
|
98
|
+
export function instanceOfStockFinancialDividendEvent(value: object): value is StockFinancialDividendEvent {
|
|
99
|
+
if (!('source' in value) || value['source'] === undefined) return false;
|
|
100
|
+
if (!('ex_date' in value) || value['ex_date'] === undefined) return false;
|
|
101
|
+
if (!('record_date' in value) || value['record_date'] === undefined) return false;
|
|
102
|
+
if (!('payment_date' in value) || value['payment_date'] === undefined) return false;
|
|
103
|
+
if (!('declaration_date' in value) || value['declaration_date'] === undefined) return false;
|
|
104
|
+
if (!('amount' in value) || value['amount'] === undefined) return false;
|
|
105
|
+
if (!('adj_amount' in value) || value['adj_amount'] === undefined) return false;
|
|
106
|
+
if (!('frequency' in value) || value['frequency'] === undefined) return false;
|
|
107
|
+
if (!('currency' in value) || value['currency'] === undefined) return false;
|
|
108
|
+
if (!('status' in value) || value['status'] === undefined) return false;
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function StockFinancialDividendEventFromJSON(json: any): StockFinancialDividendEvent {
|
|
113
|
+
return StockFinancialDividendEventFromJSONTyped(json, false);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function StockFinancialDividendEventFromJSONTyped(json: any, ignoreDiscriminator: boolean): StockFinancialDividendEvent {
|
|
117
|
+
if (json == null) {
|
|
118
|
+
return json;
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
|
|
122
|
+
'source': json['source'],
|
|
123
|
+
'ex_date': json['ex_date'],
|
|
124
|
+
'record_date': json['record_date'],
|
|
125
|
+
'payment_date': json['payment_date'],
|
|
126
|
+
'declaration_date': json['declaration_date'],
|
|
127
|
+
'amount': json['amount'],
|
|
128
|
+
'adj_amount': json['adj_amount'],
|
|
129
|
+
'frequency': json['frequency'],
|
|
130
|
+
'currency': json['currency'],
|
|
131
|
+
'status': json['status'],
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function StockFinancialDividendEventToJSON(value?: StockFinancialDividendEvent | null): any {
|
|
136
|
+
if (value == null) {
|
|
137
|
+
return value;
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
|
|
141
|
+
'source': value['source'],
|
|
142
|
+
'ex_date': value['ex_date'],
|
|
143
|
+
'record_date': value['record_date'],
|
|
144
|
+
'payment_date': value['payment_date'],
|
|
145
|
+
'declaration_date': value['declaration_date'],
|
|
146
|
+
'amount': value['amount'],
|
|
147
|
+
'adj_amount': value['adj_amount'],
|
|
148
|
+
'frequency': value['frequency'],
|
|
149
|
+
'currency': value['currency'],
|
|
150
|
+
'status': value['status'],
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
|
6
|
+
*
|
|
7
|
+
* The version of the OpenAPI document:
|
|
8
|
+
*
|
|
9
|
+
*
|
|
10
|
+
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
|
11
|
+
* https://openapi-generator.tech
|
|
12
|
+
* Do not edit the class manually.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { mapValues } from '../runtime';
|
|
16
|
+
import type { StockFinancialDividendEvent } from './StockFinancialDividendEvent';
|
|
17
|
+
import {
|
|
18
|
+
StockFinancialDividendEventFromJSON,
|
|
19
|
+
StockFinancialDividendEventFromJSONTyped,
|
|
20
|
+
StockFinancialDividendEventToJSON,
|
|
21
|
+
} from './StockFinancialDividendEvent';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
*
|
|
25
|
+
* @export
|
|
26
|
+
* @interface StockFinancialDividends
|
|
27
|
+
*/
|
|
28
|
+
export interface StockFinancialDividends {
|
|
29
|
+
/**
|
|
30
|
+
*
|
|
31
|
+
* @type {StockFinancialDividendEvent}
|
|
32
|
+
* @memberof StockFinancialDividends
|
|
33
|
+
*/
|
|
34
|
+
next?: StockFinancialDividendEvent;
|
|
35
|
+
/**
|
|
36
|
+
*
|
|
37
|
+
* @type {Array<StockFinancialDividendEvent>}
|
|
38
|
+
* @memberof StockFinancialDividends
|
|
39
|
+
*/
|
|
40
|
+
history: Array<StockFinancialDividendEvent>;
|
|
41
|
+
/**
|
|
42
|
+
*
|
|
43
|
+
* @type {Array<StockFinancialDividendEvent>}
|
|
44
|
+
* @memberof StockFinancialDividends
|
|
45
|
+
*/
|
|
46
|
+
distributions: Array<StockFinancialDividendEvent>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Check if a given object implements the StockFinancialDividends interface.
|
|
51
|
+
*/
|
|
52
|
+
export function instanceOfStockFinancialDividends(value: object): value is StockFinancialDividends {
|
|
53
|
+
if (!('history' in value) || value['history'] === undefined) return false;
|
|
54
|
+
if (!('distributions' in value) || value['distributions'] === undefined) return false;
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function StockFinancialDividendsFromJSON(json: any): StockFinancialDividends {
|
|
59
|
+
return StockFinancialDividendsFromJSONTyped(json, false);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function StockFinancialDividendsFromJSONTyped(json: any, ignoreDiscriminator: boolean): StockFinancialDividends {
|
|
63
|
+
if (json == null) {
|
|
64
|
+
return json;
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
|
|
68
|
+
'next': json['next'] == null ? undefined : StockFinancialDividendEventFromJSON(json['next']),
|
|
69
|
+
'history': ((json['history'] as Array<any>).map(StockFinancialDividendEventFromJSON)),
|
|
70
|
+
'distributions': ((json['distributions'] as Array<any>).map(StockFinancialDividendEventFromJSON)),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function StockFinancialDividendsToJSON(value?: StockFinancialDividends | null): any {
|
|
75
|
+
if (value == null) {
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
|
|
80
|
+
'next': StockFinancialDividendEventToJSON(value['next']),
|
|
81
|
+
'history': ((value['history'] as Array<any>).map(StockFinancialDividendEventToJSON)),
|
|
82
|
+
'distributions': ((value['distributions'] as Array<any>).map(StockFinancialDividendEventToJSON)),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
package/models/TvSymbolInfo.ts
CHANGED
|
@@ -112,10 +112,10 @@ export interface TvSymbolInfo {
|
|
|
112
112
|
has_intraday: boolean;
|
|
113
113
|
/**
|
|
114
114
|
*
|
|
115
|
-
* @type {boolean}
|
|
115
|
+
* @type {Array<boolean>}
|
|
116
116
|
* @memberof TvSymbolInfo
|
|
117
117
|
*/
|
|
118
|
-
has_no_volume: boolean
|
|
118
|
+
has_no_volume: Array<boolean>;
|
|
119
119
|
/**
|
|
120
120
|
*
|
|
121
121
|
* @type {boolean}
|
package/models/index.ts
CHANGED
|
@@ -237,6 +237,8 @@ export * from './Status';
|
|
|
237
237
|
export * from './StockBalanceSheet';
|
|
238
238
|
export * from './StockCashFlowStatement';
|
|
239
239
|
export * from './StockFinancial';
|
|
240
|
+
export * from './StockFinancialDividendEvent';
|
|
241
|
+
export * from './StockFinancialDividends';
|
|
240
242
|
export * from './StockFinancialEarnings';
|
|
241
243
|
export * from './StockFinancialEarningsEvent';
|
|
242
244
|
export * from './StockFinancialHistoricalEarning';
|
package/openapi.json
CHANGED
|
@@ -4832,7 +4832,7 @@
|
|
|
4832
4832
|
"consumes": [
|
|
4833
4833
|
"multipart/form-data"
|
|
4834
4834
|
],
|
|
4835
|
-
"description": "Get stock financials. Returns stock_financial for a single market_id, or stock_financials for every stock market when market_id is omitted. fields narrows the response to a subset of currency, exchange, industry, sector, country, market_cap, next_earnings; omit it to get the full record, which requires market_id."
|
|
4835
|
+
"description": "Get stock financials. Returns stock_financial for a single market_id, or stock_financials for every stock market when market_id is omitted. fields narrows the response to a subset of currency, exchange, industry, sector, country, market_cap, next_earnings, next_dividend; omit it to get the full record, which requires market_id."
|
|
4836
4836
|
}
|
|
4837
4837
|
},
|
|
4838
4838
|
"/api/v1/syntheticSpotInfo": {
|
|
@@ -15548,6 +15548,9 @@
|
|
|
15548
15548
|
"earnings": {
|
|
15549
15549
|
"$ref": "#/definitions/StockFinancialEarnings"
|
|
15550
15550
|
},
|
|
15551
|
+
"dividends": {
|
|
15552
|
+
"$ref": "#/definitions/StockFinancialDividends"
|
|
15553
|
+
},
|
|
15551
15554
|
"statements": {
|
|
15552
15555
|
"$ref": "#/definitions/StockFinancialStatements"
|
|
15553
15556
|
}
|
|
@@ -15557,9 +15560,89 @@
|
|
|
15557
15560
|
"market_id",
|
|
15558
15561
|
"profile",
|
|
15559
15562
|
"earnings",
|
|
15563
|
+
"dividends",
|
|
15560
15564
|
"statements"
|
|
15561
15565
|
]
|
|
15562
15566
|
},
|
|
15567
|
+
"StockFinancialDividendEvent": {
|
|
15568
|
+
"type": "object",
|
|
15569
|
+
"properties": {
|
|
15570
|
+
"source": {
|
|
15571
|
+
"type": "string",
|
|
15572
|
+
"enum": [
|
|
15573
|
+
"fmp",
|
|
15574
|
+
"robinhood"
|
|
15575
|
+
]
|
|
15576
|
+
},
|
|
15577
|
+
"ex_date": {
|
|
15578
|
+
"type": "string"
|
|
15579
|
+
},
|
|
15580
|
+
"record_date": {
|
|
15581
|
+
"type": "string"
|
|
15582
|
+
},
|
|
15583
|
+
"payment_date": {
|
|
15584
|
+
"type": "string"
|
|
15585
|
+
},
|
|
15586
|
+
"declaration_date": {
|
|
15587
|
+
"type": "string"
|
|
15588
|
+
},
|
|
15589
|
+
"amount": {
|
|
15590
|
+
"type": "number",
|
|
15591
|
+
"format": "double"
|
|
15592
|
+
},
|
|
15593
|
+
"adj_amount": {
|
|
15594
|
+
"type": "number",
|
|
15595
|
+
"format": "double"
|
|
15596
|
+
},
|
|
15597
|
+
"frequency": {
|
|
15598
|
+
"type": "string"
|
|
15599
|
+
},
|
|
15600
|
+
"currency": {
|
|
15601
|
+
"type": "string"
|
|
15602
|
+
},
|
|
15603
|
+
"status": {
|
|
15604
|
+
"type": "string"
|
|
15605
|
+
}
|
|
15606
|
+
},
|
|
15607
|
+
"title": "StockFinancialDividendEvent",
|
|
15608
|
+
"required": [
|
|
15609
|
+
"source",
|
|
15610
|
+
"ex_date",
|
|
15611
|
+
"record_date",
|
|
15612
|
+
"payment_date",
|
|
15613
|
+
"declaration_date",
|
|
15614
|
+
"amount",
|
|
15615
|
+
"adj_amount",
|
|
15616
|
+
"frequency",
|
|
15617
|
+
"currency",
|
|
15618
|
+
"status"
|
|
15619
|
+
]
|
|
15620
|
+
},
|
|
15621
|
+
"StockFinancialDividends": {
|
|
15622
|
+
"type": "object",
|
|
15623
|
+
"properties": {
|
|
15624
|
+
"next": {
|
|
15625
|
+
"$ref": "#/definitions/StockFinancialDividendEvent"
|
|
15626
|
+
},
|
|
15627
|
+
"history": {
|
|
15628
|
+
"type": "array",
|
|
15629
|
+
"items": {
|
|
15630
|
+
"$ref": "#/definitions/StockFinancialDividendEvent"
|
|
15631
|
+
}
|
|
15632
|
+
},
|
|
15633
|
+
"distributions": {
|
|
15634
|
+
"type": "array",
|
|
15635
|
+
"items": {
|
|
15636
|
+
"$ref": "#/definitions/StockFinancialDividendEvent"
|
|
15637
|
+
}
|
|
15638
|
+
}
|
|
15639
|
+
},
|
|
15640
|
+
"title": "StockFinancialDividends",
|
|
15641
|
+
"required": [
|
|
15642
|
+
"history",
|
|
15643
|
+
"distributions"
|
|
15644
|
+
]
|
|
15645
|
+
},
|
|
15563
15646
|
"StockFinancialEarnings": {
|
|
15564
15647
|
"type": "object",
|
|
15565
15648
|
"properties": {
|
|
@@ -16859,8 +16942,10 @@
|
|
|
16859
16942
|
"format": "boolean"
|
|
16860
16943
|
},
|
|
16861
16944
|
"has-no-volume": {
|
|
16862
|
-
"type": "
|
|
16863
|
-
"
|
|
16945
|
+
"type": "array",
|
|
16946
|
+
"items": {
|
|
16947
|
+
"type": "boolean"
|
|
16948
|
+
}
|
|
16864
16949
|
},
|
|
16865
16950
|
"has-daily": {
|
|
16866
16951
|
"type": "boolean",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zklighter-perps",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.304",
|
|
4
4
|
"description": "Lighter Perps SDK",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"directories": {
|
|
@@ -8,8 +8,11 @@
|
|
|
8
8
|
"test": "test"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
+
"prepare": "node -e \"require('fs').existsSync('.git')&&require('child_process').execFileSync('git',['config','core.hooksPath','.githooks'])\"",
|
|
11
12
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
12
|
-
"typecheck": "tsc --noEmit"
|
|
13
|
+
"typecheck": "tsc --noEmit",
|
|
14
|
+
"scan:secrets": "secretlint \"**/*\"",
|
|
15
|
+
"prepublishOnly": "npm run scan:secrets"
|
|
13
16
|
},
|
|
14
17
|
"repository": {
|
|
15
18
|
"type": "git",
|
|
@@ -22,6 +25,8 @@
|
|
|
22
25
|
},
|
|
23
26
|
"homepage": "https://github.com/elliottech/zklighter-perps-ts#readme",
|
|
24
27
|
"devDependencies": {
|
|
28
|
+
"@secretlint/secretlint-rule-preset-recommend": "13.0.5",
|
|
29
|
+
"secretlint": "13.0.5",
|
|
25
30
|
"typescript": "7.0.2"
|
|
26
31
|
}
|
|
27
32
|
}
|
package/.circleci/config.yml
DELETED
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
version: 2.1
|
|
2
|
-
|
|
3
|
-
jobs:
|
|
4
|
-
update_openapi:
|
|
5
|
-
docker:
|
|
6
|
-
- image: cimg/go:1.22.5
|
|
7
|
-
|
|
8
|
-
working_directory: ~/project
|
|
9
|
-
|
|
10
|
-
steps:
|
|
11
|
-
- checkout
|
|
12
|
-
|
|
13
|
-
- run:
|
|
14
|
-
name: Clone zklighter-perps repository
|
|
15
|
-
command: |
|
|
16
|
-
git clone -b << pipeline.parameters.BE_BRANCH >> --depth 1 https://${GITHUB_TOKEN}@github.com/elliottech/zklighter-perps.git
|
|
17
|
-
|
|
18
|
-
- run:
|
|
19
|
-
name: Download goctl-swagger binary
|
|
20
|
-
command: |
|
|
21
|
-
mv goctl-swagger-amd zklighter-perps/service/apiserver
|
|
22
|
-
cd zklighter-perps/service/apiserver
|
|
23
|
-
chmod +x goctl-swagger-amd
|
|
24
|
-
|
|
25
|
-
- run:
|
|
26
|
-
name: Run goctl api plugin
|
|
27
|
-
command: |
|
|
28
|
-
cd zklighter-perps/service/apiserver
|
|
29
|
-
GO111MODULE=on go install github.com/zeromicro/go-zero/tools/goctl@v1.6.6
|
|
30
|
-
sed 's/struct{}/{}/g' server.api > temp.txt && cp temp.txt server.api && rm temp.txt
|
|
31
|
-
goctl api plugin --plugin ./goctl-swagger-amd="swagger -filename openapi.json -host mainnet.zklighter.elliot.ai -schemes https" --api server.api --dir .
|
|
32
|
-
|
|
33
|
-
# NOTE: all openapi.json post-processing now lives in the dedicated
|
|
34
|
-
# `openapi_postprocess` job (.circleci/openapi_postprocess.py). This job
|
|
35
|
-
# only generates and persists the raw spec. See README.md.
|
|
36
|
-
|
|
37
|
-
- store_artifacts:
|
|
38
|
-
path: ~/project/zklighter-perps/service/apiserver/openapi.json
|
|
39
|
-
|
|
40
|
-
- persist_to_workspace:
|
|
41
|
-
root: ~/project/zklighter-perps/service/apiserver
|
|
42
|
-
paths:
|
|
43
|
-
- openapi.json
|
|
44
|
-
|
|
45
|
-
openapi_postprocess:
|
|
46
|
-
docker:
|
|
47
|
-
- image: cimg/python:3.10.0
|
|
48
|
-
working_directory: ~/project
|
|
49
|
-
steps:
|
|
50
|
-
- checkout
|
|
51
|
-
|
|
52
|
-
- attach_workspace:
|
|
53
|
-
at: /tmp/workspace
|
|
54
|
-
|
|
55
|
-
- run:
|
|
56
|
-
name: Get openapi.json from workspace
|
|
57
|
-
command: |
|
|
58
|
-
cp /tmp/workspace/openapi.json ./.circleci
|
|
59
|
-
|
|
60
|
-
- run:
|
|
61
|
-
name: Run postprocess script
|
|
62
|
-
command: |
|
|
63
|
-
cd ./.circleci
|
|
64
|
-
python3 openapi_postprocess.py
|
|
65
|
-
|
|
66
|
-
- store_artifacts:
|
|
67
|
-
path: ~/project/.circleci/openapi.json
|
|
68
|
-
|
|
69
|
-
- persist_to_workspace:
|
|
70
|
-
root: ~/project/.circleci
|
|
71
|
-
paths:
|
|
72
|
-
- openapi.json
|
|
73
|
-
|
|
74
|
-
update_ts_sdk:
|
|
75
|
-
docker:
|
|
76
|
-
- image: cimg/openjdk:21.0.2
|
|
77
|
-
working_directory: ~/project
|
|
78
|
-
steps:
|
|
79
|
-
- checkout
|
|
80
|
-
|
|
81
|
-
- attach_workspace:
|
|
82
|
-
at: /tmp/workspace
|
|
83
|
-
|
|
84
|
-
- run:
|
|
85
|
-
name: Get openapi.json from workspace
|
|
86
|
-
command: |
|
|
87
|
-
cp /tmp/workspace/openapi.json .
|
|
88
|
-
|
|
89
|
-
- run:
|
|
90
|
-
name: Download OpenAPI Generator JAR
|
|
91
|
-
command: |
|
|
92
|
-
wget https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/7.7.0/openapi-generator-cli-7.7.0.jar -O openapi-generator-cli.jar
|
|
93
|
-
|
|
94
|
-
- run:
|
|
95
|
-
name: Generate TS client using OpenAPI Generator
|
|
96
|
-
command: |
|
|
97
|
-
java -jar openapi-generator-cli.jar generate -i ./openapi.json -g typescript-fetch -o . -c config.yaml
|
|
98
|
-
- run:
|
|
99
|
-
name: git status
|
|
100
|
-
command: |
|
|
101
|
-
if git status | grep -q "nothing to commit"; then
|
|
102
|
-
exit 1;
|
|
103
|
-
fi
|
|
104
|
-
- run:
|
|
105
|
-
name: Increase package version
|
|
106
|
-
command: |
|
|
107
|
-
jq '.version |= (split(".") | .[2] = ((.[2] | tonumber) + 1 | tostring) | join("."))' package.json > tmp.json && mv tmp.json package.json
|
|
108
|
-
|
|
109
|
-
- run:
|
|
110
|
-
name: push to new branch
|
|
111
|
-
command: |
|
|
112
|
-
git remote remove origin
|
|
113
|
-
git remote add origin https://${GITHUB_TOKEN}@github.com/elliottech/zklighter-perps-ts
|
|
114
|
-
|
|
115
|
-
git config --global user.email "hasan@circleci.com"
|
|
116
|
-
git config --global user.name "CircleCI Hasan"
|
|
117
|
-
export BRANCH_NAME=`date +%s`
|
|
118
|
-
git checkout -b $BRANCH_NAME
|
|
119
|
-
git add .
|
|
120
|
-
git commit -m "Update SDK"
|
|
121
|
-
git push origin $BRANCH_NAME
|
|
122
|
-
|
|
123
|
-
BE_BRANCH=<< pipeline.parameters.BE_BRANCH >>
|
|
124
|
-
|
|
125
|
-
PR_URL=$(curl -X POST -H "Authorization: Bearer ${GITHUB_TOKEN}" -d '{"title": "'$BE_BRANCH'", "head": "'$BRANCH_NAME'", "base": "main"}' https://api.github.com/repos/elliottech/zklighter-perps-ts/pulls | jq -r '.html_url')
|
|
126
|
-
curl -X POST -H 'Content-type: application/json' --data '{"text":"TypeScript SDK has been updated. Check the PR here: '$PR_URL'", "type": "mrkdwn"}' ${SLACK_URL}
|
|
127
|
-
|
|
128
|
-
typecheck:
|
|
129
|
-
docker:
|
|
130
|
-
- image: cimg/node:22.4.1
|
|
131
|
-
|
|
132
|
-
working_directory: ~/project
|
|
133
|
-
|
|
134
|
-
steps:
|
|
135
|
-
- checkout
|
|
136
|
-
- run:
|
|
137
|
-
name: Install dependencies
|
|
138
|
-
command: |
|
|
139
|
-
npm install
|
|
140
|
-
- run:
|
|
141
|
-
name: Type-check generated SDK
|
|
142
|
-
command: |
|
|
143
|
-
npm run typecheck
|
|
144
|
-
|
|
145
|
-
update_npm_package:
|
|
146
|
-
docker:
|
|
147
|
-
- image: cimg/node:22.4.1
|
|
148
|
-
|
|
149
|
-
steps:
|
|
150
|
-
- checkout
|
|
151
|
-
- run:
|
|
152
|
-
name: Remove binaries
|
|
153
|
-
command: |
|
|
154
|
-
rm -rf goctl-swagger-amd
|
|
155
|
-
rm -rf openapi-generator-cli.jar
|
|
156
|
-
- run:
|
|
157
|
-
name: Publish npm package
|
|
158
|
-
command: |
|
|
159
|
-
VERSION=$(jq -r .version package.json)
|
|
160
|
-
if npm view "zklighter-perps@${VERSION}" version > /dev/null 2>&1; then
|
|
161
|
-
echo "zklighter-perps@${VERSION} is already published; skipping"
|
|
162
|
-
exit 0
|
|
163
|
-
fi
|
|
164
|
-
git config --global user.email "hasan@lighter.xyz"
|
|
165
|
-
git config --global user.name "CircleCI Hasan"
|
|
166
|
-
npm set //registry.npmjs.org/:_authToken=$NPM_TOKEN
|
|
167
|
-
npm publish
|
|
168
|
-
|
|
169
|
-
publish_prerelease:
|
|
170
|
-
docker:
|
|
171
|
-
- image: cimg/node:22.4.1
|
|
172
|
-
|
|
173
|
-
steps:
|
|
174
|
-
- checkout
|
|
175
|
-
- run:
|
|
176
|
-
name: Find open PR for branch
|
|
177
|
-
command: |
|
|
178
|
-
PR_NUMBER=$(curl -s -H "Authorization: Bearer ${GITHUB_TOKEN}" \
|
|
179
|
-
"https://api.github.com/repos/elliottech/zklighter-perps-ts/pulls?head=elliottech:${CIRCLE_BRANCH}&state=open" \
|
|
180
|
-
| jq -r '.[0].number // empty')
|
|
181
|
-
if [ -z "$PR_NUMBER" ]; then
|
|
182
|
-
echo "No open PR for branch ${CIRCLE_BRANCH}; skipping prerelease publish"
|
|
183
|
-
circleci-agent step halt
|
|
184
|
-
else
|
|
185
|
-
echo "Found PR #${PR_NUMBER}"
|
|
186
|
-
echo "export PR_NUMBER=${PR_NUMBER}" >> "$BASH_ENV"
|
|
187
|
-
fi
|
|
188
|
-
- run:
|
|
189
|
-
name: Generate prerelease version
|
|
190
|
-
command: |
|
|
191
|
-
CLEAN_BRANCH_NAME=$(echo "$CIRCLE_BRANCH" | sed 's/[^a-zA-Z0-9-]/-/g' | sed 's/--*/-/g' | sed 's/^-\|-$//g')
|
|
192
|
-
# npm rejects dist-tags that parse as a semver range (e.g. an
|
|
193
|
-
# all-numeric branch name), so prefix those.
|
|
194
|
-
if echo "$CLEAN_BRANCH_NAME" | grep -Eq '^[0-9]+$'; then
|
|
195
|
-
CLEAN_BRANCH_NAME="branch-${CLEAN_BRANCH_NAME}"
|
|
196
|
-
fi
|
|
197
|
-
CLEAN_ACTOR=$(echo "${CIRCLE_USERNAME:-circleci}" | sed 's/[^a-zA-Z0-9-]/-/g' | sed 's/--*/-/g' | sed 's/^-\|-$//g')
|
|
198
|
-
COMMIT_SHA=$(echo "$CIRCLE_SHA1" | cut -c1-7)
|
|
199
|
-
|
|
200
|
-
# Semver-compatible version: 0.PR_NUMBER.0-ACTOR.COMMIT_SHA.BRANCH_NAME
|
|
201
|
-
# Always < 1.0.0 so it can never shadow a real release.
|
|
202
|
-
PRERELEASE_VERSION="0.${PR_NUMBER}.0-${CLEAN_ACTOR}.${COMMIT_SHA}.${CLEAN_BRANCH_NAME}"
|
|
203
|
-
echo "Prerelease version: $PRERELEASE_VERSION"
|
|
204
|
-
|
|
205
|
-
echo "export CLEAN_BRANCH_NAME=${CLEAN_BRANCH_NAME}" >> "$BASH_ENV"
|
|
206
|
-
echo "export PRERELEASE_VERSION=${PRERELEASE_VERSION}" >> "$BASH_ENV"
|
|
207
|
-
- run:
|
|
208
|
-
name: Remove binaries
|
|
209
|
-
command: |
|
|
210
|
-
rm -rf goctl-swagger-amd
|
|
211
|
-
rm -rf openapi-generator-cli.jar
|
|
212
|
-
- run:
|
|
213
|
-
name: Publish prerelease npm package
|
|
214
|
-
command: |
|
|
215
|
-
jq --arg v "$PRERELEASE_VERSION" '.version = $v' package.json > tmp.json && mv tmp.json package.json
|
|
216
|
-
npm set //registry.npmjs.org/:_authToken=$NPM_TOKEN
|
|
217
|
-
npm publish --tag "$CLEAN_BRANCH_NAME"
|
|
218
|
-
- run:
|
|
219
|
-
name: Comment on PR
|
|
220
|
-
command: |
|
|
221
|
-
COMMENT_BODY=$(jq -n --arg version "$PRERELEASE_VERSION" --arg tag "$CLEAN_BRANCH_NAME" \
|
|
222
|
-
'{body: ("## 🚀 Prerelease Published\n\n**Version:** `" + $version + "`\n**Tag:** `" + $tag + "`\n\n### Update package.json:\n```json\n\"zklighter-perps\": \"" + $version + "\"\n```")}')
|
|
223
|
-
|
|
224
|
-
EXISTING_COMMENT_ID=$(curl -s -H "Authorization: Bearer ${GITHUB_TOKEN}" \
|
|
225
|
-
"https://api.github.com/repos/elliottech/zklighter-perps-ts/issues/${PR_NUMBER}/comments?per_page=100" \
|
|
226
|
-
| jq -r '[.[] | select(.body | contains("🚀 Prerelease Published"))][0].id // empty')
|
|
227
|
-
|
|
228
|
-
if [ -n "$EXISTING_COMMENT_ID" ]; then
|
|
229
|
-
curl -s -X PATCH -H "Authorization: Bearer ${GITHUB_TOKEN}" \
|
|
230
|
-
-d "$COMMENT_BODY" \
|
|
231
|
-
"https://api.github.com/repos/elliottech/zklighter-perps-ts/issues/comments/${EXISTING_COMMENT_ID}" > /dev/null
|
|
232
|
-
else
|
|
233
|
-
curl -s -X POST -H "Authorization: Bearer ${GITHUB_TOKEN}" \
|
|
234
|
-
-d "$COMMENT_BODY" \
|
|
235
|
-
"https://api.github.com/repos/elliottech/zklighter-perps-ts/issues/${PR_NUMBER}/comments" > /dev/null
|
|
236
|
-
fi
|
|
237
|
-
|
|
238
|
-
parameters:
|
|
239
|
-
update_ts_sdk:
|
|
240
|
-
default: false
|
|
241
|
-
type: boolean
|
|
242
|
-
BE_BRANCH:
|
|
243
|
-
type: string
|
|
244
|
-
default: "main"
|
|
245
|
-
|
|
246
|
-
workflows:
|
|
247
|
-
version: 2
|
|
248
|
-
update_ts_sdk:
|
|
249
|
-
when: << pipeline.parameters.update_ts_sdk >>
|
|
250
|
-
jobs:
|
|
251
|
-
- update_openapi:
|
|
252
|
-
filters:
|
|
253
|
-
branches:
|
|
254
|
-
only: main
|
|
255
|
-
- openapi_postprocess:
|
|
256
|
-
filters:
|
|
257
|
-
branches:
|
|
258
|
-
only: main
|
|
259
|
-
requires:
|
|
260
|
-
- update_openapi
|
|
261
|
-
- update_ts_sdk:
|
|
262
|
-
filters:
|
|
263
|
-
branches:
|
|
264
|
-
only: main
|
|
265
|
-
requires:
|
|
266
|
-
- openapi_postprocess
|
|
267
|
-
|
|
268
|
-
update_npm_package:
|
|
269
|
-
when:
|
|
270
|
-
not: << pipeline.parameters.update_ts_sdk >>
|
|
271
|
-
jobs:
|
|
272
|
-
# Runs on every branch (including the timestamped branches opened by the
|
|
273
|
-
# update_ts_sdk workflow) so a regenerated SDK that would break consumers
|
|
274
|
-
# fails its PR check before merge.
|
|
275
|
-
- typecheck
|
|
276
|
-
- update_npm_package:
|
|
277
|
-
filters:
|
|
278
|
-
branches:
|
|
279
|
-
only: main
|
|
280
|
-
requires:
|
|
281
|
-
- typecheck
|
|
282
|
-
# Publishes a PR prerelease (version 0.PR.0-actor.sha.branch, dist-tag =
|
|
283
|
-
# branch name) and posts/updates a PR comment with the version to use,
|
|
284
|
-
# mirroring the prerelease flow in zklighter-react-store.
|
|
285
|
-
- publish_prerelease:
|
|
286
|
-
filters:
|
|
287
|
-
branches:
|
|
288
|
-
ignore: main
|
|
289
|
-
requires:
|
|
290
|
-
- typecheck
|
|
291
|
-
|
|
@@ -1,366 +0,0 @@
|
|
|
1
|
-
"""Post-process the swagger/openapi.json before the TypeScript SDK is generated.
|
|
2
|
-
|
|
3
|
-
This is the single source of truth for every transformation applied to the
|
|
4
|
-
spec emitted by goctl-swagger. The raw spec has a number of quirks (empty keys,
|
|
5
|
-
non-standard int16 types, missing error responses, placeholder enum values,
|
|
6
|
-
auto-generated operation ids, etc.) that either break the OpenAPI Generator or
|
|
7
|
-
produce an awkward SDK. See README.md ("OpenAPI post-processing") for the
|
|
8
|
-
rationale behind each step.
|
|
9
|
-
|
|
10
|
-
Previously some of these fixes lived as inline `jq`/`sed` commands in the
|
|
11
|
-
`update_openapi` CI job. They have been consolidated here so the logic is in one
|
|
12
|
-
place, testable, and easy to reason about.
|
|
13
|
-
|
|
14
|
-
The steps below run in the same order they used to run in the pipeline:
|
|
15
|
-
the former `jq`/`sed` transforms first, then the original Python transforms.
|
|
16
|
-
"""
|
|
17
|
-
|
|
18
|
-
import json
|
|
19
|
-
|
|
20
|
-
FILE = "./openapi.json"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def walk(node, fn):
|
|
24
|
-
"""Apply ``fn`` to every node bottom-up, mirroring jq's ``walk``.
|
|
25
|
-
|
|
26
|
-
Children are transformed before their parent so ``fn`` always sees
|
|
27
|
-
already-processed sub-trees, matching the semantics of the jq commands
|
|
28
|
-
these helpers replaced.
|
|
29
|
-
"""
|
|
30
|
-
if isinstance(node, dict):
|
|
31
|
-
node = {key: walk(value, fn) for key, value in node.items()}
|
|
32
|
-
elif isinstance(node, list):
|
|
33
|
-
node = [walk(item, fn) for item in node]
|
|
34
|
-
return fn(node)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
with open(FILE, "r") as f:
|
|
38
|
-
data = json.load(f)
|
|
39
|
-
|
|
40
|
-
# ---------------------------------------------------------------------------
|
|
41
|
-
# Step 1. Drop endpoints/definitions that must not be part of the public SDK.
|
|
42
|
-
# (was: jq 'del(.paths[...], .definitions["ReqSendFeedback"])')
|
|
43
|
-
# ---------------------------------------------------------------------------
|
|
44
|
-
for dropped_path in [
|
|
45
|
-
"/api/v1/feedback",
|
|
46
|
-
"/api/v1/ws_status",
|
|
47
|
-
"/stream",
|
|
48
|
-
"/api/v1/permission",
|
|
49
|
-
]:
|
|
50
|
-
data.get("paths", {}).pop(dropped_path, None)
|
|
51
|
-
data.get("definitions", {}).pop("ReqSendFeedback", None)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
# ---------------------------------------------------------------------------
|
|
55
|
-
# Step 2. Remove empty-string keys emitted by the swagger generator, which the
|
|
56
|
-
# OpenAPI Generator cannot handle.
|
|
57
|
-
# (was: jq 'walk(... with_entries(select(.key != "")) ...)')
|
|
58
|
-
# ---------------------------------------------------------------------------
|
|
59
|
-
def _strip_empty_keys(node):
|
|
60
|
-
if isinstance(node, dict):
|
|
61
|
-
return {key: value for key, value in node.items() if key != ""}
|
|
62
|
-
return node
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
data = walk(data, _strip_empty_keys)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
# ---------------------------------------------------------------------------
|
|
69
|
-
# Step 3. Mirror `summary` into `description` so generated SDK doc comments keep
|
|
70
|
-
# the original human-readable text before `summary` is overwritten below.
|
|
71
|
-
# (was: jq 'walk(if has("summary") then .description = .summary end)')
|
|
72
|
-
# ---------------------------------------------------------------------------
|
|
73
|
-
def _summary_to_description(node):
|
|
74
|
-
if isinstance(node, dict) and "summary" in node:
|
|
75
|
-
node["description"] = node["summary"]
|
|
76
|
-
return node
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
data = walk(data, _summary_to_description)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
# ---------------------------------------------------------------------------
|
|
83
|
-
# Step 4. Seed `summary` from `operationId` (Step 8 may refine it per-path).
|
|
84
|
-
# (was: jq 'walk(if has("operationId") then .summary = .operationId end)')
|
|
85
|
-
# ---------------------------------------------------------------------------
|
|
86
|
-
def _operation_id_to_summary(node):
|
|
87
|
-
if isinstance(node, dict) and "operationId" in node:
|
|
88
|
-
node["summary"] = node["operationId"]
|
|
89
|
-
return node
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
data = walk(data, _operation_id_to_summary)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
# ---------------------------------------------------------------------------
|
|
96
|
-
# Step 5. Give every operation a documented 400 response referencing ResultCode.
|
|
97
|
-
# (was: jq 'walk(if has("responses") then .responses["400"] = {...} end)')
|
|
98
|
-
# ---------------------------------------------------------------------------
|
|
99
|
-
def _add_bad_request_response(node):
|
|
100
|
-
if isinstance(node, dict) and isinstance(node.get("responses"), dict):
|
|
101
|
-
node["responses"]["400"] = {
|
|
102
|
-
"description": "Bad request",
|
|
103
|
-
"schema": {"$ref": "#/definitions/ResultCode"},
|
|
104
|
-
}
|
|
105
|
-
return node
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
data = walk(data, _add_bad_request_response)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
# ---------------------------------------------------------------------------
|
|
112
|
-
# Step 6. Restore array request parameters from their request definitions. The
|
|
113
|
-
# generator preserves arrays in definitions but flattens them in path
|
|
114
|
-
# parameters.
|
|
115
|
-
# ---------------------------------------------------------------------------
|
|
116
|
-
def restore_array_parameters(data):
|
|
117
|
-
definitions = data.get("definitions", {})
|
|
118
|
-
|
|
119
|
-
for path_item in data.get("paths", {}).values():
|
|
120
|
-
for operation in path_item.values():
|
|
121
|
-
if not isinstance(operation, dict):
|
|
122
|
-
continue
|
|
123
|
-
|
|
124
|
-
request = definitions.get(f"Req{operation.get('operationId')}", {})
|
|
125
|
-
properties = request.get("properties", {})
|
|
126
|
-
|
|
127
|
-
for parameter in operation.get("parameters", []):
|
|
128
|
-
property_schema = properties.get(parameter.get("name"), {})
|
|
129
|
-
if (
|
|
130
|
-
property_schema.get("type") != "array"
|
|
131
|
-
or parameter.get("type") == "array"
|
|
132
|
-
):
|
|
133
|
-
continue
|
|
134
|
-
|
|
135
|
-
items = {"type": parameter["type"]}
|
|
136
|
-
if "format" in parameter:
|
|
137
|
-
items["format"] = parameter.pop("format")
|
|
138
|
-
if "enum" in parameter:
|
|
139
|
-
items["enum"] = parameter.pop("enum")
|
|
140
|
-
|
|
141
|
-
parameter["type"] = "array"
|
|
142
|
-
parameter["items"] = items
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
restore_array_parameters(data)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
# ---------------------------------------------------------------------------
|
|
149
|
-
# Step 7. Remove placeholder "-" values from enum/array lists.
|
|
150
|
-
# The former `sed 's/"-",//g'` only stripped a "-" element when it was
|
|
151
|
-
# followed by another element (i.e. not the last item); we preserve that
|
|
152
|
-
# behaviour here.
|
|
153
|
-
# ---------------------------------------------------------------------------
|
|
154
|
-
def _drop_dash_values(node):
|
|
155
|
-
if isinstance(node, list):
|
|
156
|
-
last_index = len(node) - 1
|
|
157
|
-
return [
|
|
158
|
-
value
|
|
159
|
-
for index, value in enumerate(node)
|
|
160
|
-
if not (value == "-" and index != last_index)
|
|
161
|
-
]
|
|
162
|
-
return node
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
data = walk(data, _drop_dash_values)
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
# ---------------------------------------------------------------------------
|
|
169
|
-
# Step 8. Derive stable, path-based operationId/summary so generated method
|
|
170
|
-
# names are predictable (e.g. /api/v1/account -> "account").
|
|
171
|
-
# ---------------------------------------------------------------------------
|
|
172
|
-
for path in data["paths"]:
|
|
173
|
-
methods = list(data["paths"][path].keys())
|
|
174
|
-
has_multiple_methods = len(methods) > 1
|
|
175
|
-
|
|
176
|
-
for method in methods:
|
|
177
|
-
if "api/v1/" in path:
|
|
178
|
-
base_name = path.split("api/v1/")[1].replace("/", "_")
|
|
179
|
-
data["paths"][path][method]["summary"] = base_name
|
|
180
|
-
if has_multiple_methods:
|
|
181
|
-
data["paths"][path][method]["operationId"] = f"{base_name}_{method}"
|
|
182
|
-
else:
|
|
183
|
-
data["paths"][path][method]["operationId"] = base_name
|
|
184
|
-
elif "api/v2/" in path:
|
|
185
|
-
base_name = path.split("api/v2/")[1].replace("/", "_") + "_v2"
|
|
186
|
-
data["paths"][path][method]["summary"] = base_name
|
|
187
|
-
if has_multiple_methods:
|
|
188
|
-
data["paths"][path][method]["operationId"] = f"{base_name}_{method}"
|
|
189
|
-
else:
|
|
190
|
-
data["paths"][path][method]["operationId"] = base_name
|
|
191
|
-
else:
|
|
192
|
-
base_name = path.split("/")[-1]
|
|
193
|
-
data["paths"][path][method]["summary"] = base_name
|
|
194
|
-
if has_multiple_methods:
|
|
195
|
-
data["paths"][path][method]["operationId"] = f"{base_name}_{method}"
|
|
196
|
-
else:
|
|
197
|
-
data["paths"][path][method]["operationId"] = base_name
|
|
198
|
-
|
|
199
|
-
if data["paths"][path][method]["summary"] == "":
|
|
200
|
-
data["paths"][path][method]["summary"] = "status"
|
|
201
|
-
if has_multiple_methods:
|
|
202
|
-
data["paths"][path][method]["operationId"] = f"status_{method}"
|
|
203
|
-
else:
|
|
204
|
-
data["paths"][path][method]["operationId"] = "status"
|
|
205
|
-
|
|
206
|
-
# Replace $ref to int16/float64 types with inline equivalents across all
|
|
207
|
-
# definitions. int16, float64 and derived map types are not standard OpenAPI
|
|
208
|
-
# and cause the generator to emit broken model references.
|
|
209
|
-
def replace_int16_refs(obj):
|
|
210
|
-
if isinstance(obj, dict):
|
|
211
|
-
if obj.get("$ref") == "#/definitions/int16":
|
|
212
|
-
return {"type": "integer", "format": "int64"}
|
|
213
|
-
if obj.get("$ref") == "#/definitions/float64":
|
|
214
|
-
return {"type": "number", "format": "double"}
|
|
215
|
-
if obj.get("$ref") == "#/definitions/mapint16string":
|
|
216
|
-
return {"type": "object", "additionalProperties": {"type": "string"}}
|
|
217
|
-
if obj.get("$ref") == "#/definitions/mapstringfloat64":
|
|
218
|
-
return {"type": "object", "additionalProperties": {"type": "number", "format": "double"}}
|
|
219
|
-
return {k: replace_int16_refs(v) for k, v in obj.items()}
|
|
220
|
-
if isinstance(obj, list):
|
|
221
|
-
return [replace_int16_refs(i) for i in obj]
|
|
222
|
-
return obj
|
|
223
|
-
|
|
224
|
-
for defn_name in list(data["definitions"]):
|
|
225
|
-
data["definitions"][defn_name] = replace_int16_refs(
|
|
226
|
-
data["definitions"][defn_name]
|
|
227
|
-
)
|
|
228
|
-
|
|
229
|
-
# Fix enum placement for array types: move enum from array level into items
|
|
230
|
-
for defn in data["definitions"].values():
|
|
231
|
-
for prop in defn.get("properties", {}).values():
|
|
232
|
-
if prop.get("type") == "array" and "enum" in prop:
|
|
233
|
-
prop["items"]["enum"] = prop.pop("enum")
|
|
234
|
-
|
|
235
|
-
# goctl-swagger does not preserve Go pointer types. Restore nullability for
|
|
236
|
-
# stock-financial fields that are always present but may contain JSON null.
|
|
237
|
-
nullable_properties = {
|
|
238
|
-
"StockBalanceSheet": {
|
|
239
|
-
"cash_and_cash_equivalents",
|
|
240
|
-
"total_assets",
|
|
241
|
-
"total_liabilities",
|
|
242
|
-
"total_equity",
|
|
243
|
-
"total_debt",
|
|
244
|
-
"net_debt",
|
|
245
|
-
},
|
|
246
|
-
"StockCashFlowStatement": {
|
|
247
|
-
"operating_cash_flow",
|
|
248
|
-
"capital_expenditure",
|
|
249
|
-
"free_cash_flow",
|
|
250
|
-
},
|
|
251
|
-
"StockFinancialEarningsEvent": {
|
|
252
|
-
"eps_estimated",
|
|
253
|
-
"revenue_estimated",
|
|
254
|
-
},
|
|
255
|
-
"StockFinancialHistoricalEarning": {
|
|
256
|
-
"eps_estimated",
|
|
257
|
-
"eps_actual",
|
|
258
|
-
"revenue_estimated",
|
|
259
|
-
"revenue_actual",
|
|
260
|
-
},
|
|
261
|
-
"StockFinancialProfile": {"market_cap"},
|
|
262
|
-
"StockIncomeStatement": {
|
|
263
|
-
"revenue",
|
|
264
|
-
"gross_profit",
|
|
265
|
-
"operating_income",
|
|
266
|
-
"ebitda",
|
|
267
|
-
"net_income",
|
|
268
|
-
"eps",
|
|
269
|
-
"eps_diluted",
|
|
270
|
-
},
|
|
271
|
-
"UpcomingEarning": {
|
|
272
|
-
"eps_estimated",
|
|
273
|
-
"revenue_estimated",
|
|
274
|
-
},
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
for definition_name, property_names in nullable_properties.items():
|
|
278
|
-
properties = (
|
|
279
|
-
data["definitions"].get(definition_name, {}).get("properties", {})
|
|
280
|
-
)
|
|
281
|
-
for property_name in property_names:
|
|
282
|
-
if property_name in properties:
|
|
283
|
-
properties[property_name]["x-nullable"] = True
|
|
284
|
-
|
|
285
|
-
# These fields use `omitempty` in server.api and are absent when FMP has no
|
|
286
|
-
# value. They are optional rather than nullable in the generated SDK.
|
|
287
|
-
optional_properties = {
|
|
288
|
-
"RespStockFinancials": {"stock_financials"},
|
|
289
|
-
"StockFinancialEarnings": {"history"},
|
|
290
|
-
"StockFinancialEarningsEvent": {"timing"},
|
|
291
|
-
"StockFinancialPeriod": {"reported_currency"},
|
|
292
|
-
"StockFinancialProfile": {
|
|
293
|
-
"currency",
|
|
294
|
-
"exchange",
|
|
295
|
-
"industry",
|
|
296
|
-
"sector",
|
|
297
|
-
"country",
|
|
298
|
-
},
|
|
299
|
-
"StockFinancialStatements": {"annual", "quarterly"},
|
|
300
|
-
"Token": {"backend_symbol"},
|
|
301
|
-
"UpcomingEarning": {"currency", "timing"},
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
for path in data["definitions"]:
|
|
305
|
-
if not path.startswith("Req"):
|
|
306
|
-
required_fields = list(data["definitions"][path]["properties"].keys())
|
|
307
|
-
if "message" in required_fields:
|
|
308
|
-
required_fields.remove("message")
|
|
309
|
-
|
|
310
|
-
if "next" in required_fields:
|
|
311
|
-
required_fields.remove("next")
|
|
312
|
-
|
|
313
|
-
if "next_cursor" in required_fields:
|
|
314
|
-
required_fields.remove("next_cursor")
|
|
315
|
-
|
|
316
|
-
if "account_share" in required_fields:
|
|
317
|
-
required_fields.remove("account_share")
|
|
318
|
-
|
|
319
|
-
if "total_funding_paid_out" in required_fields:
|
|
320
|
-
required_fields.remove("total_funding_paid_out")
|
|
321
|
-
|
|
322
|
-
if "pending_unlocks" in required_fields:
|
|
323
|
-
required_fields.remove("pending_unlocks")
|
|
324
|
-
|
|
325
|
-
if "account_trading_mode" in required_fields:
|
|
326
|
-
required_fields.remove("account_trading_mode")
|
|
327
|
-
|
|
328
|
-
if "funding_fee_discounts_enabled" in required_fields:
|
|
329
|
-
required_fields.remove("funding_fee_discounts_enabled")
|
|
330
|
-
|
|
331
|
-
if "hidden" in required_fields:
|
|
332
|
-
required_fields.remove("hidden")
|
|
333
|
-
|
|
334
|
-
if "approved_integrators" in required_fields:
|
|
335
|
-
required_fields.remove("approved_integrators")
|
|
336
|
-
|
|
337
|
-
if "ask_id_str" in required_fields:
|
|
338
|
-
required_fields.remove("ask_id_str")
|
|
339
|
-
|
|
340
|
-
if "bid_id_str" in required_fields:
|
|
341
|
-
required_fields.remove("bid_id_str")
|
|
342
|
-
|
|
343
|
-
if "market_maker_incentive_account_index" in required_fields:
|
|
344
|
-
required_fields.remove("market_maker_incentive_account_index")
|
|
345
|
-
|
|
346
|
-
if "user_tier_last_update" in required_fields:
|
|
347
|
-
required_fields.remove("user_tier_last_update")
|
|
348
|
-
|
|
349
|
-
if path == "Trade":
|
|
350
|
-
if "taker_fee" in required_fields:
|
|
351
|
-
required_fields.remove("taker_fee")
|
|
352
|
-
|
|
353
|
-
if "maker_fee" in required_fields:
|
|
354
|
-
required_fields.remove("maker_fee")
|
|
355
|
-
|
|
356
|
-
for field in optional_properties.get(path, set()):
|
|
357
|
-
if field in required_fields:
|
|
358
|
-
required_fields.remove(field)
|
|
359
|
-
|
|
360
|
-
if len(required_fields) > 0:
|
|
361
|
-
data["definitions"][path]["required"] = required_fields
|
|
362
|
-
else:
|
|
363
|
-
data["definitions"][path].pop("required", None)
|
|
364
|
-
|
|
365
|
-
with open(FILE, "w") as f:
|
|
366
|
-
json.dump(data, f, indent=2)
|