Bot
This commit is contained in:
+131
@@ -0,0 +1,131 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.CoreApiClient = exports.CoreApiClientError = void 0;
|
||||
class CoreApiClientError extends Error {
|
||||
status;
|
||||
constructor(message, status) {
|
||||
super(message);
|
||||
this.name = 'CoreApiClientError';
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
exports.CoreApiClientError = CoreApiClientError;
|
||||
class CoreApiClient {
|
||||
apiUrl;
|
||||
clientId;
|
||||
clientSecret;
|
||||
timeoutMs;
|
||||
cachedToken = null;
|
||||
tokenExpiry = 0; // epoch ms
|
||||
tokenMarginSec = 60; // safety margin in seconds
|
||||
constructor(options) {
|
||||
this.apiUrl = options?.apiUrl ?? process.env.RAYLAB_CORE_API_URL ?? 'http://localhost:3000';
|
||||
this.clientId = options?.clientId ?? process.env.RAYLAB_BOT_CLIENT_ID ?? '';
|
||||
this.clientSecret = options?.clientSecret ?? process.env.RAYLAB_BOT_CLIENT_SECRET ?? '';
|
||||
this.timeoutMs = options?.timeoutMs ?? 5000;
|
||||
if (!this.clientId || !this.clientSecret) {
|
||||
// keep construction allowed but operations will fail with clear errors
|
||||
}
|
||||
}
|
||||
async fetchWithTimeout(url, init) {
|
||||
const controller = new AbortController();
|
||||
const id = setTimeout(() => controller.abort(), this.timeoutMs);
|
||||
try {
|
||||
const res = await fetch(url, { ...init, signal: controller.signal });
|
||||
return res;
|
||||
}
|
||||
finally {
|
||||
clearTimeout(id);
|
||||
}
|
||||
}
|
||||
isTokenValid() {
|
||||
return !!this.cachedToken && Date.now() < this.tokenExpiry;
|
||||
}
|
||||
async requestAccessToken() {
|
||||
if (!this.clientId || !this.clientSecret) {
|
||||
throw new CoreApiClientError('Missing client credentials');
|
||||
}
|
||||
const url = `${this.apiUrl.replace(/\/$/, '')}/api/v1/auth/token`;
|
||||
const body = JSON.stringify({ client_id: this.clientId, client_secret: this.clientSecret, grant_type: 'client_credentials' });
|
||||
let res;
|
||||
try {
|
||||
res = await this.fetchWithTimeout(url, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body,
|
||||
});
|
||||
}
|
||||
catch (err) {
|
||||
if (err.name === 'AbortError') {
|
||||
throw new CoreApiClientError('Request timeout');
|
||||
}
|
||||
throw new CoreApiClientError('Network error');
|
||||
}
|
||||
if (res.status === 401) {
|
||||
throw new CoreApiClientError('Invalid client credentials', 401);
|
||||
}
|
||||
if (res.status >= 400) {
|
||||
throw new CoreApiClientError(`Token request failed with status ${res.status}`, res.status);
|
||||
}
|
||||
const payload = await res.json();
|
||||
// Expecting { success: true, data: { access_token, token_type, expires_in }, ... }
|
||||
const data = payload?.data;
|
||||
if (!data || !data.access_token) {
|
||||
throw new CoreApiClientError('Invalid token response');
|
||||
}
|
||||
// Cache token
|
||||
this.cachedToken = data.access_token;
|
||||
const expiresIn = typeof data.expires_in === 'number' ? data.expires_in : parseInt(data.expires_in, 10) || 3600;
|
||||
const effective = Math.max(0, expiresIn - this.tokenMarginSec);
|
||||
this.tokenExpiry = Date.now() + effective * 1000;
|
||||
return { access_token: data.access_token, token_type: data.token_type ?? 'Bearer', expires_in: expiresIn };
|
||||
}
|
||||
async getToken() {
|
||||
if (this.isTokenValid()) {
|
||||
return this.cachedToken;
|
||||
}
|
||||
const tokenResp = await this.requestAccessToken();
|
||||
return tokenResp.access_token;
|
||||
}
|
||||
async authenticatedRequest(input, init, retry = true) {
|
||||
const token = await this.getToken();
|
||||
const headers = new Headers(init?.headers);
|
||||
headers.set('Authorization', `Bearer ${token}`);
|
||||
headers.set('Accept', 'application/json');
|
||||
let res;
|
||||
try {
|
||||
res = await this.fetchWithTimeout(typeof input === 'string' ? input : input.url, {
|
||||
...init,
|
||||
headers,
|
||||
});
|
||||
}
|
||||
catch (err) {
|
||||
if (err.name === 'AbortError') {
|
||||
throw new CoreApiClientError('Request timeout');
|
||||
}
|
||||
throw new CoreApiClientError('Network error');
|
||||
}
|
||||
if (res.status === 401 && retry) {
|
||||
// invalidate token and retry once
|
||||
this.cachedToken = null;
|
||||
this.tokenExpiry = 0;
|
||||
try {
|
||||
const newToken = await this.getToken();
|
||||
const headers2 = new Headers(init?.headers);
|
||||
headers2.set('Authorization', `Bearer ${newToken}`);
|
||||
headers2.set('Accept', 'application/json');
|
||||
const res2 = await this.fetchWithTimeout(typeof input === 'string' ? input : input.url, {
|
||||
...init,
|
||||
headers: headers2,
|
||||
});
|
||||
return res2;
|
||||
}
|
||||
catch (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
exports.CoreApiClient = CoreApiClient;
|
||||
//# sourceMappingURL=core-api-client.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"core-api-client.js","sourceRoot":"","sources":["../../../src/adapters/notification/core-api-client.ts"],"names":[],"mappings":"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"}
|
||||
Reference in New Issue
Block a user