@temple-digital-group/temple-canton-js 1.0.39-beta.6 → 2.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -13
- package/dist/api/index.d.ts +6 -26
- package/dist/api/index.js +12 -109
- package/dist/api/tokenStore.d.ts +6 -30
- package/dist/api/tokenStore.js +9 -60
- package/dist/api/types.d.ts +1 -24
- package/dist/api/types.js +1 -1
- package/package.json +1 -1
- package/src/api/index.ts +13 -129
- package/src/api/tokenStore.ts +30 -87
- package/src/api/types.ts +2 -31
- package/src/config/index.d.ts +1 -0
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,
|
|
3
|
-
export {
|
|
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
|
+
export { 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,36 +1,26 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
2
|
import config, { initializeConfig, setWalletAdapter } from "../../src/config/index.js";
|
|
3
|
-
import {
|
|
4
|
-
export {
|
|
3
|
+
import { getAuthHeader, setUserId, } from "./tokenStore.js";
|
|
4
|
+
export { 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);
|
|
16
14
|
if (cfg.WALLET_ADAPTER) {
|
|
17
15
|
setWalletAdapter(cfg.WALLET_ADAPTER);
|
|
18
16
|
}
|
|
19
|
-
const
|
|
20
|
-
if (
|
|
21
|
-
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
const email = cfg.API_EMAIL;
|
|
25
|
-
const password = cfg.API_PASSWORD;
|
|
26
|
-
if (email && password) {
|
|
27
|
-
return login(email, password);
|
|
17
|
+
const userIdValue = cfg.USER_ID;
|
|
18
|
+
if (userIdValue) {
|
|
19
|
+
setUserId(userIdValue);
|
|
28
20
|
}
|
|
29
21
|
return null;
|
|
30
22
|
}
|
|
31
23
|
// ── Internal helpers ──
|
|
32
|
-
/** Pending auto-login promise for dedup. */
|
|
33
|
-
let autoLoginPromise = null;
|
|
34
24
|
function handleApiError(error, context) {
|
|
35
25
|
const err = error;
|
|
36
26
|
const status = err.response?.status ?? null;
|
|
@@ -42,49 +32,13 @@ function handleApiError(error, context) {
|
|
|
42
32
|
console.error(`[Temple API] ${context}: ${message}${status ? ` (HTTP ${status})` : ""}`);
|
|
43
33
|
return { error: true, status, code, message };
|
|
44
34
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
async function ensureAuthenticated() {
|
|
48
|
-
// API key takes priority — no login needed
|
|
49
|
-
const configApiKey = config.API_KEY;
|
|
50
|
-
if (!getApiKey() && configApiKey) {
|
|
51
|
-
setApiKeyFromConfig(configApiKey);
|
|
52
|
-
}
|
|
53
|
-
if (getApiKey())
|
|
35
|
+
function ensureAuthenticated() {
|
|
36
|
+
if (config.API_KEY)
|
|
54
37
|
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;
|
|
38
|
+
return { error: true, status: 401, code: "NOT_AUTHENTICATED", message: "API key required. Pass API_KEY in initialize()." };
|
|
85
39
|
}
|
|
86
40
|
async function authenticatedGet(path, params) {
|
|
87
|
-
const authError =
|
|
41
|
+
const authError = ensureAuthenticated();
|
|
88
42
|
if (authError)
|
|
89
43
|
return authError;
|
|
90
44
|
const headers = {
|
|
@@ -111,7 +65,7 @@ async function authenticatedGet(path, params) {
|
|
|
111
65
|
}
|
|
112
66
|
}
|
|
113
67
|
async function authenticatedPost(path, body) {
|
|
114
|
-
const authError =
|
|
68
|
+
const authError = ensureAuthenticated();
|
|
115
69
|
if (authError)
|
|
116
70
|
return authError;
|
|
117
71
|
const headers = {
|
|
@@ -126,56 +80,6 @@ async function authenticatedPost(path, body) {
|
|
|
126
80
|
return handleApiError(error, `POST ${path}`);
|
|
127
81
|
}
|
|
128
82
|
}
|
|
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
83
|
// ── Helpers ──
|
|
180
84
|
/** Normalize CC → Amulet in symbol strings (e.g. "CC/SBC" → "Amulet/SBC", "CC" → "Amulet") */
|
|
181
85
|
function normalizeSymbol(symbol) {
|
|
@@ -281,7 +185,6 @@ export async function getDisclosures(partyId) {
|
|
|
281
185
|
// ── Delegation ──
|
|
282
186
|
/**
|
|
283
187
|
* Get the user's trading delegation status.
|
|
284
|
-
* The user ID is extracted from the JWT token automatically.
|
|
285
188
|
*/
|
|
286
189
|
export async function getDelegation() {
|
|
287
190
|
return authenticatedGet("/api/trading/delegation");
|
package/dist/api/tokenStore.d.ts
CHANGED
|
@@ -1,38 +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
|
-
*
|
|
24
|
-
*/
|
|
25
|
-
export declare function clearTokens(): void;
|
|
26
|
-
/**
|
|
27
|
-
* Set an API key for authentication (future: replaces email/password login).
|
|
28
|
-
*/
|
|
29
|
-
export declare function setApiKey(key: string): void;
|
|
30
|
-
/**
|
|
31
|
-
* Get the stored API key, or null if not set.
|
|
7
|
+
* Set the user ID directly (e.g. from config at init time).
|
|
32
8
|
*/
|
|
33
|
-
export declare function
|
|
9
|
+
export declare function setUserId(id: string): void;
|
|
34
10
|
/**
|
|
35
|
-
* Get the authorization header
|
|
36
|
-
* Returns null if
|
|
11
|
+
* Get the authorization header using the API key from config.
|
|
12
|
+
* Returns null if no API key is configured.
|
|
37
13
|
*/
|
|
38
14
|
export declare function getAuthHeader(): AuthHeaders | null;
|
package/dist/api/tokenStore.js
CHANGED
|
@@ -1,76 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
let refreshToken = null;
|
|
3
|
-
let tokenExpiryTime = null;
|
|
4
|
-
let apiKey = null;
|
|
1
|
+
import config from "../../src/config/index.js";
|
|
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
|
-
*
|
|
45
|
-
*/
|
|
46
|
-
export function clearTokens() {
|
|
47
|
-
accessToken = null;
|
|
48
|
-
refreshToken = null;
|
|
49
|
-
tokenExpiryTime = null;
|
|
50
|
-
userId = null;
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Set an API key for authentication (future: replaces email/password login).
|
|
10
|
+
* Set the user ID directly (e.g. from config at init time).
|
|
54
11
|
*/
|
|
55
|
-
export function
|
|
56
|
-
|
|
12
|
+
export function setUserId(id) {
|
|
13
|
+
userId = id;
|
|
57
14
|
}
|
|
58
15
|
/**
|
|
59
|
-
* Get the
|
|
60
|
-
|
|
61
|
-
export function getApiKey() {
|
|
62
|
-
return apiKey;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Get the authorization header. Prefers API key if set, otherwise uses Bearer token.
|
|
66
|
-
* Returns null if neither is available.
|
|
16
|
+
* Get the authorization header using the API key from config.
|
|
17
|
+
* Returns null if no API key is configured.
|
|
67
18
|
*/
|
|
68
19
|
export function getAuthHeader() {
|
|
20
|
+
const apiKey = config.API_KEY;
|
|
69
21
|
if (apiKey) {
|
|
70
|
-
return {
|
|
71
|
-
}
|
|
72
|
-
if (accessToken) {
|
|
73
|
-
return { Authorization: `Bearer ${accessToken}` };
|
|
22
|
+
return { "X-API-Key": apiKey };
|
|
74
23
|
}
|
|
75
24
|
return null;
|
|
76
25
|
}
|
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
|
+
"X-API-Key": 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,11 @@
|
|
|
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
|
-
getApiKey,
|
|
8
|
-
setApiKey as setApiKeyFromConfig,
|
|
9
|
-
isTokenExpired,
|
|
10
|
-
clearTokens,
|
|
11
4
|
getAuthHeader,
|
|
5
|
+
setUserId,
|
|
12
6
|
} from "./tokenStore.js";
|
|
13
7
|
import type {
|
|
14
8
|
ApiError,
|
|
15
|
-
LoginUser,
|
|
16
|
-
LoginResponse,
|
|
17
|
-
RefreshResponse,
|
|
18
9
|
Ticker,
|
|
19
10
|
OrderBook,
|
|
20
11
|
OrderBookOptions,
|
|
@@ -40,9 +31,6 @@ import type {
|
|
|
40
31
|
// Re-export types and token utilities consumers may need
|
|
41
32
|
export type {
|
|
42
33
|
ApiError,
|
|
43
|
-
LoginUser,
|
|
44
|
-
LoginResponse,
|
|
45
|
-
RefreshResponse,
|
|
46
34
|
Ticker,
|
|
47
35
|
OrderBook,
|
|
48
36
|
OrderBookOptions,
|
|
@@ -63,35 +51,26 @@ export type {
|
|
|
63
51
|
AmuletDisclosure,
|
|
64
52
|
DisclosuresResponse,
|
|
65
53
|
};
|
|
66
|
-
export {
|
|
54
|
+
export { getUserId } from "./tokenStore.js";
|
|
67
55
|
export { setWalletAdapter } from "../../src/config/index.js";
|
|
68
56
|
|
|
69
57
|
// ── Initialization ──
|
|
70
58
|
|
|
71
59
|
/**
|
|
72
|
-
* Initialize the Temple SDK — sets config and
|
|
73
|
-
* Pass `API_EMAIL`/`API_PASSWORD` or `API_KEY` to authenticate eagerly at init time.
|
|
60
|
+
* Initialize the Temple SDK — sets config and authenticates with the REST API via API key.
|
|
74
61
|
*
|
|
75
|
-
* @returns
|
|
76
|
-
* Returns `null` if no API credentials were provided (config-only init).
|
|
62
|
+
* @returns null (config-only init). Throws no errors.
|
|
77
63
|
*/
|
|
78
|
-
export async function initialize(cfg: Record<string, unknown>): Promise<
|
|
64
|
+
export async function initialize(cfg: Record<string, unknown>): Promise<null> {
|
|
79
65
|
initializeConfig(cfg);
|
|
80
66
|
|
|
81
67
|
if (cfg.WALLET_ADAPTER) {
|
|
82
68
|
setWalletAdapter(cfg.WALLET_ADAPTER);
|
|
83
69
|
}
|
|
84
70
|
|
|
85
|
-
const
|
|
86
|
-
if (
|
|
87
|
-
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const email = cfg.API_EMAIL as string | undefined;
|
|
92
|
-
const password = cfg.API_PASSWORD as string | undefined;
|
|
93
|
-
if (email && password) {
|
|
94
|
-
return login(email, password);
|
|
71
|
+
const userIdValue = cfg.USER_ID as string | undefined;
|
|
72
|
+
if (userIdValue) {
|
|
73
|
+
setUserId(userIdValue);
|
|
95
74
|
}
|
|
96
75
|
|
|
97
76
|
return null;
|
|
@@ -99,9 +78,6 @@ export async function initialize(cfg: Record<string, unknown>): Promise<LoginRes
|
|
|
99
78
|
|
|
100
79
|
// ── Internal helpers ──
|
|
101
80
|
|
|
102
|
-
/** Pending auto-login promise for dedup. */
|
|
103
|
-
let autoLoginPromise: Promise<LoginResponse | ApiError> | null = null;
|
|
104
|
-
|
|
105
81
|
function handleApiError(error: unknown, context: string): ApiError {
|
|
106
82
|
const err = error as { response?: { status?: number; data?: { message?: string; error?: string; code?: string } }; message?: string };
|
|
107
83
|
const status = err.response?.status ?? null;
|
|
@@ -117,50 +93,13 @@ function handleApiError(error: unknown, context: string): ApiError {
|
|
|
117
93
|
return { error: true, status, code, message };
|
|
118
94
|
}
|
|
119
95
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
async function ensureAuthenticated(): Promise<ApiError | null> {
|
|
124
|
-
// API key takes priority — no login needed
|
|
125
|
-
const configApiKey = (config as Record<string, unknown>).API_KEY as string | undefined;
|
|
126
|
-
if (!getApiKey() && configApiKey) {
|
|
127
|
-
setApiKeyFromConfig(configApiKey);
|
|
128
|
-
}
|
|
129
|
-
if (getApiKey()) return null;
|
|
130
|
-
|
|
131
|
-
// Auto-login from config if no token exists
|
|
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;
|
|
96
|
+
function ensureAuthenticated(): ApiError | null {
|
|
97
|
+
if (config.API_KEY) return null;
|
|
98
|
+
return { error: true, status: 401, code: "NOT_AUTHENTICATED", message: "API key required. Pass API_KEY in initialize()." };
|
|
160
99
|
}
|
|
161
100
|
|
|
162
101
|
async function authenticatedGet<T>(path: string, params?: Record<string, string | number | undefined>): Promise<T | ApiError> {
|
|
163
|
-
const authError =
|
|
102
|
+
const authError = ensureAuthenticated();
|
|
164
103
|
if (authError) return authError;
|
|
165
104
|
|
|
166
105
|
const headers = {
|
|
@@ -188,7 +127,7 @@ async function authenticatedGet<T>(path: string, params?: Record<string, string
|
|
|
188
127
|
}
|
|
189
128
|
|
|
190
129
|
async function authenticatedPost<T>(path: string, body?: Record<string, unknown>): Promise<T | ApiError> {
|
|
191
|
-
const authError =
|
|
130
|
+
const authError = ensureAuthenticated();
|
|
192
131
|
if (authError) return authError;
|
|
193
132
|
|
|
194
133
|
const headers = {
|
|
@@ -204,60 +143,6 @@ async function authenticatedPost<T>(path: string, body?: Record<string, unknown>
|
|
|
204
143
|
}
|
|
205
144
|
}
|
|
206
145
|
|
|
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
146
|
// ── Helpers ──
|
|
262
147
|
|
|
263
148
|
/** Normalize CC → Amulet in symbol strings (e.g. "CC/SBC" → "Amulet/SBC", "CC" → "Amulet") */
|
|
@@ -378,7 +263,6 @@ export async function getDisclosures(partyId: string): Promise<DisclosuresRespon
|
|
|
378
263
|
|
|
379
264
|
/**
|
|
380
265
|
* Get the user's trading delegation status.
|
|
381
|
-
* The user ID is extracted from the JWT token automatically.
|
|
382
266
|
*/
|
|
383
267
|
export async function getDelegation(): Promise<DelegationResponse | ApiError> {
|
|
384
268
|
return authenticatedGet("/api/trading/delegation");
|
package/src/api/tokenStore.ts
CHANGED
|
@@ -1,87 +1,30 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
let
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
*
|
|
23
|
-
*/
|
|
24
|
-
export function
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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.
|
|
45
|
-
*/
|
|
46
|
-
export function getUserId(): string | null {
|
|
47
|
-
return userId;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Clear all stored tokens (logout).
|
|
53
|
-
*/
|
|
54
|
-
export function clearTokens(): void {
|
|
55
|
-
accessToken = null;
|
|
56
|
-
refreshToken = null;
|
|
57
|
-
tokenExpiryTime = null;
|
|
58
|
-
userId = null;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Set an API key for authentication (future: replaces email/password login).
|
|
63
|
-
*/
|
|
64
|
-
export function setApiKey(key: string): void {
|
|
65
|
-
apiKey = key;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Get the stored API key, or null if not set.
|
|
70
|
-
*/
|
|
71
|
-
export function getApiKey(): string | null {
|
|
72
|
-
return apiKey;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Get the authorization header. Prefers API key if set, otherwise uses Bearer token.
|
|
77
|
-
* Returns null if neither is available.
|
|
78
|
-
*/
|
|
79
|
-
export function getAuthHeader(): AuthHeaders | null {
|
|
80
|
-
if (apiKey) {
|
|
81
|
-
return { Authorization: `Bearer ${apiKey}` };
|
|
82
|
-
}
|
|
83
|
-
if (accessToken) {
|
|
84
|
-
return { Authorization: `Bearer ${accessToken}` };
|
|
85
|
-
}
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
1
|
+
import config from "../../src/config/index.js";
|
|
2
|
+
import type { AuthHeaders } from "./types.js";
|
|
3
|
+
|
|
4
|
+
let userId: string | null = null;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Get the stored user ID, or null if not set.
|
|
8
|
+
*/
|
|
9
|
+
export function getUserId(): string | null {
|
|
10
|
+
return userId;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Set the user ID directly (e.g. from config at init time).
|
|
15
|
+
*/
|
|
16
|
+
export function setUserId(id: string): void {
|
|
17
|
+
userId = id;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Get the authorization header using the API key from config.
|
|
22
|
+
* Returns null if no API key is configured.
|
|
23
|
+
*/
|
|
24
|
+
export function getAuthHeader(): AuthHeaders | null {
|
|
25
|
+
const apiKey = config.API_KEY;
|
|
26
|
+
if (apiKey) {
|
|
27
|
+
return { "X-API-Key": apiKey };
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
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,15 +187,8 @@ 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
|
+
"X-API-Key": string;
|
|
223
194
|
}
|