@bloque/sdk-core 0.0.1 → 0.0.3
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/dist/constants.d.ts +5 -0
- package/dist/errors.d.ts +8 -0
- package/dist/http-client.d.ts +10 -0
- package/dist/index.cjs +141 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +99 -0
- package/dist/types.d.ts +124 -0
- package/package.json +1 -1
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare class BloqueAPIError extends Error {
|
|
2
|
+
readonly status?: number;
|
|
3
|
+
readonly code?: string;
|
|
4
|
+
constructor(message: string, status?: number, code?: string);
|
|
5
|
+
}
|
|
6
|
+
export declare class BloqueConfigError extends Error {
|
|
7
|
+
constructor(message: string);
|
|
8
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { BloqueConfig, RequestOptions } from './types';
|
|
2
|
+
export declare class HttpClient {
|
|
3
|
+
private readonly config;
|
|
4
|
+
private readonly baseUrl;
|
|
5
|
+
private readonly publicRoutes;
|
|
6
|
+
constructor(config: BloqueConfig);
|
|
7
|
+
private isPublicRoute;
|
|
8
|
+
private validateConfig;
|
|
9
|
+
request<T, U = unknown>(options: RequestOptions<U>): Promise<T>;
|
|
10
|
+
}
|
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
1
24
|
var __webpack_exports__ = {};
|
|
2
|
-
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
API_BASE_URLS: ()=>API_BASE_URLS,
|
|
28
|
+
DEFAULT_HEADERS: ()=>DEFAULT_HEADERS,
|
|
29
|
+
HttpClient: ()=>HttpClient,
|
|
30
|
+
BloqueAPIError: ()=>BloqueAPIError,
|
|
31
|
+
BloqueConfigError: ()=>BloqueConfigError
|
|
32
|
+
});
|
|
33
|
+
const API_BASE_URLS = {
|
|
34
|
+
sandbox: 'https://dev.bloque.app',
|
|
35
|
+
production: 'https://api.bloque.app'
|
|
36
|
+
};
|
|
37
|
+
const DEFAULT_HEADERS = {
|
|
38
|
+
'Content-Type': 'application/json'
|
|
39
|
+
};
|
|
40
|
+
class BloqueAPIError extends Error {
|
|
41
|
+
status;
|
|
42
|
+
code;
|
|
43
|
+
constructor(message, status, code){
|
|
44
|
+
super(message);
|
|
45
|
+
this.name = 'BloqueAPIError';
|
|
46
|
+
this.status = status;
|
|
47
|
+
this.code = code;
|
|
48
|
+
Object.setPrototypeOf(this, BloqueAPIError.prototype);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
class BloqueConfigError extends Error {
|
|
52
|
+
constructor(message){
|
|
53
|
+
super(message);
|
|
54
|
+
this.name = 'BloqueConfigError';
|
|
55
|
+
Object.setPrototypeOf(this, BloqueConfigError.prototype);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const createLocalStorageAdapter = ()=>({
|
|
59
|
+
get: ()=>{
|
|
60
|
+
if ('undefined' == typeof localStorage) return null;
|
|
61
|
+
return localStorage.getItem('access_token');
|
|
62
|
+
},
|
|
63
|
+
set: (token)=>{
|
|
64
|
+
if ('undefined' != typeof localStorage) localStorage.setItem('access_token', token);
|
|
65
|
+
},
|
|
66
|
+
clear: ()=>{
|
|
67
|
+
if ('undefined' != typeof localStorage) localStorage.removeItem('access_token');
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
class HttpClient {
|
|
71
|
+
config;
|
|
72
|
+
baseUrl;
|
|
73
|
+
publicRoutes = [
|
|
74
|
+
'/api/aliases',
|
|
75
|
+
'/api/origins/*/assert'
|
|
76
|
+
];
|
|
77
|
+
constructor(config){
|
|
78
|
+
this.validateConfig(config);
|
|
79
|
+
this.config = config;
|
|
80
|
+
this.baseUrl = API_BASE_URLS[config.mode ?? 'production'];
|
|
81
|
+
}
|
|
82
|
+
isPublicRoute(path) {
|
|
83
|
+
const pathWithoutQuery = path.split('?')[0];
|
|
84
|
+
return this.publicRoutes.some((route)=>{
|
|
85
|
+
const pattern = route.replace(/\*/g, '[^/]+');
|
|
86
|
+
const regex = new RegExp(`^${pattern}$`);
|
|
87
|
+
return regex.test(pathWithoutQuery);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
validateConfig(config) {
|
|
91
|
+
if (!config.apiKey || '' === config.apiKey.trim()) throw new BloqueConfigError('API key is required');
|
|
92
|
+
if (!config.mode) config.mode = 'production';
|
|
93
|
+
if (![
|
|
94
|
+
'sandbox',
|
|
95
|
+
'production'
|
|
96
|
+
].includes(config.mode)) throw new BloqueConfigError('Mode must be either "sandbox" or "production"');
|
|
97
|
+
if ('client' === config.runtime && !config.tokenStorage) config.tokenStorage = createLocalStorageAdapter();
|
|
98
|
+
}
|
|
99
|
+
async request(options) {
|
|
100
|
+
const { method, path, body, headers = {} } = options;
|
|
101
|
+
const url = `${this.baseUrl}${path}`;
|
|
102
|
+
const requestHeaders = {
|
|
103
|
+
...DEFAULT_HEADERS,
|
|
104
|
+
Authorization: this.config.apiKey,
|
|
105
|
+
...headers
|
|
106
|
+
};
|
|
107
|
+
if ('client' === this.config.runtime && !this.isPublicRoute(path)) {
|
|
108
|
+
const token = this.config.tokenStorage?.get();
|
|
109
|
+
if (!token) throw new BloqueConfigError('Authentication token is missing');
|
|
110
|
+
requestHeaders.Authorization = `Bearer ${token}`;
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
const response = await fetch(url, {
|
|
114
|
+
method,
|
|
115
|
+
headers: requestHeaders,
|
|
116
|
+
body: body ? JSON.stringify(body) : void 0
|
|
117
|
+
});
|
|
118
|
+
const responseData = await response.json().catch(()=>({}));
|
|
119
|
+
if (!response.ok) {
|
|
120
|
+
const errorData = responseData;
|
|
121
|
+
throw new BloqueAPIError(errorData.message || `HTTP ${response.status}: ${response.statusText}`, response.status, errorData.code);
|
|
122
|
+
}
|
|
123
|
+
return responseData;
|
|
124
|
+
} catch (error) {
|
|
125
|
+
if (error instanceof BloqueAPIError) throw error;
|
|
126
|
+
if (error instanceof Error) throw new BloqueAPIError(`Request failed: ${error.message}`, void 0, 'NETWORK_ERROR');
|
|
127
|
+
throw new BloqueAPIError('Unknown error occurred', void 0, 'UNKNOWN_ERROR');
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
exports.API_BASE_URLS = __webpack_exports__.API_BASE_URLS;
|
|
132
|
+
exports.BloqueAPIError = __webpack_exports__.BloqueAPIError;
|
|
133
|
+
exports.BloqueConfigError = __webpack_exports__.BloqueConfigError;
|
|
134
|
+
exports.DEFAULT_HEADERS = __webpack_exports__.DEFAULT_HEADERS;
|
|
135
|
+
exports.HttpClient = __webpack_exports__.HttpClient;
|
|
136
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
137
|
+
"API_BASE_URLS",
|
|
138
|
+
"BloqueAPIError",
|
|
139
|
+
"BloqueConfigError",
|
|
140
|
+
"DEFAULT_HEADERS",
|
|
141
|
+
"HttpClient"
|
|
142
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
3
143
|
Object.defineProperty(exports, '__esModule', {
|
|
4
144
|
value: true
|
|
5
145
|
});
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
const API_BASE_URLS = {
|
|
2
|
+
sandbox: 'https://dev.bloque.app',
|
|
3
|
+
production: 'https://api.bloque.app'
|
|
4
|
+
};
|
|
5
|
+
const DEFAULT_HEADERS = {
|
|
6
|
+
'Content-Type': 'application/json'
|
|
7
|
+
};
|
|
8
|
+
class BloqueAPIError extends Error {
|
|
9
|
+
status;
|
|
10
|
+
code;
|
|
11
|
+
constructor(message, status, code){
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = 'BloqueAPIError';
|
|
14
|
+
this.status = status;
|
|
15
|
+
this.code = code;
|
|
16
|
+
Object.setPrototypeOf(this, BloqueAPIError.prototype);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
class BloqueConfigError extends Error {
|
|
20
|
+
constructor(message){
|
|
21
|
+
super(message);
|
|
22
|
+
this.name = 'BloqueConfigError';
|
|
23
|
+
Object.setPrototypeOf(this, BloqueConfigError.prototype);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const createLocalStorageAdapter = ()=>({
|
|
27
|
+
get: ()=>{
|
|
28
|
+
if ('undefined' == typeof localStorage) return null;
|
|
29
|
+
return localStorage.getItem('access_token');
|
|
30
|
+
},
|
|
31
|
+
set: (token)=>{
|
|
32
|
+
if ('undefined' != typeof localStorage) localStorage.setItem('access_token', token);
|
|
33
|
+
},
|
|
34
|
+
clear: ()=>{
|
|
35
|
+
if ('undefined' != typeof localStorage) localStorage.removeItem('access_token');
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
class HttpClient {
|
|
39
|
+
config;
|
|
40
|
+
baseUrl;
|
|
41
|
+
publicRoutes = [
|
|
42
|
+
'/api/aliases',
|
|
43
|
+
'/api/origins/*/assert'
|
|
44
|
+
];
|
|
45
|
+
constructor(config){
|
|
46
|
+
this.validateConfig(config);
|
|
47
|
+
this.config = config;
|
|
48
|
+
this.baseUrl = API_BASE_URLS[config.mode ?? 'production'];
|
|
49
|
+
}
|
|
50
|
+
isPublicRoute(path) {
|
|
51
|
+
const pathWithoutQuery = path.split('?')[0];
|
|
52
|
+
return this.publicRoutes.some((route)=>{
|
|
53
|
+
const pattern = route.replace(/\*/g, '[^/]+');
|
|
54
|
+
const regex = new RegExp(`^${pattern}$`);
|
|
55
|
+
return regex.test(pathWithoutQuery);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
validateConfig(config) {
|
|
59
|
+
if (!config.apiKey || '' === config.apiKey.trim()) throw new BloqueConfigError('API key is required');
|
|
60
|
+
if (!config.mode) config.mode = 'production';
|
|
61
|
+
if (![
|
|
62
|
+
'sandbox',
|
|
63
|
+
'production'
|
|
64
|
+
].includes(config.mode)) throw new BloqueConfigError('Mode must be either "sandbox" or "production"');
|
|
65
|
+
if ('client' === config.runtime && !config.tokenStorage) config.tokenStorage = createLocalStorageAdapter();
|
|
66
|
+
}
|
|
67
|
+
async request(options) {
|
|
68
|
+
const { method, path, body, headers = {} } = options;
|
|
69
|
+
const url = `${this.baseUrl}${path}`;
|
|
70
|
+
const requestHeaders = {
|
|
71
|
+
...DEFAULT_HEADERS,
|
|
72
|
+
Authorization: this.config.apiKey,
|
|
73
|
+
...headers
|
|
74
|
+
};
|
|
75
|
+
if ('client' === this.config.runtime && !this.isPublicRoute(path)) {
|
|
76
|
+
const token = this.config.tokenStorage?.get();
|
|
77
|
+
if (!token) throw new BloqueConfigError('Authentication token is missing');
|
|
78
|
+
requestHeaders.Authorization = `Bearer ${token}`;
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
const response = await fetch(url, {
|
|
82
|
+
method,
|
|
83
|
+
headers: requestHeaders,
|
|
84
|
+
body: body ? JSON.stringify(body) : void 0
|
|
85
|
+
});
|
|
86
|
+
const responseData = await response.json().catch(()=>({}));
|
|
87
|
+
if (!response.ok) {
|
|
88
|
+
const errorData = responseData;
|
|
89
|
+
throw new BloqueAPIError(errorData.message || `HTTP ${response.status}: ${response.statusText}`, response.status, errorData.code);
|
|
90
|
+
}
|
|
91
|
+
return responseData;
|
|
92
|
+
} catch (error) {
|
|
93
|
+
if (error instanceof BloqueAPIError) throw error;
|
|
94
|
+
if (error instanceof Error) throw new BloqueAPIError(`Request failed: ${error.message}`, void 0, 'NETWORK_ERROR');
|
|
95
|
+
throw new BloqueAPIError('Unknown error occurred', void 0, 'UNKNOWN_ERROR');
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
export { API_BASE_URLS, BloqueAPIError, BloqueConfigError, DEFAULT_HEADERS, HttpClient };
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
export type Mode =
|
|
2
|
+
/**
|
|
3
|
+
* Production environment.
|
|
4
|
+
*
|
|
5
|
+
* Uses live endpoints and real data.
|
|
6
|
+
* This is the default mode.
|
|
7
|
+
*/
|
|
8
|
+
'production'
|
|
9
|
+
/**
|
|
10
|
+
* Sandbox environment.
|
|
11
|
+
*
|
|
12
|
+
* Uses isolated endpoints and mock data for development and testing.
|
|
13
|
+
*/
|
|
14
|
+
| 'sandbox';
|
|
15
|
+
export type Runtime =
|
|
16
|
+
/**
|
|
17
|
+
* Server runtime (default).
|
|
18
|
+
*
|
|
19
|
+
* Intended for backend environments such as Node.js, Bun,
|
|
20
|
+
* Deno, Edge runtimes, or any server-side execution context.
|
|
21
|
+
*
|
|
22
|
+
* Allows the use of private API keys.
|
|
23
|
+
*/
|
|
24
|
+
'server'
|
|
25
|
+
/**
|
|
26
|
+
* Client runtime.
|
|
27
|
+
*
|
|
28
|
+
* Intended for browsers or frontend runtimes.
|
|
29
|
+
*
|
|
30
|
+
* In the current version of the SDK:
|
|
31
|
+
* - The client authenticates using the `auth` module.
|
|
32
|
+
* - The SDK automatically obtains and manages a JWT.
|
|
33
|
+
* - The JWT is used to authenticate all subsequent requests.
|
|
34
|
+
* - An authenticated client can execute any operation
|
|
35
|
+
* exposed by the API.
|
|
36
|
+
*
|
|
37
|
+
* Authorization and security enforcement are handled
|
|
38
|
+
* exclusively by the backend.
|
|
39
|
+
*/
|
|
40
|
+
| 'client';
|
|
41
|
+
/**
|
|
42
|
+
* Interface that defines how the SDK stores and retrieves
|
|
43
|
+
* the JWT token when running in `client` runtime.
|
|
44
|
+
*
|
|
45
|
+
* This allows consumers to customize the storage mechanism
|
|
46
|
+
* (localStorage, sessionStorage, cookies, in-memory, etc.).
|
|
47
|
+
*/
|
|
48
|
+
export interface TokenStorage {
|
|
49
|
+
/**
|
|
50
|
+
* Retrieves the currently stored JWT.
|
|
51
|
+
*
|
|
52
|
+
* @returns The JWT token, or `null` if no token is stored.
|
|
53
|
+
*/
|
|
54
|
+
get(): string | null;
|
|
55
|
+
/**
|
|
56
|
+
* Persists a JWT token.
|
|
57
|
+
*
|
|
58
|
+
* @param token The JWT token to store.
|
|
59
|
+
*/
|
|
60
|
+
set(token: string): void;
|
|
61
|
+
/**
|
|
62
|
+
* Clears the stored JWT token.
|
|
63
|
+
*/
|
|
64
|
+
clear(): void;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Main configuration object for the Bloque SDK.
|
|
68
|
+
*
|
|
69
|
+
* This configuration is resolved once when initializing
|
|
70
|
+
* the SDK (via `new SDK()` or `init()` in the modular API).
|
|
71
|
+
*/
|
|
72
|
+
export interface BloqueConfig {
|
|
73
|
+
/**
|
|
74
|
+
* Bloque API key.
|
|
75
|
+
*
|
|
76
|
+
* - In `server` runtime, a private API key is expected.
|
|
77
|
+
* - In `client` runtime, the API key is not used directly;
|
|
78
|
+
* authentication is performed via JWT instead.
|
|
79
|
+
*/
|
|
80
|
+
apiKey: string;
|
|
81
|
+
/**
|
|
82
|
+
* SDK operation mode.
|
|
83
|
+
*
|
|
84
|
+
* - `production` (default): production environment.
|
|
85
|
+
* - `sandbox`: sandbox environment.
|
|
86
|
+
*
|
|
87
|
+
* If not specified, the SDK defaults to `production`.
|
|
88
|
+
*/
|
|
89
|
+
mode?: Mode;
|
|
90
|
+
/**
|
|
91
|
+
* Runtime environment where the SDK is executed.
|
|
92
|
+
*
|
|
93
|
+
* - `server` (default): backend runtime using API keys.
|
|
94
|
+
* - `client`: frontend runtime using JWT authentication.
|
|
95
|
+
*
|
|
96
|
+
* If not specified, the SDK defaults to `server`.
|
|
97
|
+
*/
|
|
98
|
+
runtime?: 'server' | 'client';
|
|
99
|
+
/**
|
|
100
|
+
* JWT token storage strategy.
|
|
101
|
+
*
|
|
102
|
+
* Only applies when `runtime` is set to `client`.
|
|
103
|
+
*
|
|
104
|
+
* By default, the SDK uses `localStorage` to persist
|
|
105
|
+
* the JWT token. This behavior can be overridden to
|
|
106
|
+
* use alternative storage mechanisms.
|
|
107
|
+
*/
|
|
108
|
+
tokenStorage?: TokenStorage;
|
|
109
|
+
}
|
|
110
|
+
export interface RequestOptions<U = unknown> {
|
|
111
|
+
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
|
112
|
+
path: string;
|
|
113
|
+
body?: U;
|
|
114
|
+
headers?: Record<string, string>;
|
|
115
|
+
}
|
|
116
|
+
export interface BloqueResponse<T> {
|
|
117
|
+
data?: T;
|
|
118
|
+
error?: BloqueError;
|
|
119
|
+
}
|
|
120
|
+
export interface BloqueError {
|
|
121
|
+
message: string;
|
|
122
|
+
code?: string;
|
|
123
|
+
status?: number;
|
|
124
|
+
}
|