@temple-digital-group/temple-canton-js 1.0.39-beta.6 → 2.0.0-beta.1
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/README.md +4 -13
- package/dist/api/index.d.ts +5 -25
- package/dist/api/index.js +11 -99
- package/dist/api/tokenStore.d.ts +7 -23
- package/dist/api/tokenStore.js +7 -47
- package/dist/api/types.d.ts +0 -23
- package/dist/api/types.js +1 -1
- package/package.json +1 -1
- package/src/api/index.ts +12 -115
- package/src/api/tokenStore.ts +8 -52
- package/src/api/types.ts +1 -30
package/README.md
CHANGED
|
@@ -40,12 +40,7 @@ setWalletAdapter(loop);
|
|
|
40
40
|
| ---------------- | -------- | --------------------------------------------------------------- |
|
|
41
41
|
| `NETWORK` | Yes | `mainnet`, `testnet`, or `localhost` |
|
|
42
42
|
| `WALLET_ADAPTER` | Yes | Loop SDK instance — auto-detects server/client mode for signing |
|
|
43
|
-
| `
|
|
44
|
-
| `API_PASSWORD` | No | Temple REST API password (required with `API_EMAIL`) |
|
|
45
|
-
|
|
46
|
-
> You can optionally pass `API_EMAIL`/`API_PASSWORD` to authenticate with the REST API at init time.
|
|
47
|
-
|
|
48
|
-
> **Legacy:** `initializeConfig()` is still available as a sync-only alternative (no REST API auth). `initialize()` is the recommended approach.
|
|
43
|
+
| `API_KEY` | No | Temple REST API key for authenticated endpoints |
|
|
49
44
|
|
|
50
45
|
## Supported Instruments
|
|
51
46
|
|
|
@@ -301,21 +296,17 @@ const counts = await getUtxoCount(partyId, "USDCx", walletProvider);
|
|
|
301
296
|
| ------------------------------------------------------------------------------------------ | -------- | ------------------------------ |
|
|
302
297
|
| `mergeAmuletHoldingsForParty(party, returnCommand, provider, maxUtxos, amuletDisclosures)` | **W** | Merge Amulet holdings into one |
|
|
303
298
|
| `mergeUtilityHoldingsForParty(party, utilityAsset, returnCommand, provider, maxUtxos)` | **W** | Merge utility holdings into one |
|
|
304
|
-
| `splitAmuletHoldingForParty(party, outputQuantity)` | | Split an Amulet holding |
|
|
305
|
-
| `unlockLockedAmulets(party)` | | Unlock locked Amulet holdings |
|
|
306
299
|
|
|
307
300
|
### Temple REST API
|
|
308
301
|
|
|
309
|
-
> These functions call the Temple REST API. Pass `
|
|
302
|
+
> These functions call the Temple REST API. Pass `API_KEY` in `initialize()` or call `setApiKey()` to authenticate.
|
|
310
303
|
|
|
311
304
|
#### Auth
|
|
312
305
|
|
|
313
306
|
| Function | Description |
|
|
314
307
|
| ----------------------------------- | --------------------------------------------------- |
|
|
315
|
-
| `
|
|
316
|
-
| `
|
|
317
|
-
| `logout()` | Clear stored tokens |
|
|
318
|
-
| `getUserId()` | Get the stored user ID from login |
|
|
308
|
+
| `setApiKey(key)` | Set the API key for REST API authentication |
|
|
309
|
+
| `getUserId()` | Get the stored user ID |
|
|
319
310
|
|
|
320
311
|
#### Market Data
|
|
321
312
|
|
package/dist/api/index.d.ts
CHANGED
|
@@ -1,32 +1,13 @@
|
|
|
1
|
-
import type { ApiError,
|
|
2
|
-
export type { ApiError,
|
|
1
|
+
import type { ApiError, Ticker, OrderBook, OrderBookOptions, SymbolConfig, OpenInterest, Trade, RecentTradesOptions, ActiveOrder, ActiveOrdersOptions, CancelOrderResponse, CancelAllOrdersOptions, CancelAllOrdersResponse, CreateOrderRequestOpts, CreateOrderRequestResponse, DelegationResponse, WithdrawalResponse, WithdrawalStatusResponse, TradingBalanceResponse, AmuletDisclosure, DisclosuresResponse } from "./types.js";
|
|
2
|
+
export type { ApiError, Ticker, OrderBook, OrderBookOptions, SymbolConfig, OpenInterest, Trade, RecentTradesOptions, ActiveOrder, ActiveOrdersOptions, CancelOrderResponse, CancelAllOrdersOptions, CancelAllOrdersResponse, CreateOrderRequestResponse, DelegationResponse, WithdrawalResponse, WithdrawalStatusResponse, TradingBalanceResponse, AmuletDisclosure, DisclosuresResponse, };
|
|
3
3
|
export { setApiKey, getUserId } from "./tokenStore.js";
|
|
4
4
|
export { setWalletAdapter } from "../../src/config/index.js";
|
|
5
5
|
/**
|
|
6
|
-
* Initialize the Temple SDK — sets config and
|
|
7
|
-
* Pass `API_EMAIL`/`API_PASSWORD` or `API_KEY` to authenticate eagerly at init time.
|
|
6
|
+
* Initialize the Temple SDK — sets config and authenticates with the REST API via API key.
|
|
8
7
|
*
|
|
9
|
-
* @returns
|
|
10
|
-
* Returns `null` if no API credentials were provided (config-only init).
|
|
8
|
+
* @returns null (config-only init). Throws no errors.
|
|
11
9
|
*/
|
|
12
|
-
export declare function initialize(cfg: Record<string, unknown>): Promise<
|
|
13
|
-
/**
|
|
14
|
-
* Login to the Temple REST API with email and password.
|
|
15
|
-
* Stores tokens automatically for subsequent API calls.
|
|
16
|
-
* @param email - User email
|
|
17
|
-
* @param password - User password
|
|
18
|
-
*/
|
|
19
|
-
export declare function login(email: string, password: string): Promise<LoginResponse | ApiError>;
|
|
20
|
-
/**
|
|
21
|
-
* Refresh the access token using the stored or provided refresh token.
|
|
22
|
-
* Updates the token store automatically on success.
|
|
23
|
-
* @param refreshTokenOverride - Optional explicit refresh token (uses stored one if omitted)
|
|
24
|
-
*/
|
|
25
|
-
export declare function refreshAccessToken(refreshTokenOverride?: string): Promise<RefreshResponse | ApiError>;
|
|
26
|
-
/**
|
|
27
|
-
* Logout: clear all stored REST API tokens.
|
|
28
|
-
*/
|
|
29
|
-
export declare function logout(): void;
|
|
10
|
+
export declare function initialize(cfg: Record<string, unknown>): Promise<null>;
|
|
30
11
|
/**
|
|
31
12
|
* Get ticker data for one or all trading pairs.
|
|
32
13
|
* @param symbol - Optional symbol filter (e.g., "Amulet/USDCx")
|
|
@@ -77,7 +58,6 @@ export declare function cancelAllOrders(options?: CancelAllOrdersOptions): Promi
|
|
|
77
58
|
export declare function getDisclosures(partyId: string): Promise<DisclosuresResponse | ApiError>;
|
|
78
59
|
/**
|
|
79
60
|
* Get the user's trading delegation status.
|
|
80
|
-
* The user ID is extracted from the JWT token automatically.
|
|
81
61
|
*/
|
|
82
62
|
export declare function getDelegation(): Promise<DelegationResponse | ApiError>;
|
|
83
63
|
/**
|
package/dist/api/index.js
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
2
|
import config, { initializeConfig, setWalletAdapter } from "../../src/config/index.js";
|
|
3
|
-
import {
|
|
3
|
+
import { getApiKey, setApiKey as setApiKeyFromConfig, getAuthHeader, setUserId, } from "./tokenStore.js";
|
|
4
4
|
export { setApiKey, getUserId } from "./tokenStore.js";
|
|
5
5
|
export { setWalletAdapter } from "../../src/config/index.js";
|
|
6
6
|
// ── Initialization ──
|
|
7
7
|
/**
|
|
8
|
-
* Initialize the Temple SDK — sets config and
|
|
9
|
-
* Pass `API_EMAIL`/`API_PASSWORD` or `API_KEY` to authenticate eagerly at init time.
|
|
8
|
+
* Initialize the Temple SDK — sets config and authenticates with the REST API via API key.
|
|
10
9
|
*
|
|
11
|
-
* @returns
|
|
12
|
-
* Returns `null` if no API credentials were provided (config-only init).
|
|
10
|
+
* @returns null (config-only init). Throws no errors.
|
|
13
11
|
*/
|
|
14
12
|
export async function initialize(cfg) {
|
|
15
13
|
initializeConfig(cfg);
|
|
@@ -19,18 +17,14 @@ export async function initialize(cfg) {
|
|
|
19
17
|
const apiKey = cfg.API_KEY;
|
|
20
18
|
if (apiKey) {
|
|
21
19
|
setApiKeyFromConfig(apiKey);
|
|
22
|
-
return null;
|
|
23
20
|
}
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return login(email, password);
|
|
21
|
+
const userIdValue = cfg.USER_ID;
|
|
22
|
+
if (userIdValue) {
|
|
23
|
+
setUserId(userIdValue);
|
|
28
24
|
}
|
|
29
25
|
return null;
|
|
30
26
|
}
|
|
31
27
|
// ── Internal helpers ──
|
|
32
|
-
/** Pending auto-login promise for dedup. */
|
|
33
|
-
let autoLoginPromise = null;
|
|
34
28
|
function handleApiError(error, context) {
|
|
35
29
|
const err = error;
|
|
36
30
|
const status = err.response?.status ?? null;
|
|
@@ -42,49 +36,18 @@ function handleApiError(error, context) {
|
|
|
42
36
|
console.error(`[Temple API] ${context}: ${message}${status ? ` (HTTP ${status})` : ""}`);
|
|
43
37
|
return { error: true, status, code, message };
|
|
44
38
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
async function ensureAuthenticated() {
|
|
48
|
-
// API key takes priority — no login needed
|
|
39
|
+
function ensureAuthenticated() {
|
|
40
|
+
// API key from config if not already set
|
|
49
41
|
const configApiKey = config.API_KEY;
|
|
50
42
|
if (!getApiKey() && configApiKey) {
|
|
51
43
|
setApiKeyFromConfig(configApiKey);
|
|
52
44
|
}
|
|
53
45
|
if (getApiKey())
|
|
54
46
|
return null;
|
|
55
|
-
|
|
56
|
-
if (!getAccessToken()) {
|
|
57
|
-
const email = config.API_EMAIL;
|
|
58
|
-
const password = config.API_PASSWORD;
|
|
59
|
-
if (email && password) {
|
|
60
|
-
if (!autoLoginPromise) {
|
|
61
|
-
autoLoginPromise = login(email, password).finally(() => {
|
|
62
|
-
autoLoginPromise = null;
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
const result = await autoLoginPromise;
|
|
66
|
-
if ("error" in result && result.error)
|
|
67
|
-
return result;
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
return { error: true, status: 401, code: "NOT_AUTHENTICATED", message: "Not logged in. Call login() or provide API_EMAIL/API_PASSWORD in config." };
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
// Auto-refresh if expired
|
|
74
|
-
if (isTokenExpired()) {
|
|
75
|
-
if (!refreshPromise) {
|
|
76
|
-
refreshPromise = refreshAccessToken().finally(() => {
|
|
77
|
-
refreshPromise = null;
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
const result = await refreshPromise;
|
|
81
|
-
if ("error" in result && result.error)
|
|
82
|
-
return result;
|
|
83
|
-
}
|
|
84
|
-
return null;
|
|
47
|
+
return { error: true, status: 401, code: "NOT_AUTHENTICATED", message: "API key required. Pass API_KEY in initialize() or call setApiKey()." };
|
|
85
48
|
}
|
|
86
49
|
async function authenticatedGet(path, params) {
|
|
87
|
-
const authError =
|
|
50
|
+
const authError = ensureAuthenticated();
|
|
88
51
|
if (authError)
|
|
89
52
|
return authError;
|
|
90
53
|
const headers = {
|
|
@@ -111,7 +74,7 @@ async function authenticatedGet(path, params) {
|
|
|
111
74
|
}
|
|
112
75
|
}
|
|
113
76
|
async function authenticatedPost(path, body) {
|
|
114
|
-
const authError =
|
|
77
|
+
const authError = ensureAuthenticated();
|
|
115
78
|
if (authError)
|
|
116
79
|
return authError;
|
|
117
80
|
const headers = {
|
|
@@ -126,56 +89,6 @@ async function authenticatedPost(path, body) {
|
|
|
126
89
|
return handleApiError(error, `POST ${path}`);
|
|
127
90
|
}
|
|
128
91
|
}
|
|
129
|
-
// ── Auth ──
|
|
130
|
-
/**
|
|
131
|
-
* Login to the Temple REST API with email and password.
|
|
132
|
-
* Stores tokens automatically for subsequent API calls.
|
|
133
|
-
* @param email - User email
|
|
134
|
-
* @param password - User password
|
|
135
|
-
*/
|
|
136
|
-
export async function login(email, password) {
|
|
137
|
-
if (!email || !password) {
|
|
138
|
-
return { error: true, status: null, code: "INVALID_PARAMS", message: "Email and password are required." };
|
|
139
|
-
}
|
|
140
|
-
try {
|
|
141
|
-
const response = await axios.post(`${config.API_BASE_URL}/auth/login`, {
|
|
142
|
-
email,
|
|
143
|
-
password,
|
|
144
|
-
});
|
|
145
|
-
setTokens(response.data);
|
|
146
|
-
return response.data;
|
|
147
|
-
}
|
|
148
|
-
catch (error) {
|
|
149
|
-
return handleApiError(error, "login");
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* Refresh the access token using the stored or provided refresh token.
|
|
154
|
-
* Updates the token store automatically on success.
|
|
155
|
-
* @param refreshTokenOverride - Optional explicit refresh token (uses stored one if omitted)
|
|
156
|
-
*/
|
|
157
|
-
export async function refreshAccessToken(refreshTokenOverride) {
|
|
158
|
-
const token = refreshTokenOverride ?? getRefreshToken();
|
|
159
|
-
if (!token) {
|
|
160
|
-
return { error: true, status: null, code: "NO_REFRESH_TOKEN", message: "No refresh token available. Call login() first." };
|
|
161
|
-
}
|
|
162
|
-
try {
|
|
163
|
-
const response = await axios.post(`${config.API_BASE_URL}/auth/refresh`, {
|
|
164
|
-
refresh_token: token,
|
|
165
|
-
});
|
|
166
|
-
setTokens(response.data);
|
|
167
|
-
return response.data;
|
|
168
|
-
}
|
|
169
|
-
catch (error) {
|
|
170
|
-
return handleApiError(error, "refreshAccessToken");
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Logout: clear all stored REST API tokens.
|
|
175
|
-
*/
|
|
176
|
-
export function logout() {
|
|
177
|
-
clearTokens();
|
|
178
|
-
}
|
|
179
92
|
// ── Helpers ──
|
|
180
93
|
/** Normalize CC → Amulet in symbol strings (e.g. "CC/SBC" → "Amulet/SBC", "CC" → "Amulet") */
|
|
181
94
|
function normalizeSymbol(symbol) {
|
|
@@ -281,7 +194,6 @@ export async function getDisclosures(partyId) {
|
|
|
281
194
|
// ── Delegation ──
|
|
282
195
|
/**
|
|
283
196
|
* Get the user's trading delegation status.
|
|
284
|
-
* The user ID is extracted from the JWT token automatically.
|
|
285
197
|
*/
|
|
286
198
|
export async function getDelegation() {
|
|
287
199
|
return authenticatedGet("/api/trading/delegation");
|
package/dist/api/tokenStore.d.ts
CHANGED
|
@@ -1,30 +1,14 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AuthHeaders } from "./types.js";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*/
|
|
5
|
-
export declare function setTokens(data: TokenData): void;
|
|
6
|
-
/**
|
|
7
|
-
* Get the current access token, or null if not logged in.
|
|
8
|
-
*/
|
|
9
|
-
export declare function getAccessToken(): string | null;
|
|
10
|
-
/**
|
|
11
|
-
* Get the stored refresh token, or null if not logged in.
|
|
12
|
-
*/
|
|
13
|
-
export declare function getRefreshToken(): string | null;
|
|
14
|
-
/**
|
|
15
|
-
* Check if the current access token is expired (with 60-second buffer).
|
|
16
|
-
*/
|
|
17
|
-
export declare function isTokenExpired(): boolean;
|
|
18
|
-
/**
|
|
19
|
-
* Get the stored user ID from login, or null if not logged in.
|
|
3
|
+
* Get the stored user ID, or null if not set.
|
|
20
4
|
*/
|
|
21
5
|
export declare function getUserId(): string | null;
|
|
22
6
|
/**
|
|
23
|
-
*
|
|
7
|
+
* Set the user ID directly (e.g. from config at init time).
|
|
24
8
|
*/
|
|
25
|
-
export declare function
|
|
9
|
+
export declare function setUserId(id: string): void;
|
|
26
10
|
/**
|
|
27
|
-
* Set an API key for authentication
|
|
11
|
+
* Set an API key for authentication.
|
|
28
12
|
*/
|
|
29
13
|
export declare function setApiKey(key: string): void;
|
|
30
14
|
/**
|
|
@@ -32,7 +16,7 @@ export declare function setApiKey(key: string): void;
|
|
|
32
16
|
*/
|
|
33
17
|
export declare function getApiKey(): string | null;
|
|
34
18
|
/**
|
|
35
|
-
* Get the authorization header
|
|
36
|
-
* Returns null if
|
|
19
|
+
* Get the authorization header using the API key.
|
|
20
|
+
* Returns null if no API key is set.
|
|
37
21
|
*/
|
|
38
22
|
export declare function getAuthHeader(): AuthHeaders | null;
|
package/dist/api/tokenStore.js
CHANGED
|
@@ -1,56 +1,19 @@
|
|
|
1
|
-
let accessToken = null;
|
|
2
|
-
let refreshToken = null;
|
|
3
|
-
let tokenExpiryTime = null;
|
|
4
1
|
let apiKey = null;
|
|
5
2
|
let userId = null;
|
|
6
3
|
/**
|
|
7
|
-
*
|
|
8
|
-
*/
|
|
9
|
-
export function setTokens(data) {
|
|
10
|
-
accessToken = data.access_token;
|
|
11
|
-
refreshToken = data.refresh_token;
|
|
12
|
-
tokenExpiryTime = Date.now() + data.expires_in * 1000;
|
|
13
|
-
if (data.user?.user_id != null) {
|
|
14
|
-
userId = String(data.user.user_id);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Get the current access token, or null if not logged in.
|
|
19
|
-
*/
|
|
20
|
-
export function getAccessToken() {
|
|
21
|
-
return accessToken;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Get the stored refresh token, or null if not logged in.
|
|
25
|
-
*/
|
|
26
|
-
export function getRefreshToken() {
|
|
27
|
-
return refreshToken;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Check if the current access token is expired (with 60-second buffer).
|
|
31
|
-
*/
|
|
32
|
-
export function isTokenExpired() {
|
|
33
|
-
if (!tokenExpiryTime)
|
|
34
|
-
return true;
|
|
35
|
-
return Date.now() >= tokenExpiryTime - 60000;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Get the stored user ID from login, or null if not logged in.
|
|
4
|
+
* Get the stored user ID, or null if not set.
|
|
39
5
|
*/
|
|
40
6
|
export function getUserId() {
|
|
41
7
|
return userId;
|
|
42
8
|
}
|
|
43
9
|
/**
|
|
44
|
-
*
|
|
10
|
+
* Set the user ID directly (e.g. from config at init time).
|
|
45
11
|
*/
|
|
46
|
-
export function
|
|
47
|
-
|
|
48
|
-
refreshToken = null;
|
|
49
|
-
tokenExpiryTime = null;
|
|
50
|
-
userId = null;
|
|
12
|
+
export function setUserId(id) {
|
|
13
|
+
userId = id;
|
|
51
14
|
}
|
|
52
15
|
/**
|
|
53
|
-
* Set an API key for authentication
|
|
16
|
+
* Set an API key for authentication.
|
|
54
17
|
*/
|
|
55
18
|
export function setApiKey(key) {
|
|
56
19
|
apiKey = key;
|
|
@@ -62,15 +25,12 @@ export function getApiKey() {
|
|
|
62
25
|
return apiKey;
|
|
63
26
|
}
|
|
64
27
|
/**
|
|
65
|
-
* Get the authorization header
|
|
66
|
-
* Returns null if
|
|
28
|
+
* Get the authorization header using the API key.
|
|
29
|
+
* Returns null if no API key is set.
|
|
67
30
|
*/
|
|
68
31
|
export function getAuthHeader() {
|
|
69
32
|
if (apiKey) {
|
|
70
33
|
return { Authorization: `Bearer ${apiKey}` };
|
|
71
34
|
}
|
|
72
|
-
if (accessToken) {
|
|
73
|
-
return { Authorization: `Bearer ${accessToken}` };
|
|
74
|
-
}
|
|
75
35
|
return null;
|
|
76
36
|
}
|
package/dist/api/types.d.ts
CHANGED
|
@@ -1,20 +1,3 @@
|
|
|
1
|
-
export interface LoginUser {
|
|
2
|
-
user_id: number;
|
|
3
|
-
max_limit_orders: number;
|
|
4
|
-
max_market_orders: number;
|
|
5
|
-
}
|
|
6
|
-
export interface LoginResponse {
|
|
7
|
-
access_token: string;
|
|
8
|
-
refresh_token: string;
|
|
9
|
-
expires_in: number;
|
|
10
|
-
token_type: string;
|
|
11
|
-
user: LoginUser;
|
|
12
|
-
}
|
|
13
|
-
export interface RefreshResponse {
|
|
14
|
-
access_token: string;
|
|
15
|
-
refresh_token: string;
|
|
16
|
-
expires_in: number;
|
|
17
|
-
}
|
|
18
1
|
export interface Ticker {
|
|
19
2
|
symbol: string;
|
|
20
3
|
last_price: string;
|
|
@@ -161,12 +144,6 @@ export interface ApiError {
|
|
|
161
144
|
code: string | null;
|
|
162
145
|
message: string;
|
|
163
146
|
}
|
|
164
|
-
export interface TokenData {
|
|
165
|
-
access_token: string;
|
|
166
|
-
refresh_token: string;
|
|
167
|
-
expires_in: number;
|
|
168
|
-
user?: LoginUser;
|
|
169
|
-
}
|
|
170
147
|
export interface AuthHeaders {
|
|
171
148
|
Authorization: string;
|
|
172
149
|
}
|
package/dist/api/types.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
// ──
|
|
1
|
+
// ── Market Data ──
|
|
2
2
|
export {};
|
package/package.json
CHANGED
package/src/api/index.ts
CHANGED
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
import axios, { type AxiosRequestConfig } from "axios";
|
|
2
2
|
import config, { initializeConfig, setWalletAdapter } from "../../src/config/index.js";
|
|
3
3
|
import {
|
|
4
|
-
setTokens,
|
|
5
|
-
getAccessToken,
|
|
6
|
-
getRefreshToken,
|
|
7
4
|
getApiKey,
|
|
8
5
|
setApiKey as setApiKeyFromConfig,
|
|
9
|
-
isTokenExpired,
|
|
10
|
-
clearTokens,
|
|
11
6
|
getAuthHeader,
|
|
7
|
+
setUserId,
|
|
12
8
|
} from "./tokenStore.js";
|
|
13
9
|
import type {
|
|
14
10
|
ApiError,
|
|
15
|
-
LoginUser,
|
|
16
|
-
LoginResponse,
|
|
17
|
-
RefreshResponse,
|
|
18
11
|
Ticker,
|
|
19
12
|
OrderBook,
|
|
20
13
|
OrderBookOptions,
|
|
@@ -40,9 +33,6 @@ import type {
|
|
|
40
33
|
// Re-export types and token utilities consumers may need
|
|
41
34
|
export type {
|
|
42
35
|
ApiError,
|
|
43
|
-
LoginUser,
|
|
44
|
-
LoginResponse,
|
|
45
|
-
RefreshResponse,
|
|
46
36
|
Ticker,
|
|
47
37
|
OrderBook,
|
|
48
38
|
OrderBookOptions,
|
|
@@ -69,13 +59,11 @@ export { setWalletAdapter } from "../../src/config/index.js";
|
|
|
69
59
|
// ── Initialization ──
|
|
70
60
|
|
|
71
61
|
/**
|
|
72
|
-
* Initialize the Temple SDK — sets config and
|
|
73
|
-
* Pass `API_EMAIL`/`API_PASSWORD` or `API_KEY` to authenticate eagerly at init time.
|
|
62
|
+
* Initialize the Temple SDK — sets config and authenticates with the REST API via API key.
|
|
74
63
|
*
|
|
75
|
-
* @returns
|
|
76
|
-
* Returns `null` if no API credentials were provided (config-only init).
|
|
64
|
+
* @returns null (config-only init). Throws no errors.
|
|
77
65
|
*/
|
|
78
|
-
export async function initialize(cfg: Record<string, unknown>): Promise<
|
|
66
|
+
export async function initialize(cfg: Record<string, unknown>): Promise<null> {
|
|
79
67
|
initializeConfig(cfg);
|
|
80
68
|
|
|
81
69
|
if (cfg.WALLET_ADAPTER) {
|
|
@@ -85,13 +73,11 @@ export async function initialize(cfg: Record<string, unknown>): Promise<LoginRes
|
|
|
85
73
|
const apiKey = cfg.API_KEY as string | undefined;
|
|
86
74
|
if (apiKey) {
|
|
87
75
|
setApiKeyFromConfig(apiKey);
|
|
88
|
-
return null;
|
|
89
76
|
}
|
|
90
77
|
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
return login(email, password);
|
|
78
|
+
const userIdValue = cfg.USER_ID as string | undefined;
|
|
79
|
+
if (userIdValue) {
|
|
80
|
+
setUserId(userIdValue);
|
|
95
81
|
}
|
|
96
82
|
|
|
97
83
|
return null;
|
|
@@ -99,9 +85,6 @@ export async function initialize(cfg: Record<string, unknown>): Promise<LoginRes
|
|
|
99
85
|
|
|
100
86
|
// ── Internal helpers ──
|
|
101
87
|
|
|
102
|
-
/** Pending auto-login promise for dedup. */
|
|
103
|
-
let autoLoginPromise: Promise<LoginResponse | ApiError> | null = null;
|
|
104
|
-
|
|
105
88
|
function handleApiError(error: unknown, context: string): ApiError {
|
|
106
89
|
const err = error as { response?: { status?: number; data?: { message?: string; error?: string; code?: string } }; message?: string };
|
|
107
90
|
const status = err.response?.status ?? null;
|
|
@@ -117,50 +100,19 @@ function handleApiError(error: unknown, context: string): ApiError {
|
|
|
117
100
|
return { error: true, status, code, message };
|
|
118
101
|
}
|
|
119
102
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
async function ensureAuthenticated(): Promise<ApiError | null> {
|
|
124
|
-
// API key takes priority — no login needed
|
|
103
|
+
function ensureAuthenticated(): ApiError | null {
|
|
104
|
+
// API key from config if not already set
|
|
125
105
|
const configApiKey = (config as Record<string, unknown>).API_KEY as string | undefined;
|
|
126
106
|
if (!getApiKey() && configApiKey) {
|
|
127
107
|
setApiKeyFromConfig(configApiKey);
|
|
128
108
|
}
|
|
129
109
|
if (getApiKey()) return null;
|
|
130
110
|
|
|
131
|
-
|
|
132
|
-
if (!getAccessToken()) {
|
|
133
|
-
const email = (config as Record<string, unknown>).API_EMAIL as string | undefined;
|
|
134
|
-
const password = (config as Record<string, unknown>).API_PASSWORD as string | undefined;
|
|
135
|
-
if (email && password) {
|
|
136
|
-
if (!autoLoginPromise) {
|
|
137
|
-
autoLoginPromise = login(email, password).finally(() => {
|
|
138
|
-
autoLoginPromise = null;
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
const result = await autoLoginPromise;
|
|
142
|
-
if ("error" in result && result.error) return result as ApiError;
|
|
143
|
-
} else {
|
|
144
|
-
return { error: true, status: 401, code: "NOT_AUTHENTICATED", message: "Not logged in. Call login() or provide API_EMAIL/API_PASSWORD in config." };
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Auto-refresh if expired
|
|
149
|
-
if (isTokenExpired()) {
|
|
150
|
-
if (!refreshPromise) {
|
|
151
|
-
refreshPromise = refreshAccessToken().finally(() => {
|
|
152
|
-
refreshPromise = null;
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
const result = await refreshPromise;
|
|
156
|
-
if ("error" in result && result.error) return result as ApiError;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
return null;
|
|
111
|
+
return { error: true, status: 401, code: "NOT_AUTHENTICATED", message: "API key required. Pass API_KEY in initialize() or call setApiKey()." };
|
|
160
112
|
}
|
|
161
113
|
|
|
162
114
|
async function authenticatedGet<T>(path: string, params?: Record<string, string | number | undefined>): Promise<T | ApiError> {
|
|
163
|
-
const authError =
|
|
115
|
+
const authError = ensureAuthenticated();
|
|
164
116
|
if (authError) return authError;
|
|
165
117
|
|
|
166
118
|
const headers = {
|
|
@@ -188,7 +140,7 @@ async function authenticatedGet<T>(path: string, params?: Record<string, string
|
|
|
188
140
|
}
|
|
189
141
|
|
|
190
142
|
async function authenticatedPost<T>(path: string, body?: Record<string, unknown>): Promise<T | ApiError> {
|
|
191
|
-
const authError =
|
|
143
|
+
const authError = ensureAuthenticated();
|
|
192
144
|
if (authError) return authError;
|
|
193
145
|
|
|
194
146
|
const headers = {
|
|
@@ -204,60 +156,6 @@ async function authenticatedPost<T>(path: string, body?: Record<string, unknown>
|
|
|
204
156
|
}
|
|
205
157
|
}
|
|
206
158
|
|
|
207
|
-
// ── Auth ──
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Login to the Temple REST API with email and password.
|
|
211
|
-
* Stores tokens automatically for subsequent API calls.
|
|
212
|
-
* @param email - User email
|
|
213
|
-
* @param password - User password
|
|
214
|
-
*/
|
|
215
|
-
export async function login(email: string, password: string): Promise<LoginResponse | ApiError> {
|
|
216
|
-
if (!email || !password) {
|
|
217
|
-
return { error: true, status: null, code: "INVALID_PARAMS", message: "Email and password are required." };
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
try {
|
|
221
|
-
const response = await axios.post<LoginResponse>(`${config.API_BASE_URL}/auth/login`, {
|
|
222
|
-
email,
|
|
223
|
-
password,
|
|
224
|
-
});
|
|
225
|
-
setTokens(response.data);
|
|
226
|
-
return response.data;
|
|
227
|
-
} catch (error) {
|
|
228
|
-
return handleApiError(error, "login");
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Refresh the access token using the stored or provided refresh token.
|
|
234
|
-
* Updates the token store automatically on success.
|
|
235
|
-
* @param refreshTokenOverride - Optional explicit refresh token (uses stored one if omitted)
|
|
236
|
-
*/
|
|
237
|
-
export async function refreshAccessToken(refreshTokenOverride?: string): Promise<RefreshResponse | ApiError> {
|
|
238
|
-
const token = refreshTokenOverride ?? getRefreshToken();
|
|
239
|
-
if (!token) {
|
|
240
|
-
return { error: true, status: null, code: "NO_REFRESH_TOKEN", message: "No refresh token available. Call login() first." };
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
try {
|
|
244
|
-
const response = await axios.post<RefreshResponse>(`${config.API_BASE_URL}/auth/refresh`, {
|
|
245
|
-
refresh_token: token,
|
|
246
|
-
});
|
|
247
|
-
setTokens(response.data);
|
|
248
|
-
return response.data;
|
|
249
|
-
} catch (error) {
|
|
250
|
-
return handleApiError(error, "refreshAccessToken");
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
/**
|
|
255
|
-
* Logout: clear all stored REST API tokens.
|
|
256
|
-
*/
|
|
257
|
-
export function logout(): void {
|
|
258
|
-
clearTokens();
|
|
259
|
-
}
|
|
260
|
-
|
|
261
159
|
// ── Helpers ──
|
|
262
160
|
|
|
263
161
|
/** Normalize CC → Amulet in symbol strings (e.g. "CC/SBC" → "Amulet/SBC", "CC" → "Amulet") */
|
|
@@ -378,7 +276,6 @@ export async function getDisclosures(partyId: string): Promise<DisclosuresRespon
|
|
|
378
276
|
|
|
379
277
|
/**
|
|
380
278
|
* Get the user's trading delegation status.
|
|
381
|
-
* The user ID is extracted from the JWT token automatically.
|
|
382
279
|
*/
|
|
383
280
|
export async function getDelegation(): Promise<DelegationResponse | ApiError> {
|
|
384
281
|
return authenticatedGet("/api/trading/delegation");
|
package/src/api/tokenStore.ts
CHANGED
|
@@ -1,65 +1,24 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AuthHeaders } from "./types.js";
|
|
2
2
|
|
|
3
|
-
let accessToken: string | null = null;
|
|
4
|
-
let refreshToken: string | null = null;
|
|
5
|
-
let tokenExpiryTime: number | null = null;
|
|
6
3
|
let apiKey: string | null = null;
|
|
7
4
|
let userId: string | null = null;
|
|
8
5
|
|
|
9
6
|
/**
|
|
10
|
-
*
|
|
11
|
-
*/
|
|
12
|
-
export function setTokens(data: TokenData): void {
|
|
13
|
-
accessToken = data.access_token;
|
|
14
|
-
refreshToken = data.refresh_token;
|
|
15
|
-
tokenExpiryTime = Date.now() + data.expires_in * 1000;
|
|
16
|
-
if (data.user?.user_id != null) {
|
|
17
|
-
userId = String(data.user.user_id);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Get the current access token, or null if not logged in.
|
|
23
|
-
*/
|
|
24
|
-
export function getAccessToken(): string | null {
|
|
25
|
-
return accessToken;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Get the stored refresh token, or null if not logged in.
|
|
30
|
-
*/
|
|
31
|
-
export function getRefreshToken(): string | null {
|
|
32
|
-
return refreshToken;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Check if the current access token is expired (with 60-second buffer).
|
|
37
|
-
*/
|
|
38
|
-
export function isTokenExpired(): boolean {
|
|
39
|
-
if (!tokenExpiryTime) return true;
|
|
40
|
-
return Date.now() >= tokenExpiryTime - 60_000;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Get the stored user ID from login, or null if not logged in.
|
|
7
|
+
* Get the stored user ID, or null if not set.
|
|
45
8
|
*/
|
|
46
9
|
export function getUserId(): string | null {
|
|
47
10
|
return userId;
|
|
48
11
|
}
|
|
49
12
|
|
|
50
|
-
|
|
51
13
|
/**
|
|
52
|
-
*
|
|
14
|
+
* Set the user ID directly (e.g. from config at init time).
|
|
53
15
|
*/
|
|
54
|
-
export function
|
|
55
|
-
|
|
56
|
-
refreshToken = null;
|
|
57
|
-
tokenExpiryTime = null;
|
|
58
|
-
userId = null;
|
|
16
|
+
export function setUserId(id: string): void {
|
|
17
|
+
userId = id;
|
|
59
18
|
}
|
|
60
19
|
|
|
61
20
|
/**
|
|
62
|
-
* Set an API key for authentication
|
|
21
|
+
* Set an API key for authentication.
|
|
63
22
|
*/
|
|
64
23
|
export function setApiKey(key: string): void {
|
|
65
24
|
apiKey = key;
|
|
@@ -73,15 +32,12 @@ export function getApiKey(): string | null {
|
|
|
73
32
|
}
|
|
74
33
|
|
|
75
34
|
/**
|
|
76
|
-
* Get the authorization header
|
|
77
|
-
* Returns null if
|
|
35
|
+
* Get the authorization header using the API key.
|
|
36
|
+
* Returns null if no API key is set.
|
|
78
37
|
*/
|
|
79
38
|
export function getAuthHeader(): AuthHeaders | null {
|
|
80
39
|
if (apiKey) {
|
|
81
40
|
return { Authorization: `Bearer ${apiKey}` };
|
|
82
41
|
}
|
|
83
|
-
if (accessToken) {
|
|
84
|
-
return { Authorization: `Bearer ${accessToken}` };
|
|
85
|
-
}
|
|
86
42
|
return null;
|
|
87
43
|
}
|
package/src/api/types.ts
CHANGED
|
@@ -1,25 +1,3 @@
|
|
|
1
|
-
// ── Auth ──
|
|
2
|
-
|
|
3
|
-
export interface LoginUser {
|
|
4
|
-
user_id: number;
|
|
5
|
-
max_limit_orders: number;
|
|
6
|
-
max_market_orders: number;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface LoginResponse {
|
|
10
|
-
access_token: string;
|
|
11
|
-
refresh_token: string;
|
|
12
|
-
expires_in: number;
|
|
13
|
-
token_type: string;
|
|
14
|
-
user: LoginUser;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface RefreshResponse {
|
|
18
|
-
access_token: string;
|
|
19
|
-
refresh_token: string;
|
|
20
|
-
expires_in: number;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
1
|
// ── Market Data ──
|
|
24
2
|
|
|
25
3
|
export interface Ticker {
|
|
@@ -209,14 +187,7 @@ export interface ApiError {
|
|
|
209
187
|
message: string;
|
|
210
188
|
}
|
|
211
189
|
|
|
212
|
-
// ──
|
|
213
|
-
|
|
214
|
-
export interface TokenData {
|
|
215
|
-
access_token: string;
|
|
216
|
-
refresh_token: string;
|
|
217
|
-
expires_in: number;
|
|
218
|
-
user?: LoginUser;
|
|
219
|
-
}
|
|
190
|
+
// ── Auth ──
|
|
220
191
|
|
|
221
192
|
export interface AuthHeaders {
|
|
222
193
|
Authorization: string;
|