@sereel/sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +121 -0
- package/dist/index.cjs +282 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +82 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.js +245 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -0
package/README.md
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Seree TypeScript SDK
|
|
2
|
+
|
|
3
|
+
TypeScript SDK for the Seree SDK-facing REST asset endpoints.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @seree/sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quickstart
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { createClient } from "@seree/sdk";
|
|
15
|
+
|
|
16
|
+
const client = createClient({
|
|
17
|
+
environment: "mainnet",
|
|
18
|
+
apiKey: process.env.SEREE_SDK_API_KEY!,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const assets = await client.getAssets();
|
|
22
|
+
const asset = await client.getAssetByTokenAddress("0x123");
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Authentication
|
|
26
|
+
|
|
27
|
+
The SDK sends your API key in the `x-api-key` header.
|
|
28
|
+
|
|
29
|
+
Only MATATA-issued API keys are supported right now.
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { createClient } from "@seree/sdk";
|
|
33
|
+
|
|
34
|
+
const client = createClient({
|
|
35
|
+
environment: "testnet",
|
|
36
|
+
apiKey: process.env.SEREE_SDK_API_KEY!,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const assets = await client.getAssets();
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Environments
|
|
43
|
+
|
|
44
|
+
The SDK resolves the API base URL from the configured environment so callers do not need to pass a raw URL in normal usage.
|
|
45
|
+
|
|
46
|
+
- `devnet` => `https://api-lazer.sereel.com`
|
|
47
|
+
- `testnet` => `https://api-lazer-v2.sereel.com`
|
|
48
|
+
- `mainnet` => `https://cahokia.sereel.com`
|
|
49
|
+
|
|
50
|
+
## Client API
|
|
51
|
+
|
|
52
|
+
### `createClient`
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { createClient } from "@seree/sdk";
|
|
56
|
+
|
|
57
|
+
const client = createClient({
|
|
58
|
+
environment: "testnet",
|
|
59
|
+
apiKey: process.env.SEREE_SDK_API_KEY!,
|
|
60
|
+
timeoutMs: 10_000,
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Advanced option:
|
|
65
|
+
|
|
66
|
+
`baseUrl` can be provided as an explicit override for local integration testing or temporary pre-release environments, but `environment` remains the primary and recommended path.
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
const client = createClient({
|
|
70
|
+
environment: "devnet",
|
|
71
|
+
apiKey: process.env.SEREE_SDK_API_KEY!,
|
|
72
|
+
baseUrl: "http://localhost:8080",
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### `client.getAssets()`
|
|
77
|
+
|
|
78
|
+
Fetches `GET /sdk/assets`.
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
const assets = await client.getAssets();
|
|
82
|
+
|
|
83
|
+
console.log(assets.count);
|
|
84
|
+
console.log(assets.data[0]?.security.token_symbol);
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### `client.getAssetByTokenAddress(tokenAddress)`
|
|
88
|
+
|
|
89
|
+
Fetches `GET /sdk/assets/{token_address}`.
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
const asset = await client.getAssetByTokenAddress("0x123");
|
|
93
|
+
|
|
94
|
+
console.log(asset.data.security.token_name);
|
|
95
|
+
console.log(asset.data.books.length);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Response shape
|
|
99
|
+
|
|
100
|
+
The SDK models the backend SDK DTOs and returns joined asset records with:
|
|
101
|
+
|
|
102
|
+
- `security`
|
|
103
|
+
- `seller_organization`
|
|
104
|
+
- `books`
|
|
105
|
+
|
|
106
|
+
Token price fields are intentionally not included in the SDK types.
|
|
107
|
+
|
|
108
|
+
## Errors
|
|
109
|
+
|
|
110
|
+
The SDK throws typed errors for common failure cases:
|
|
111
|
+
|
|
112
|
+
- `InvalidConfigurationError`
|
|
113
|
+
- `UnauthorizedError`
|
|
114
|
+
- `NotFoundError`
|
|
115
|
+
- `ServerError`
|
|
116
|
+
- `TimeoutError`
|
|
117
|
+
- `MalformedResponseError`
|
|
118
|
+
|
|
119
|
+
## Runtime support
|
|
120
|
+
|
|
121
|
+
The SDK is framework-agnostic and uses the platform `fetch` API. In runtimes without a global `fetch`, pass a compatible implementation through `createClient({ fetch })`.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
ENVIRONMENT_BASE_URLS: () => ENVIRONMENT_BASE_URLS,
|
|
24
|
+
HttpError: () => HttpError,
|
|
25
|
+
InvalidConfigurationError: () => InvalidConfigurationError,
|
|
26
|
+
MalformedResponseError: () => MalformedResponseError,
|
|
27
|
+
NotFoundError: () => NotFoundError,
|
|
28
|
+
SereeSdkError: () => SereeSdkError,
|
|
29
|
+
ServerError: () => ServerError,
|
|
30
|
+
TimeoutError: () => TimeoutError,
|
|
31
|
+
UnauthorizedError: () => UnauthorizedError,
|
|
32
|
+
createClient: () => createClient,
|
|
33
|
+
resolveBaseUrl: () => resolveBaseUrl
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(index_exports);
|
|
36
|
+
|
|
37
|
+
// src/errors.ts
|
|
38
|
+
var SereeSdkError = class extends Error {
|
|
39
|
+
status;
|
|
40
|
+
code;
|
|
41
|
+
details;
|
|
42
|
+
constructor(message, options = {}) {
|
|
43
|
+
super(message, options.cause ? { cause: options.cause } : void 0);
|
|
44
|
+
this.name = new.target.name;
|
|
45
|
+
this.status = options.status;
|
|
46
|
+
this.code = options.code;
|
|
47
|
+
this.details = options.details;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var InvalidConfigurationError = class extends SereeSdkError {
|
|
51
|
+
};
|
|
52
|
+
var HttpError = class extends SereeSdkError {
|
|
53
|
+
};
|
|
54
|
+
var UnauthorizedError = class extends HttpError {
|
|
55
|
+
};
|
|
56
|
+
var NotFoundError = class extends HttpError {
|
|
57
|
+
};
|
|
58
|
+
var ServerError = class extends HttpError {
|
|
59
|
+
};
|
|
60
|
+
var TimeoutError = class extends SereeSdkError {
|
|
61
|
+
};
|
|
62
|
+
var MalformedResponseError = class extends SereeSdkError {
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// src/config.ts
|
|
66
|
+
var ENVIRONMENT_BASE_URLS = {
|
|
67
|
+
devnet: "https://api-lazer.sereel.com",
|
|
68
|
+
testnet: "https://api-lazer-v2.sereel.com",
|
|
69
|
+
mainnet: "https://cahokia.sereel.com"
|
|
70
|
+
};
|
|
71
|
+
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
72
|
+
function getFetchImplementation(providedFetch) {
|
|
73
|
+
if (providedFetch) {
|
|
74
|
+
return providedFetch;
|
|
75
|
+
}
|
|
76
|
+
if (typeof globalThis.fetch === "function") {
|
|
77
|
+
return globalThis.fetch.bind(globalThis);
|
|
78
|
+
}
|
|
79
|
+
throw new InvalidConfigurationError(
|
|
80
|
+
"No fetch implementation is available. Provide config.fetch in this runtime."
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
function normalizeBaseUrl(baseUrl) {
|
|
84
|
+
const trimmed = baseUrl.trim();
|
|
85
|
+
if (!trimmed) {
|
|
86
|
+
throw new InvalidConfigurationError("baseUrl must not be empty when provided.");
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
return new URL(trimmed).toString().replace(/\/+$/, "");
|
|
90
|
+
} catch (cause) {
|
|
91
|
+
throw new InvalidConfigurationError("baseUrl must be a valid absolute URL.", {
|
|
92
|
+
cause
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function resolveBaseUrl(environment, baseUrl) {
|
|
97
|
+
if (baseUrl) {
|
|
98
|
+
return normalizeBaseUrl(baseUrl);
|
|
99
|
+
}
|
|
100
|
+
return ENVIRONMENT_BASE_URLS[environment];
|
|
101
|
+
}
|
|
102
|
+
function resolveClientConfig(config) {
|
|
103
|
+
const apiKey = config.apiKey.trim();
|
|
104
|
+
if (!apiKey) {
|
|
105
|
+
throw new InvalidConfigurationError("apiKey must not be empty.");
|
|
106
|
+
}
|
|
107
|
+
const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
108
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
109
|
+
throw new InvalidConfigurationError("timeoutMs must be a positive number.");
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
environment: config.environment,
|
|
113
|
+
apiKey,
|
|
114
|
+
timeoutMs,
|
|
115
|
+
baseUrl: resolveBaseUrl(config.environment, config.baseUrl),
|
|
116
|
+
fetch: getFetchImplementation(config.fetch)
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// src/transport.ts
|
|
121
|
+
function createTimeoutSignal(timeoutMs) {
|
|
122
|
+
const controller = new AbortController();
|
|
123
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
124
|
+
return {
|
|
125
|
+
signal: controller.signal,
|
|
126
|
+
cleanup: () => clearTimeout(timeout)
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
async function parseBody(response) {
|
|
130
|
+
const text = await response.text();
|
|
131
|
+
if (!text) {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
try {
|
|
135
|
+
return JSON.parse(text);
|
|
136
|
+
} catch (cause) {
|
|
137
|
+
throw new MalformedResponseError("Received a non-JSON response body.", {
|
|
138
|
+
cause,
|
|
139
|
+
status: response.status,
|
|
140
|
+
details: text
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function getErrorMessage(status, body) {
|
|
145
|
+
if (body && typeof body === "object") {
|
|
146
|
+
const apiError = body;
|
|
147
|
+
if (typeof apiError.error === "string" && apiError.error.trim()) {
|
|
148
|
+
return apiError.error;
|
|
149
|
+
}
|
|
150
|
+
if (typeof apiError.message === "string" && apiError.message.trim()) {
|
|
151
|
+
return apiError.message;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return `Request failed with status ${status}.`;
|
|
155
|
+
}
|
|
156
|
+
function toHttpError(status, body) {
|
|
157
|
+
const message = getErrorMessage(status, body);
|
|
158
|
+
const options = { status, details: body };
|
|
159
|
+
if (status === 401) {
|
|
160
|
+
return new UnauthorizedError(message, options);
|
|
161
|
+
}
|
|
162
|
+
if (status === 404) {
|
|
163
|
+
return new NotFoundError(message, options);
|
|
164
|
+
}
|
|
165
|
+
if (status >= 500) {
|
|
166
|
+
return new ServerError(message, options);
|
|
167
|
+
}
|
|
168
|
+
return new HttpError(message, options);
|
|
169
|
+
}
|
|
170
|
+
async function requestJson(config, path, validate) {
|
|
171
|
+
const { signal, cleanup } = createTimeoutSignal(config.timeoutMs);
|
|
172
|
+
try {
|
|
173
|
+
const response = await config.fetch(`${config.baseUrl}${path}`, {
|
|
174
|
+
method: "GET",
|
|
175
|
+
signal,
|
|
176
|
+
headers: {
|
|
177
|
+
accept: "application/json",
|
|
178
|
+
"x-api-key": config.apiKey
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
const body = await parseBody(response);
|
|
182
|
+
if (!response.ok) {
|
|
183
|
+
throw toHttpError(response.status, body);
|
|
184
|
+
}
|
|
185
|
+
return validate(body);
|
|
186
|
+
} catch (error) {
|
|
187
|
+
if (error instanceof HttpError || error instanceof MalformedResponseError) {
|
|
188
|
+
throw error;
|
|
189
|
+
}
|
|
190
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
191
|
+
throw new TimeoutError(
|
|
192
|
+
`Request timed out after ${config.timeoutMs}ms.`,
|
|
193
|
+
{ cause: error }
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
throw error;
|
|
197
|
+
} finally {
|
|
198
|
+
cleanup();
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// src/validation.ts
|
|
203
|
+
function isRecord(value) {
|
|
204
|
+
return typeof value === "object" && value !== null;
|
|
205
|
+
}
|
|
206
|
+
function isString(value) {
|
|
207
|
+
return typeof value === "string";
|
|
208
|
+
}
|
|
209
|
+
function isNullableString(value) {
|
|
210
|
+
return typeof value === "string" || value === null;
|
|
211
|
+
}
|
|
212
|
+
function isFiniteNumber(value) {
|
|
213
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
214
|
+
}
|
|
215
|
+
function isSecuritySummary(value) {
|
|
216
|
+
return isRecord(value) && isString(value.id) && isString(value.token_address) && isString(value.token_name) && isString(value.token_symbol) && isString(value.network_id) && isString(value.token_type);
|
|
217
|
+
}
|
|
218
|
+
function isSellerOrganizationSummary(value) {
|
|
219
|
+
return isRecord(value) && isString(value.id) && isString(value.legal_name) && isNullableString(value.display_name) && isString(value.jurisdiction) && isNullableString(value.website);
|
|
220
|
+
}
|
|
221
|
+
function isBookSummary(value) {
|
|
222
|
+
return isRecord(value) && isString(value.id) && isString(value.order_book_address) && isString(value.status) && isString(value.network_id) && isFiniteNumber(value.subscription_start) && isFiniteNumber(value.subscription_end) && isString(value.prospectus_file_url);
|
|
223
|
+
}
|
|
224
|
+
function isAssetRecord(value) {
|
|
225
|
+
return isRecord(value) && isSecuritySummary(value.security) && isSellerOrganizationSummary(value.seller_organization) && Array.isArray(value.books) && value.books.every(isBookSummary);
|
|
226
|
+
}
|
|
227
|
+
function validateSdkAssetsResponse(value) {
|
|
228
|
+
if (!isRecord(value) || !Array.isArray(value.data) || !isFiniteNumber(value.count) || !value.data.every(isAssetRecord)) {
|
|
229
|
+
throw new MalformedResponseError(
|
|
230
|
+
"Received an invalid SDK assets response shape.",
|
|
231
|
+
{ details: value }
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
return value;
|
|
235
|
+
}
|
|
236
|
+
function validateSdkAssetResponse(value) {
|
|
237
|
+
if (!isRecord(value) || !isAssetRecord(value.data)) {
|
|
238
|
+
throw new MalformedResponseError(
|
|
239
|
+
"Received an invalid SDK asset response shape.",
|
|
240
|
+
{ details: value }
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
return value;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// src/client.ts
|
|
247
|
+
function createClient(config) {
|
|
248
|
+
const resolved = resolveClientConfig(config);
|
|
249
|
+
return {
|
|
250
|
+
getAssets() {
|
|
251
|
+
return requestJson(resolved, "/sdk/assets", validateSdkAssetsResponse);
|
|
252
|
+
},
|
|
253
|
+
getAssetByTokenAddress(tokenAddress) {
|
|
254
|
+
const trimmedTokenAddress = tokenAddress.trim();
|
|
255
|
+
if (!trimmedTokenAddress) {
|
|
256
|
+
throw new InvalidConfigurationError(
|
|
257
|
+
"tokenAddress must not be empty."
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
return requestJson(
|
|
261
|
+
resolved,
|
|
262
|
+
`/sdk/assets/${encodeURIComponent(trimmedTokenAddress)}`,
|
|
263
|
+
validateSdkAssetResponse
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
269
|
+
0 && (module.exports = {
|
|
270
|
+
ENVIRONMENT_BASE_URLS,
|
|
271
|
+
HttpError,
|
|
272
|
+
InvalidConfigurationError,
|
|
273
|
+
MalformedResponseError,
|
|
274
|
+
NotFoundError,
|
|
275
|
+
SereeSdkError,
|
|
276
|
+
ServerError,
|
|
277
|
+
TimeoutError,
|
|
278
|
+
UnauthorizedError,
|
|
279
|
+
createClient,
|
|
280
|
+
resolveBaseUrl
|
|
281
|
+
});
|
|
282
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/config.ts","../src/transport.ts","../src/validation.ts","../src/client.ts"],"sourcesContent":["export { createClient } from \"./client\";\nexport { ENVIRONMENT_BASE_URLS, resolveBaseUrl } from \"./config\";\nexport {\n HttpError,\n InvalidConfigurationError,\n MalformedResponseError,\n NotFoundError,\n ServerError,\n SereeSdkError,\n TimeoutError,\n UnauthorizedError,\n} from \"./errors\";\nexport type {\n ClientConfig,\n SdkAssetRecord,\n SdkAssetResponse,\n SdkAssetsResponse,\n SdkBookSummary,\n SdkSecuritySummary,\n SdkSellerOrganizationSummary,\n SereeEnvironment,\n SereeSdkClient,\n} from \"./types\";\n","export interface SereeSdkErrorOptions {\n status?: number;\n code?: string;\n cause?: unknown;\n details?: unknown;\n}\n\nexport class SereeSdkError extends Error {\n readonly status: number | undefined;\n readonly code: string | undefined;\n readonly details?: unknown;\n\n constructor(message: string, options: SereeSdkErrorOptions = {}) {\n super(message, options.cause ? { cause: options.cause } : undefined);\n this.name = new.target.name;\n this.status = options.status;\n this.code = options.code;\n this.details = options.details;\n }\n}\n\nexport class InvalidConfigurationError extends SereeSdkError {}\n\nexport class HttpError extends SereeSdkError {}\n\nexport class UnauthorizedError extends HttpError {}\n\nexport class NotFoundError extends HttpError {}\n\nexport class ServerError extends HttpError {}\n\nexport class TimeoutError extends SereeSdkError {}\n\nexport class MalformedResponseError extends SereeSdkError {}\n","import { InvalidConfigurationError } from \"./errors\";\nimport type { ClientConfig, SereeEnvironment } from \"./types\";\n\nexport const ENVIRONMENT_BASE_URLS: Record<SereeEnvironment, string> = {\n devnet: \"https://api-lazer.sereel.com\",\n testnet: \"https://api-lazer-v2.sereel.com\",\n mainnet: \"https://cahokia.sereel.com\",\n};\n\nexport interface ResolvedClientConfig {\n environment: SereeEnvironment;\n apiKey: string;\n timeoutMs: number;\n baseUrl: string;\n fetch: typeof fetch;\n}\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\n\nfunction getFetchImplementation(\n providedFetch: ClientConfig[\"fetch\"],\n): typeof fetch {\n if (providedFetch) {\n return providedFetch;\n }\n\n if (typeof globalThis.fetch === \"function\") {\n return globalThis.fetch.bind(globalThis);\n }\n\n throw new InvalidConfigurationError(\n \"No fetch implementation is available. Provide config.fetch in this runtime.\",\n );\n}\n\nfunction normalizeBaseUrl(baseUrl: string): string {\n const trimmed = baseUrl.trim();\n\n if (!trimmed) {\n throw new InvalidConfigurationError(\"baseUrl must not be empty when provided.\");\n }\n\n try {\n return new URL(trimmed).toString().replace(/\\/+$/, \"\");\n } catch (cause) {\n throw new InvalidConfigurationError(\"baseUrl must be a valid absolute URL.\", {\n cause,\n });\n }\n}\n\nexport function resolveBaseUrl(\n environment: SereeEnvironment,\n baseUrl?: string,\n): string {\n if (baseUrl) {\n return normalizeBaseUrl(baseUrl);\n }\n\n return ENVIRONMENT_BASE_URLS[environment];\n}\n\nexport function resolveClientConfig(config: ClientConfig): ResolvedClientConfig {\n const apiKey = config.apiKey.trim();\n\n if (!apiKey) {\n throw new InvalidConfigurationError(\"apiKey must not be empty.\");\n }\n\n const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {\n throw new InvalidConfigurationError(\"timeoutMs must be a positive number.\");\n }\n\n return {\n environment: config.environment,\n apiKey,\n timeoutMs,\n baseUrl: resolveBaseUrl(config.environment, config.baseUrl),\n fetch: getFetchImplementation(config.fetch),\n };\n}\n","import {\n HttpError,\n MalformedResponseError,\n NotFoundError,\n ServerError,\n TimeoutError,\n UnauthorizedError,\n} from \"./errors\";\nimport type { ResolvedClientConfig } from \"./config\";\n\ninterface ApiErrorBody {\n error?: string;\n message?: string;\n}\n\nfunction createTimeoutSignal(timeoutMs: number): {\n signal: AbortSignal;\n cleanup: () => void;\n} {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), timeoutMs);\n\n return {\n signal: controller.signal,\n cleanup: () => clearTimeout(timeout),\n };\n}\n\nasync function parseBody(response: Response): Promise<unknown> {\n const text = await response.text();\n if (!text) {\n return null;\n }\n\n try {\n return JSON.parse(text) as unknown;\n } catch (cause) {\n throw new MalformedResponseError(\"Received a non-JSON response body.\", {\n cause,\n status: response.status,\n details: text,\n });\n }\n}\n\nfunction getErrorMessage(status: number, body: unknown): string {\n if (body && typeof body === \"object\") {\n const apiError = body as ApiErrorBody;\n if (typeof apiError.error === \"string\" && apiError.error.trim()) {\n return apiError.error;\n }\n if (typeof apiError.message === \"string\" && apiError.message.trim()) {\n return apiError.message;\n }\n }\n\n return `Request failed with status ${status}.`;\n}\n\nfunction toHttpError(status: number, body: unknown): HttpError {\n const message = getErrorMessage(status, body);\n const options = { status, details: body };\n\n if (status === 401) {\n return new UnauthorizedError(message, options);\n }\n if (status === 404) {\n return new NotFoundError(message, options);\n }\n if (status >= 500) {\n return new ServerError(message, options);\n }\n\n return new HttpError(message, options);\n}\n\nexport async function requestJson<T>(\n config: ResolvedClientConfig,\n path: string,\n validate: (value: unknown) => T,\n): Promise<T> {\n const { signal, cleanup } = createTimeoutSignal(config.timeoutMs);\n\n try {\n const response = await config.fetch(`${config.baseUrl}${path}`, {\n method: \"GET\",\n signal,\n headers: {\n accept: \"application/json\",\n \"x-api-key\": config.apiKey,\n },\n });\n\n const body = await parseBody(response);\n if (!response.ok) {\n throw toHttpError(response.status, body);\n }\n\n return validate(body);\n } catch (error) {\n if (error instanceof HttpError || error instanceof MalformedResponseError) {\n throw error;\n }\n\n if (error instanceof Error && error.name === \"AbortError\") {\n throw new TimeoutError(\n `Request timed out after ${config.timeoutMs}ms.`,\n { cause: error },\n );\n }\n\n throw error;\n } finally {\n cleanup();\n }\n}\n","import { MalformedResponseError } from \"./errors\";\nimport type {\n SdkAssetRecord,\n SdkAssetResponse,\n SdkAssetsResponse,\n SdkBookSummary,\n SdkSecuritySummary,\n SdkSellerOrganizationSummary,\n} from \"./types\";\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction isString(value: unknown): value is string {\n return typeof value === \"string\";\n}\n\nfunction isNullableString(value: unknown): value is string | null {\n return typeof value === \"string\" || value === null;\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction isSecuritySummary(value: unknown): value is SdkSecuritySummary {\n return (\n isRecord(value) &&\n isString(value.id) &&\n isString(value.token_address) &&\n isString(value.token_name) &&\n isString(value.token_symbol) &&\n isString(value.network_id) &&\n isString(value.token_type)\n );\n}\n\nfunction isSellerOrganizationSummary(\n value: unknown,\n): value is SdkSellerOrganizationSummary {\n return (\n isRecord(value) &&\n isString(value.id) &&\n isString(value.legal_name) &&\n isNullableString(value.display_name) &&\n isString(value.jurisdiction) &&\n isNullableString(value.website)\n );\n}\n\nfunction isBookSummary(value: unknown): value is SdkBookSummary {\n return (\n isRecord(value) &&\n isString(value.id) &&\n isString(value.order_book_address) &&\n isString(value.status) &&\n isString(value.network_id) &&\n isFiniteNumber(value.subscription_start) &&\n isFiniteNumber(value.subscription_end) &&\n isString(value.prospectus_file_url)\n );\n}\n\nfunction isAssetRecord(value: unknown): value is SdkAssetRecord {\n return (\n isRecord(value) &&\n isSecuritySummary(value.security) &&\n isSellerOrganizationSummary(value.seller_organization) &&\n Array.isArray(value.books) &&\n value.books.every(isBookSummary)\n );\n}\n\nexport function validateSdkAssetsResponse(value: unknown): SdkAssetsResponse {\n if (\n !isRecord(value) ||\n !Array.isArray(value.data) ||\n !isFiniteNumber(value.count) ||\n !value.data.every(isAssetRecord)\n ) {\n throw new MalformedResponseError(\n \"Received an invalid SDK assets response shape.\",\n { details: value },\n );\n }\n\n return value as unknown as SdkAssetsResponse;\n}\n\nexport function validateSdkAssetResponse(value: unknown): SdkAssetResponse {\n if (!isRecord(value) || !isAssetRecord(value.data)) {\n throw new MalformedResponseError(\n \"Received an invalid SDK asset response shape.\",\n { details: value },\n );\n }\n\n return value as unknown as SdkAssetResponse;\n}\n","import { resolveClientConfig } from \"./config\";\nimport { InvalidConfigurationError } from \"./errors\";\nimport { requestJson } from \"./transport\";\nimport type {\n ClientConfig,\n SdkAssetResponse,\n SdkAssetsResponse,\n SereeSdkClient,\n} from \"./types\";\nimport {\n validateSdkAssetResponse,\n validateSdkAssetsResponse,\n} from \"./validation\";\n\nexport function createClient(config: ClientConfig): SereeSdkClient {\n const resolved = resolveClientConfig(config);\n\n return {\n getAssets(): Promise<SdkAssetsResponse> {\n return requestJson(resolved, \"/sdk/assets\", validateSdkAssetsResponse);\n },\n\n getAssetByTokenAddress(tokenAddress: string): Promise<SdkAssetResponse> {\n const trimmedTokenAddress = tokenAddress.trim();\n if (!trimmedTokenAddress) {\n throw new InvalidConfigurationError(\n \"tokenAddress must not be empty.\",\n );\n }\n\n return requestJson(\n resolved,\n `/sdk/assets/${encodeURIComponent(trimmedTokenAddress)}`,\n validateSdkAssetResponse,\n );\n },\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
type SereeEnvironment = "devnet" | "testnet" | "mainnet";
|
|
2
|
+
interface ClientConfig {
|
|
3
|
+
environment: SereeEnvironment;
|
|
4
|
+
apiKey: string;
|
|
5
|
+
timeoutMs?: number;
|
|
6
|
+
baseUrl?: string;
|
|
7
|
+
fetch?: typeof fetch;
|
|
8
|
+
}
|
|
9
|
+
interface SdkSecuritySummary {
|
|
10
|
+
id: string;
|
|
11
|
+
token_address: string;
|
|
12
|
+
token_name: string;
|
|
13
|
+
token_symbol: string;
|
|
14
|
+
network_id: string;
|
|
15
|
+
token_type: string;
|
|
16
|
+
}
|
|
17
|
+
interface SdkSellerOrganizationSummary {
|
|
18
|
+
id: string;
|
|
19
|
+
legal_name: string;
|
|
20
|
+
display_name: string | null;
|
|
21
|
+
jurisdiction: string;
|
|
22
|
+
website: string | null;
|
|
23
|
+
}
|
|
24
|
+
interface SdkBookSummary {
|
|
25
|
+
id: string;
|
|
26
|
+
order_book_address: string;
|
|
27
|
+
status: string;
|
|
28
|
+
network_id: string;
|
|
29
|
+
subscription_start: number;
|
|
30
|
+
subscription_end: number;
|
|
31
|
+
prospectus_file_url: string;
|
|
32
|
+
}
|
|
33
|
+
interface SdkAssetRecord {
|
|
34
|
+
security: SdkSecuritySummary;
|
|
35
|
+
seller_organization: SdkSellerOrganizationSummary;
|
|
36
|
+
books: SdkBookSummary[];
|
|
37
|
+
}
|
|
38
|
+
interface SdkAssetsResponse {
|
|
39
|
+
data: SdkAssetRecord[];
|
|
40
|
+
count: number;
|
|
41
|
+
}
|
|
42
|
+
interface SdkAssetResponse {
|
|
43
|
+
data: SdkAssetRecord;
|
|
44
|
+
}
|
|
45
|
+
interface SereeSdkClient {
|
|
46
|
+
getAssets(): Promise<SdkAssetsResponse>;
|
|
47
|
+
getAssetByTokenAddress(tokenAddress: string): Promise<SdkAssetResponse>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
declare function createClient(config: ClientConfig): SereeSdkClient;
|
|
51
|
+
|
|
52
|
+
declare const ENVIRONMENT_BASE_URLS: Record<SereeEnvironment, string>;
|
|
53
|
+
declare function resolveBaseUrl(environment: SereeEnvironment, baseUrl?: string): string;
|
|
54
|
+
|
|
55
|
+
interface SereeSdkErrorOptions {
|
|
56
|
+
status?: number;
|
|
57
|
+
code?: string;
|
|
58
|
+
cause?: unknown;
|
|
59
|
+
details?: unknown;
|
|
60
|
+
}
|
|
61
|
+
declare class SereeSdkError extends Error {
|
|
62
|
+
readonly status: number | undefined;
|
|
63
|
+
readonly code: string | undefined;
|
|
64
|
+
readonly details?: unknown;
|
|
65
|
+
constructor(message: string, options?: SereeSdkErrorOptions);
|
|
66
|
+
}
|
|
67
|
+
declare class InvalidConfigurationError extends SereeSdkError {
|
|
68
|
+
}
|
|
69
|
+
declare class HttpError extends SereeSdkError {
|
|
70
|
+
}
|
|
71
|
+
declare class UnauthorizedError extends HttpError {
|
|
72
|
+
}
|
|
73
|
+
declare class NotFoundError extends HttpError {
|
|
74
|
+
}
|
|
75
|
+
declare class ServerError extends HttpError {
|
|
76
|
+
}
|
|
77
|
+
declare class TimeoutError extends SereeSdkError {
|
|
78
|
+
}
|
|
79
|
+
declare class MalformedResponseError extends SereeSdkError {
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export { type ClientConfig, ENVIRONMENT_BASE_URLS, HttpError, InvalidConfigurationError, MalformedResponseError, NotFoundError, type SdkAssetRecord, type SdkAssetResponse, type SdkAssetsResponse, type SdkBookSummary, type SdkSecuritySummary, type SdkSellerOrganizationSummary, type SereeEnvironment, type SereeSdkClient, SereeSdkError, ServerError, TimeoutError, UnauthorizedError, createClient, resolveBaseUrl };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
type SereeEnvironment = "devnet" | "testnet" | "mainnet";
|
|
2
|
+
interface ClientConfig {
|
|
3
|
+
environment: SereeEnvironment;
|
|
4
|
+
apiKey: string;
|
|
5
|
+
timeoutMs?: number;
|
|
6
|
+
baseUrl?: string;
|
|
7
|
+
fetch?: typeof fetch;
|
|
8
|
+
}
|
|
9
|
+
interface SdkSecuritySummary {
|
|
10
|
+
id: string;
|
|
11
|
+
token_address: string;
|
|
12
|
+
token_name: string;
|
|
13
|
+
token_symbol: string;
|
|
14
|
+
network_id: string;
|
|
15
|
+
token_type: string;
|
|
16
|
+
}
|
|
17
|
+
interface SdkSellerOrganizationSummary {
|
|
18
|
+
id: string;
|
|
19
|
+
legal_name: string;
|
|
20
|
+
display_name: string | null;
|
|
21
|
+
jurisdiction: string;
|
|
22
|
+
website: string | null;
|
|
23
|
+
}
|
|
24
|
+
interface SdkBookSummary {
|
|
25
|
+
id: string;
|
|
26
|
+
order_book_address: string;
|
|
27
|
+
status: string;
|
|
28
|
+
network_id: string;
|
|
29
|
+
subscription_start: number;
|
|
30
|
+
subscription_end: number;
|
|
31
|
+
prospectus_file_url: string;
|
|
32
|
+
}
|
|
33
|
+
interface SdkAssetRecord {
|
|
34
|
+
security: SdkSecuritySummary;
|
|
35
|
+
seller_organization: SdkSellerOrganizationSummary;
|
|
36
|
+
books: SdkBookSummary[];
|
|
37
|
+
}
|
|
38
|
+
interface SdkAssetsResponse {
|
|
39
|
+
data: SdkAssetRecord[];
|
|
40
|
+
count: number;
|
|
41
|
+
}
|
|
42
|
+
interface SdkAssetResponse {
|
|
43
|
+
data: SdkAssetRecord;
|
|
44
|
+
}
|
|
45
|
+
interface SereeSdkClient {
|
|
46
|
+
getAssets(): Promise<SdkAssetsResponse>;
|
|
47
|
+
getAssetByTokenAddress(tokenAddress: string): Promise<SdkAssetResponse>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
declare function createClient(config: ClientConfig): SereeSdkClient;
|
|
51
|
+
|
|
52
|
+
declare const ENVIRONMENT_BASE_URLS: Record<SereeEnvironment, string>;
|
|
53
|
+
declare function resolveBaseUrl(environment: SereeEnvironment, baseUrl?: string): string;
|
|
54
|
+
|
|
55
|
+
interface SereeSdkErrorOptions {
|
|
56
|
+
status?: number;
|
|
57
|
+
code?: string;
|
|
58
|
+
cause?: unknown;
|
|
59
|
+
details?: unknown;
|
|
60
|
+
}
|
|
61
|
+
declare class SereeSdkError extends Error {
|
|
62
|
+
readonly status: number | undefined;
|
|
63
|
+
readonly code: string | undefined;
|
|
64
|
+
readonly details?: unknown;
|
|
65
|
+
constructor(message: string, options?: SereeSdkErrorOptions);
|
|
66
|
+
}
|
|
67
|
+
declare class InvalidConfigurationError extends SereeSdkError {
|
|
68
|
+
}
|
|
69
|
+
declare class HttpError extends SereeSdkError {
|
|
70
|
+
}
|
|
71
|
+
declare class UnauthorizedError extends HttpError {
|
|
72
|
+
}
|
|
73
|
+
declare class NotFoundError extends HttpError {
|
|
74
|
+
}
|
|
75
|
+
declare class ServerError extends HttpError {
|
|
76
|
+
}
|
|
77
|
+
declare class TimeoutError extends SereeSdkError {
|
|
78
|
+
}
|
|
79
|
+
declare class MalformedResponseError extends SereeSdkError {
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export { type ClientConfig, ENVIRONMENT_BASE_URLS, HttpError, InvalidConfigurationError, MalformedResponseError, NotFoundError, type SdkAssetRecord, type SdkAssetResponse, type SdkAssetsResponse, type SdkBookSummary, type SdkSecuritySummary, type SdkSellerOrganizationSummary, type SereeEnvironment, type SereeSdkClient, SereeSdkError, ServerError, TimeoutError, UnauthorizedError, createClient, resolveBaseUrl };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var SereeSdkError = class extends Error {
|
|
3
|
+
status;
|
|
4
|
+
code;
|
|
5
|
+
details;
|
|
6
|
+
constructor(message, options = {}) {
|
|
7
|
+
super(message, options.cause ? { cause: options.cause } : void 0);
|
|
8
|
+
this.name = new.target.name;
|
|
9
|
+
this.status = options.status;
|
|
10
|
+
this.code = options.code;
|
|
11
|
+
this.details = options.details;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
var InvalidConfigurationError = class extends SereeSdkError {
|
|
15
|
+
};
|
|
16
|
+
var HttpError = class extends SereeSdkError {
|
|
17
|
+
};
|
|
18
|
+
var UnauthorizedError = class extends HttpError {
|
|
19
|
+
};
|
|
20
|
+
var NotFoundError = class extends HttpError {
|
|
21
|
+
};
|
|
22
|
+
var ServerError = class extends HttpError {
|
|
23
|
+
};
|
|
24
|
+
var TimeoutError = class extends SereeSdkError {
|
|
25
|
+
};
|
|
26
|
+
var MalformedResponseError = class extends SereeSdkError {
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// src/config.ts
|
|
30
|
+
var ENVIRONMENT_BASE_URLS = {
|
|
31
|
+
devnet: "https://api-lazer.sereel.com",
|
|
32
|
+
testnet: "https://api-lazer-v2.sereel.com",
|
|
33
|
+
mainnet: "https://cahokia.sereel.com"
|
|
34
|
+
};
|
|
35
|
+
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
36
|
+
function getFetchImplementation(providedFetch) {
|
|
37
|
+
if (providedFetch) {
|
|
38
|
+
return providedFetch;
|
|
39
|
+
}
|
|
40
|
+
if (typeof globalThis.fetch === "function") {
|
|
41
|
+
return globalThis.fetch.bind(globalThis);
|
|
42
|
+
}
|
|
43
|
+
throw new InvalidConfigurationError(
|
|
44
|
+
"No fetch implementation is available. Provide config.fetch in this runtime."
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
function normalizeBaseUrl(baseUrl) {
|
|
48
|
+
const trimmed = baseUrl.trim();
|
|
49
|
+
if (!trimmed) {
|
|
50
|
+
throw new InvalidConfigurationError("baseUrl must not be empty when provided.");
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
return new URL(trimmed).toString().replace(/\/+$/, "");
|
|
54
|
+
} catch (cause) {
|
|
55
|
+
throw new InvalidConfigurationError("baseUrl must be a valid absolute URL.", {
|
|
56
|
+
cause
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function resolveBaseUrl(environment, baseUrl) {
|
|
61
|
+
if (baseUrl) {
|
|
62
|
+
return normalizeBaseUrl(baseUrl);
|
|
63
|
+
}
|
|
64
|
+
return ENVIRONMENT_BASE_URLS[environment];
|
|
65
|
+
}
|
|
66
|
+
function resolveClientConfig(config) {
|
|
67
|
+
const apiKey = config.apiKey.trim();
|
|
68
|
+
if (!apiKey) {
|
|
69
|
+
throw new InvalidConfigurationError("apiKey must not be empty.");
|
|
70
|
+
}
|
|
71
|
+
const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
72
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
73
|
+
throw new InvalidConfigurationError("timeoutMs must be a positive number.");
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
environment: config.environment,
|
|
77
|
+
apiKey,
|
|
78
|
+
timeoutMs,
|
|
79
|
+
baseUrl: resolveBaseUrl(config.environment, config.baseUrl),
|
|
80
|
+
fetch: getFetchImplementation(config.fetch)
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// src/transport.ts
|
|
85
|
+
function createTimeoutSignal(timeoutMs) {
|
|
86
|
+
const controller = new AbortController();
|
|
87
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
88
|
+
return {
|
|
89
|
+
signal: controller.signal,
|
|
90
|
+
cleanup: () => clearTimeout(timeout)
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
async function parseBody(response) {
|
|
94
|
+
const text = await response.text();
|
|
95
|
+
if (!text) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
return JSON.parse(text);
|
|
100
|
+
} catch (cause) {
|
|
101
|
+
throw new MalformedResponseError("Received a non-JSON response body.", {
|
|
102
|
+
cause,
|
|
103
|
+
status: response.status,
|
|
104
|
+
details: text
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function getErrorMessage(status, body) {
|
|
109
|
+
if (body && typeof body === "object") {
|
|
110
|
+
const apiError = body;
|
|
111
|
+
if (typeof apiError.error === "string" && apiError.error.trim()) {
|
|
112
|
+
return apiError.error;
|
|
113
|
+
}
|
|
114
|
+
if (typeof apiError.message === "string" && apiError.message.trim()) {
|
|
115
|
+
return apiError.message;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return `Request failed with status ${status}.`;
|
|
119
|
+
}
|
|
120
|
+
function toHttpError(status, body) {
|
|
121
|
+
const message = getErrorMessage(status, body);
|
|
122
|
+
const options = { status, details: body };
|
|
123
|
+
if (status === 401) {
|
|
124
|
+
return new UnauthorizedError(message, options);
|
|
125
|
+
}
|
|
126
|
+
if (status === 404) {
|
|
127
|
+
return new NotFoundError(message, options);
|
|
128
|
+
}
|
|
129
|
+
if (status >= 500) {
|
|
130
|
+
return new ServerError(message, options);
|
|
131
|
+
}
|
|
132
|
+
return new HttpError(message, options);
|
|
133
|
+
}
|
|
134
|
+
async function requestJson(config, path, validate) {
|
|
135
|
+
const { signal, cleanup } = createTimeoutSignal(config.timeoutMs);
|
|
136
|
+
try {
|
|
137
|
+
const response = await config.fetch(`${config.baseUrl}${path}`, {
|
|
138
|
+
method: "GET",
|
|
139
|
+
signal,
|
|
140
|
+
headers: {
|
|
141
|
+
accept: "application/json",
|
|
142
|
+
"x-api-key": config.apiKey
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
const body = await parseBody(response);
|
|
146
|
+
if (!response.ok) {
|
|
147
|
+
throw toHttpError(response.status, body);
|
|
148
|
+
}
|
|
149
|
+
return validate(body);
|
|
150
|
+
} catch (error) {
|
|
151
|
+
if (error instanceof HttpError || error instanceof MalformedResponseError) {
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
155
|
+
throw new TimeoutError(
|
|
156
|
+
`Request timed out after ${config.timeoutMs}ms.`,
|
|
157
|
+
{ cause: error }
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
throw error;
|
|
161
|
+
} finally {
|
|
162
|
+
cleanup();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// src/validation.ts
|
|
167
|
+
function isRecord(value) {
|
|
168
|
+
return typeof value === "object" && value !== null;
|
|
169
|
+
}
|
|
170
|
+
function isString(value) {
|
|
171
|
+
return typeof value === "string";
|
|
172
|
+
}
|
|
173
|
+
function isNullableString(value) {
|
|
174
|
+
return typeof value === "string" || value === null;
|
|
175
|
+
}
|
|
176
|
+
function isFiniteNumber(value) {
|
|
177
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
178
|
+
}
|
|
179
|
+
function isSecuritySummary(value) {
|
|
180
|
+
return isRecord(value) && isString(value.id) && isString(value.token_address) && isString(value.token_name) && isString(value.token_symbol) && isString(value.network_id) && isString(value.token_type);
|
|
181
|
+
}
|
|
182
|
+
function isSellerOrganizationSummary(value) {
|
|
183
|
+
return isRecord(value) && isString(value.id) && isString(value.legal_name) && isNullableString(value.display_name) && isString(value.jurisdiction) && isNullableString(value.website);
|
|
184
|
+
}
|
|
185
|
+
function isBookSummary(value) {
|
|
186
|
+
return isRecord(value) && isString(value.id) && isString(value.order_book_address) && isString(value.status) && isString(value.network_id) && isFiniteNumber(value.subscription_start) && isFiniteNumber(value.subscription_end) && isString(value.prospectus_file_url);
|
|
187
|
+
}
|
|
188
|
+
function isAssetRecord(value) {
|
|
189
|
+
return isRecord(value) && isSecuritySummary(value.security) && isSellerOrganizationSummary(value.seller_organization) && Array.isArray(value.books) && value.books.every(isBookSummary);
|
|
190
|
+
}
|
|
191
|
+
function validateSdkAssetsResponse(value) {
|
|
192
|
+
if (!isRecord(value) || !Array.isArray(value.data) || !isFiniteNumber(value.count) || !value.data.every(isAssetRecord)) {
|
|
193
|
+
throw new MalformedResponseError(
|
|
194
|
+
"Received an invalid SDK assets response shape.",
|
|
195
|
+
{ details: value }
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
return value;
|
|
199
|
+
}
|
|
200
|
+
function validateSdkAssetResponse(value) {
|
|
201
|
+
if (!isRecord(value) || !isAssetRecord(value.data)) {
|
|
202
|
+
throw new MalformedResponseError(
|
|
203
|
+
"Received an invalid SDK asset response shape.",
|
|
204
|
+
{ details: value }
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
return value;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// src/client.ts
|
|
211
|
+
function createClient(config) {
|
|
212
|
+
const resolved = resolveClientConfig(config);
|
|
213
|
+
return {
|
|
214
|
+
getAssets() {
|
|
215
|
+
return requestJson(resolved, "/sdk/assets", validateSdkAssetsResponse);
|
|
216
|
+
},
|
|
217
|
+
getAssetByTokenAddress(tokenAddress) {
|
|
218
|
+
const trimmedTokenAddress = tokenAddress.trim();
|
|
219
|
+
if (!trimmedTokenAddress) {
|
|
220
|
+
throw new InvalidConfigurationError(
|
|
221
|
+
"tokenAddress must not be empty."
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
return requestJson(
|
|
225
|
+
resolved,
|
|
226
|
+
`/sdk/assets/${encodeURIComponent(trimmedTokenAddress)}`,
|
|
227
|
+
validateSdkAssetResponse
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
export {
|
|
233
|
+
ENVIRONMENT_BASE_URLS,
|
|
234
|
+
HttpError,
|
|
235
|
+
InvalidConfigurationError,
|
|
236
|
+
MalformedResponseError,
|
|
237
|
+
NotFoundError,
|
|
238
|
+
SereeSdkError,
|
|
239
|
+
ServerError,
|
|
240
|
+
TimeoutError,
|
|
241
|
+
UnauthorizedError,
|
|
242
|
+
createClient,
|
|
243
|
+
resolveBaseUrl
|
|
244
|
+
};
|
|
245
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/config.ts","../src/transport.ts","../src/validation.ts","../src/client.ts"],"sourcesContent":["export interface SereeSdkErrorOptions {\n status?: number;\n code?: string;\n cause?: unknown;\n details?: unknown;\n}\n\nexport class SereeSdkError extends Error {\n readonly status: number | undefined;\n readonly code: string | undefined;\n readonly details?: unknown;\n\n constructor(message: string, options: SereeSdkErrorOptions = {}) {\n super(message, options.cause ? { cause: options.cause } : undefined);\n this.name = new.target.name;\n this.status = options.status;\n this.code = options.code;\n this.details = options.details;\n }\n}\n\nexport class InvalidConfigurationError extends SereeSdkError {}\n\nexport class HttpError extends SereeSdkError {}\n\nexport class UnauthorizedError extends HttpError {}\n\nexport class NotFoundError extends HttpError {}\n\nexport class ServerError extends HttpError {}\n\nexport class TimeoutError extends SereeSdkError {}\n\nexport class MalformedResponseError extends SereeSdkError {}\n","import { InvalidConfigurationError } from \"./errors\";\nimport type { ClientConfig, SereeEnvironment } from \"./types\";\n\nexport const ENVIRONMENT_BASE_URLS: Record<SereeEnvironment, string> = {\n devnet: \"https://api-lazer.sereel.com\",\n testnet: \"https://api-lazer-v2.sereel.com\",\n mainnet: \"https://cahokia.sereel.com\",\n};\n\nexport interface ResolvedClientConfig {\n environment: SereeEnvironment;\n apiKey: string;\n timeoutMs: number;\n baseUrl: string;\n fetch: typeof fetch;\n}\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\n\nfunction getFetchImplementation(\n providedFetch: ClientConfig[\"fetch\"],\n): typeof fetch {\n if (providedFetch) {\n return providedFetch;\n }\n\n if (typeof globalThis.fetch === \"function\") {\n return globalThis.fetch.bind(globalThis);\n }\n\n throw new InvalidConfigurationError(\n \"No fetch implementation is available. Provide config.fetch in this runtime.\",\n );\n}\n\nfunction normalizeBaseUrl(baseUrl: string): string {\n const trimmed = baseUrl.trim();\n\n if (!trimmed) {\n throw new InvalidConfigurationError(\"baseUrl must not be empty when provided.\");\n }\n\n try {\n return new URL(trimmed).toString().replace(/\\/+$/, \"\");\n } catch (cause) {\n throw new InvalidConfigurationError(\"baseUrl must be a valid absolute URL.\", {\n cause,\n });\n }\n}\n\nexport function resolveBaseUrl(\n environment: SereeEnvironment,\n baseUrl?: string,\n): string {\n if (baseUrl) {\n return normalizeBaseUrl(baseUrl);\n }\n\n return ENVIRONMENT_BASE_URLS[environment];\n}\n\nexport function resolveClientConfig(config: ClientConfig): ResolvedClientConfig {\n const apiKey = config.apiKey.trim();\n\n if (!apiKey) {\n throw new InvalidConfigurationError(\"apiKey must not be empty.\");\n }\n\n const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {\n throw new InvalidConfigurationError(\"timeoutMs must be a positive number.\");\n }\n\n return {\n environment: config.environment,\n apiKey,\n timeoutMs,\n baseUrl: resolveBaseUrl(config.environment, config.baseUrl),\n fetch: getFetchImplementation(config.fetch),\n };\n}\n","import {\n HttpError,\n MalformedResponseError,\n NotFoundError,\n ServerError,\n TimeoutError,\n UnauthorizedError,\n} from \"./errors\";\nimport type { ResolvedClientConfig } from \"./config\";\n\ninterface ApiErrorBody {\n error?: string;\n message?: string;\n}\n\nfunction createTimeoutSignal(timeoutMs: number): {\n signal: AbortSignal;\n cleanup: () => void;\n} {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), timeoutMs);\n\n return {\n signal: controller.signal,\n cleanup: () => clearTimeout(timeout),\n };\n}\n\nasync function parseBody(response: Response): Promise<unknown> {\n const text = await response.text();\n if (!text) {\n return null;\n }\n\n try {\n return JSON.parse(text) as unknown;\n } catch (cause) {\n throw new MalformedResponseError(\"Received a non-JSON response body.\", {\n cause,\n status: response.status,\n details: text,\n });\n }\n}\n\nfunction getErrorMessage(status: number, body: unknown): string {\n if (body && typeof body === \"object\") {\n const apiError = body as ApiErrorBody;\n if (typeof apiError.error === \"string\" && apiError.error.trim()) {\n return apiError.error;\n }\n if (typeof apiError.message === \"string\" && apiError.message.trim()) {\n return apiError.message;\n }\n }\n\n return `Request failed with status ${status}.`;\n}\n\nfunction toHttpError(status: number, body: unknown): HttpError {\n const message = getErrorMessage(status, body);\n const options = { status, details: body };\n\n if (status === 401) {\n return new UnauthorizedError(message, options);\n }\n if (status === 404) {\n return new NotFoundError(message, options);\n }\n if (status >= 500) {\n return new ServerError(message, options);\n }\n\n return new HttpError(message, options);\n}\n\nexport async function requestJson<T>(\n config: ResolvedClientConfig,\n path: string,\n validate: (value: unknown) => T,\n): Promise<T> {\n const { signal, cleanup } = createTimeoutSignal(config.timeoutMs);\n\n try {\n const response = await config.fetch(`${config.baseUrl}${path}`, {\n method: \"GET\",\n signal,\n headers: {\n accept: \"application/json\",\n \"x-api-key\": config.apiKey,\n },\n });\n\n const body = await parseBody(response);\n if (!response.ok) {\n throw toHttpError(response.status, body);\n }\n\n return validate(body);\n } catch (error) {\n if (error instanceof HttpError || error instanceof MalformedResponseError) {\n throw error;\n }\n\n if (error instanceof Error && error.name === \"AbortError\") {\n throw new TimeoutError(\n `Request timed out after ${config.timeoutMs}ms.`,\n { cause: error },\n );\n }\n\n throw error;\n } finally {\n cleanup();\n }\n}\n","import { MalformedResponseError } from \"./errors\";\nimport type {\n SdkAssetRecord,\n SdkAssetResponse,\n SdkAssetsResponse,\n SdkBookSummary,\n SdkSecuritySummary,\n SdkSellerOrganizationSummary,\n} from \"./types\";\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction isString(value: unknown): value is string {\n return typeof value === \"string\";\n}\n\nfunction isNullableString(value: unknown): value is string | null {\n return typeof value === \"string\" || value === null;\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction isSecuritySummary(value: unknown): value is SdkSecuritySummary {\n return (\n isRecord(value) &&\n isString(value.id) &&\n isString(value.token_address) &&\n isString(value.token_name) &&\n isString(value.token_symbol) &&\n isString(value.network_id) &&\n isString(value.token_type)\n );\n}\n\nfunction isSellerOrganizationSummary(\n value: unknown,\n): value is SdkSellerOrganizationSummary {\n return (\n isRecord(value) &&\n isString(value.id) &&\n isString(value.legal_name) &&\n isNullableString(value.display_name) &&\n isString(value.jurisdiction) &&\n isNullableString(value.website)\n );\n}\n\nfunction isBookSummary(value: unknown): value is SdkBookSummary {\n return (\n isRecord(value) &&\n isString(value.id) &&\n isString(value.order_book_address) &&\n isString(value.status) &&\n isString(value.network_id) &&\n isFiniteNumber(value.subscription_start) &&\n isFiniteNumber(value.subscription_end) &&\n isString(value.prospectus_file_url)\n );\n}\n\nfunction isAssetRecord(value: unknown): value is SdkAssetRecord {\n return (\n isRecord(value) &&\n isSecuritySummary(value.security) &&\n isSellerOrganizationSummary(value.seller_organization) &&\n Array.isArray(value.books) &&\n value.books.every(isBookSummary)\n );\n}\n\nexport function validateSdkAssetsResponse(value: unknown): SdkAssetsResponse {\n if (\n !isRecord(value) ||\n !Array.isArray(value.data) ||\n !isFiniteNumber(value.count) ||\n !value.data.every(isAssetRecord)\n ) {\n throw new MalformedResponseError(\n \"Received an invalid SDK assets response shape.\",\n { details: value },\n );\n }\n\n return value as unknown as SdkAssetsResponse;\n}\n\nexport function validateSdkAssetResponse(value: unknown): SdkAssetResponse {\n if (!isRecord(value) || !isAssetRecord(value.data)) {\n throw new MalformedResponseError(\n \"Received an invalid SDK asset response shape.\",\n { details: value },\n );\n }\n\n return value as unknown as SdkAssetResponse;\n}\n","import { resolveClientConfig } from \"./config\";\nimport { InvalidConfigurationError } from \"./errors\";\nimport { requestJson } from \"./transport\";\nimport type {\n ClientConfig,\n SdkAssetResponse,\n SdkAssetsResponse,\n SereeSdkClient,\n} from \"./types\";\nimport {\n validateSdkAssetResponse,\n validateSdkAssetsResponse,\n} from \"./validation\";\n\nexport function createClient(config: ClientConfig): SereeSdkClient {\n const resolved = resolveClientConfig(config);\n\n return {\n getAssets(): Promise<SdkAssetsResponse> {\n return requestJson(resolved, \"/sdk/assets\", validateSdkAssetsResponse);\n },\n\n getAssetByTokenAddress(tokenAddress: string): Promise<SdkAssetResponse> {\n const trimmedTokenAddress = tokenAddress.trim();\n if (!trimmedTokenAddress) {\n throw new InvalidConfigurationError(\n \"tokenAddress must not be empty.\",\n );\n }\n\n return requestJson(\n resolved,\n `/sdk/assets/${encodeURIComponent(trimmedTokenAddress)}`,\n validateSdkAssetResponse,\n );\n },\n };\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sereel/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "TypeScript SDK for Seree asset read endpoints",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.cjs",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"require": "./dist/index.cjs"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"sideEffects": false,
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=18"
|
|
24
|
+
},
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"tsup": "^8.5.0",
|
|
30
|
+
"typescript": "^5.9.3",
|
|
31
|
+
"vitest": "^3.2.4"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsup",
|
|
35
|
+
"test": "vitest run",
|
|
36
|
+
"typecheck": "tsc --noEmit"
|
|
37
|
+
}
|
|
38
|
+
}
|