logflare-transport-core
Advanced tools
Comparing version 0.2.4 to 0.2.5-1a27192b
@@ -1,6 +0,3 @@ | ||
/// <reference types="node" /> | ||
import { AxiosInstance } from "axios"; | ||
import stream from "stream"; | ||
interface IngestTransformsI { | ||
jsNumbers: boolean; | ||
numbersToFloats: boolean; | ||
} | ||
@@ -16,3 +13,2 @@ interface LogflareUserOptionsI { | ||
declare class LogflareHttpClient { | ||
protected axiosInstance: AxiosInstance; | ||
protected readonly sourceToken: string; | ||
@@ -23,10 +19,8 @@ protected readonly transforms?: IngestTransformsI; | ||
protected readonly fromBrowser: boolean; | ||
protected readonly apiBaseUrl: string; | ||
constructor(options: LogflareUserOptionsI); | ||
addLogEvent(logEvent: object | object[]): Promise<object>; | ||
insertStream(): stream.Writable; | ||
postLogEvents(batch: object[]): Promise<any>; | ||
private _initializeResponseInterceptor; | ||
private _handleResponse; | ||
protected _handleError: (error: any) => Promise<never>; | ||
addTypecasting(): Promise<void>; | ||
} | ||
export { LogflareHttpClient, LogflareUserOptionsI }; |
"use strict"; | ||
var __extends = (this && this.__extends) || (function () { | ||
var extendStatics = function (d, b) { | ||
extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
}; | ||
return function (d, b) { | ||
if (typeof b !== "function" && b !== null) | ||
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); | ||
extendStatics(d, b); | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
}; | ||
})(); | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
@@ -38,26 +53,21 @@ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.LogflareHttpClient = void 0; | ||
var axios_1 = __importDefault(require("axios")); | ||
var lodash_1 = __importDefault(require("lodash")); | ||
var typecasting_1 = require("./typecasting"); | ||
var stream_1 = __importDefault(require("stream")); | ||
var defaultOptions = { | ||
apiBaseUrl: "https://api.logflare.app", | ||
}; | ||
var NetworkError = /** @class */ (function (_super) { | ||
__extends(NetworkError, _super); | ||
function NetworkError(message, response, data) { | ||
var _this = _super.call(this, message) || this; | ||
_this.response = response; | ||
_this.data = data; | ||
_this.name = "NetworkError"; | ||
return _this; | ||
} | ||
return NetworkError; | ||
}(Error)); | ||
var LogflareHttpClient = /** @class */ (function () { | ||
function LogflareHttpClient(options) { | ||
var _this = this; | ||
var _a; | ||
this._initializeResponseInterceptor = function () { | ||
_this.axiosInstance.interceptors.response.use(_this._handleResponse, _this._handleError); | ||
}; | ||
this._handleResponse = function (_a) { | ||
var data = _a.data; | ||
return data; | ||
}; | ||
this._handleError = function (error) { return Promise.reject(error); }; | ||
var sourceToken = options.sourceToken, apiKey = options.apiKey, transforms = options.transforms, endpoint = options.endpoint; | ||
@@ -75,19 +85,9 @@ if (!sourceToken || sourceToken == "") { | ||
this.apiKey = apiKey; | ||
this.axiosInstance = axios_1.default.create({ | ||
baseURL: options.apiBaseUrl || defaultOptions.apiBaseUrl, | ||
headers: { | ||
"Content-Type": "application/json" | ||
}, | ||
}); | ||
this._initializeResponseInterceptor(); | ||
this.apiBaseUrl = options.apiBaseUrl || defaultOptions.apiBaseUrl; | ||
} | ||
LogflareHttpClient.prototype.addLogEvent = function (logEvent) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function () { | ||
var logEvents; | ||
return __generator(this, function (_b) { | ||
return __generator(this, function (_a) { | ||
logEvents = Array.isArray(logEvent) ? logEvent : [logEvent]; | ||
if ((_a = this === null || this === void 0 ? void 0 : this.transforms) === null || _a === void 0 ? void 0 : _a.jsNumbers) { | ||
logEvents = lodash_1.default.map(logEvents, typecasting_1.applyNumberToStringTypecasting); | ||
} | ||
return [2 /*return*/, this.postLogEvents(logEvents)]; | ||
@@ -97,20 +97,5 @@ }); | ||
}; | ||
LogflareHttpClient.prototype.insertStream = function () { | ||
var self = this; | ||
var writeStream = new stream_1.default.Writable({ | ||
objectMode: true, | ||
highWaterMark: 1, | ||
}); | ||
writeStream._write = function (chunk, encoding, callback) { | ||
self.addLogEvent(chunk) | ||
.then(function () { | ||
callback(null); | ||
}) | ||
.catch(callback); | ||
}; | ||
return writeStream; | ||
}; | ||
LogflareHttpClient.prototype.postLogEvents = function (batch) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var url, payload, e_1; | ||
var path, payload, url, response, data, e_1; | ||
return __generator(this, function (_a) { | ||
@@ -120,28 +105,43 @@ switch (_a.label) { | ||
if (this.endpoint === "typecasting") { | ||
url = "/logs/typecasts?api_key=" + this.apiKey + "&source=" + this.sourceToken; | ||
path = "/logs/typecasts?api_key=".concat(this.apiKey, "&source=").concat(this.sourceToken); | ||
} | ||
else { | ||
url = "/logs?api_key=" + this.apiKey + "&source=" + this.sourceToken; | ||
path = "/logs?api_key=".concat(this.apiKey, "&source=").concat(this.sourceToken); | ||
} | ||
payload = { | ||
batch: batch | ||
batch: batch, | ||
}; | ||
_a.label = 1; | ||
case 1: | ||
_a.trys.push([1, 3, , 4]); | ||
return [4 /*yield*/, this.axiosInstance.post(url, payload)]; | ||
case 2: return [2 /*return*/, _a.sent()]; | ||
_a.trys.push([1, 4, , 5]); | ||
url = new URL(path, this.apiBaseUrl); | ||
return [4 /*yield*/, fetch(url.toString(), { | ||
body: JSON.stringify(payload), | ||
method: "POST", | ||
headers: { | ||
Accept: "application/json, text/plain, */*", | ||
"Content-Type": "application/json", | ||
}, | ||
})]; | ||
case 2: | ||
response = _a.sent(); | ||
return [4 /*yield*/, response.json()]; | ||
case 3: | ||
data = _a.sent(); | ||
if (!response.ok) { | ||
throw new NetworkError("Network response was not ok for \"".concat(url, "\""), response, data); | ||
} | ||
return [2 /*return*/, data]; | ||
case 4: | ||
e_1 = _a.sent(); | ||
if (e_1.response) { | ||
console.error("Logflare API request failed with " + e_1.response.status + " status: " + JSON.stringify(e_1.response.data)); | ||
if (e_1) { | ||
if (e_1 instanceof NetworkError && e_1.response) { | ||
console.error("Logflare API request failed with ".concat(e_1.response.status, " status: ").concat(JSON.stringify(e_1.data))); | ||
} | ||
else if (e_1 instanceof Error) { | ||
console.error(e_1.message); | ||
} | ||
} | ||
else if (e_1.request) { | ||
console.error("Logflare API request failed: " + e_1.request); | ||
} | ||
else { | ||
console.error(e_1.message); | ||
} | ||
return [2 /*return*/, e_1]; | ||
case 4: return [2 /*return*/]; | ||
case 5: return [2 /*return*/]; | ||
} | ||
@@ -151,2 +151,23 @@ }); | ||
}; | ||
LogflareHttpClient.prototype.addTypecasting = function () { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var url; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
url = new URL("/sources/", this.apiBaseUrl); | ||
return [4 /*yield*/, fetch(url.toString(), { | ||
method: "POST", | ||
headers: { | ||
Accept: "application/json, text/plain, */*", | ||
"Content-Type": "application/json", | ||
}, | ||
})]; | ||
case 1: | ||
_a.sent(); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
}; | ||
return LogflareHttpClient; | ||
@@ -153,0 +174,0 @@ }()); |
{ | ||
"name": "logflare-transport-core", | ||
"version": "0.2.4", | ||
"version": "0.2.5-1a27192b", | ||
"description": "A common core for Logflare javascript transports.", | ||
@@ -12,8 +12,5 @@ "keywords": [ | ||
"dependencies": { | ||
"@types/lodash": "^4.14.153", | ||
"axios": "^0.19.2", | ||
"big-integer": "^1.6.48", | ||
"bignumber.js": "^9.0.0", | ||
"decimal.js": "^10.2.0", | ||
"lodash": "^4.17.15" | ||
"decimal.js": "^10.2.0" | ||
}, | ||
@@ -28,4 +25,4 @@ "devDependencies": { | ||
"jest": "^26.0.1", | ||
"moxios": "^0.4.0", | ||
"prettier": "^2.0.5" | ||
"prettier": "^2.0.5", | ||
"typescript": "^4.5.4" | ||
}, | ||
@@ -48,2 +45,2 @@ "scripts": { | ||
} | ||
} | ||
} |
@@ -1,11 +0,3 @@ | ||
import axios, { AxiosInstance, AxiosResponse } from "axios" | ||
import _ from "lodash" | ||
import { | ||
applyNumberToStringTypecasting, | ||
applyCustomTypecasting, | ||
} from "./typecasting" | ||
import stream from "stream" | ||
interface IngestTransformsI { | ||
jsNumbers: boolean | ||
numbersToFloats: boolean | ||
} | ||
@@ -26,4 +18,15 @@ | ||
class NetworkError extends Error { | ||
name = "NetworkError" | ||
constructor( | ||
message: string, | ||
public response: Response, | ||
public data: unknown | ||
) { | ||
super(message) | ||
} | ||
} | ||
class LogflareHttpClient { | ||
protected axiosInstance: AxiosInstance | ||
protected readonly sourceToken: string | ||
@@ -34,5 +37,6 @@ protected readonly transforms?: IngestTransformsI | ||
protected readonly fromBrowser: boolean | ||
protected readonly apiBaseUrl: string | ||
public constructor(options: LogflareUserOptionsI) { | ||
const { sourceToken, apiKey, transforms, endpoint } = options | ||
const {sourceToken, apiKey, transforms, endpoint} = options | ||
if (!sourceToken || sourceToken == "") { | ||
@@ -49,10 +53,3 @@ throw "Logflare API logging transport source token is NOT configured!" | ||
this.apiKey = apiKey | ||
this.axiosInstance = axios.create({ | ||
baseURL: options.apiBaseUrl || defaultOptions.apiBaseUrl, | ||
headers: { | ||
"Content-Type": "application/json" | ||
}, | ||
}) | ||
this._initializeResponseInterceptor() | ||
this.apiBaseUrl = options.apiBaseUrl || defaultOptions.apiBaseUrl | ||
} | ||
@@ -62,49 +59,51 @@ | ||
let logEvents = Array.isArray(logEvent) ? logEvent : [logEvent] | ||
if (this?.transforms?.jsNumbers) { | ||
logEvents = _.map(logEvents, applyNumberToStringTypecasting) | ||
} | ||
return this.postLogEvents(logEvents) | ||
} | ||
public insertStream() { | ||
const self = this | ||
const writeStream = new stream.Writable({ | ||
objectMode: true, | ||
highWaterMark: 1, | ||
}) | ||
writeStream._write = function (chunk, encoding, callback) { | ||
self.addLogEvent(chunk) | ||
.then(() => { | ||
callback(null) | ||
}) | ||
.catch(callback) | ||
} | ||
return writeStream | ||
} | ||
async postLogEvents(batch: object[]) { | ||
let url | ||
let path | ||
if (this.endpoint === "typecasting") { | ||
url = `/logs/typecasts?api_key=${this.apiKey}&source=${this.sourceToken}` | ||
path = `/logs/typecasts?api_key=${this.apiKey}&source=${this.sourceToken}` | ||
} else { | ||
url = `/logs?api_key=${this.apiKey}&source=${this.sourceToken}` | ||
path = `/logs?api_key=${this.apiKey}&source=${this.sourceToken}` | ||
} | ||
const payload = { | ||
batch | ||
batch, | ||
} | ||
try { | ||
return await this.axiosInstance.post(url, payload) | ||
} catch (e) { | ||
if (e.response) { | ||
console.error( | ||
`Logflare API request failed with ${ | ||
e.response.status | ||
} status: ${JSON.stringify(e.response.data)}` | ||
const url = new URL(path, this.apiBaseUrl) | ||
const response = await fetch(url.toString(), { | ||
body: JSON.stringify(payload), | ||
method: "POST", | ||
headers: { | ||
Accept: "application/json, text/plain, */*", | ||
"Content-Type": "application/json", | ||
}, | ||
}) | ||
const data = await response.json() | ||
if (!response.ok) { | ||
throw new NetworkError( | ||
`Network response was not ok for "${url}"`, | ||
response, | ||
data | ||
) | ||
} else if (e.request) { | ||
console.error(`Logflare API request failed: ${e.request}`) | ||
} else { | ||
console.error(e.message) | ||
} | ||
return data | ||
} catch (e) { | ||
if (e) { | ||
if (e instanceof NetworkError && e.response) { | ||
console.error( | ||
`Logflare API request failed with ${ | ||
e.response.status | ||
} status: ${JSON.stringify(e.data)}` | ||
) | ||
} else if (e instanceof Error) { | ||
console.error(e.message) | ||
} | ||
} | ||
return e | ||
@@ -114,13 +113,15 @@ } | ||
private _initializeResponseInterceptor = () => { | ||
this.axiosInstance.interceptors.response.use( | ||
this._handleResponse, | ||
this._handleError | ||
) | ||
async addTypecasting() { | ||
const url = new URL("/sources/", this.apiBaseUrl) | ||
await fetch(url.toString(), { | ||
method: "POST", | ||
headers: { | ||
Accept: "application/json, text/plain, */*", | ||
"Content-Type": "application/json", | ||
}, | ||
}) | ||
} | ||
private _handleResponse = ({ data }: AxiosResponse) => data | ||
protected _handleError = (error: any) => Promise.reject(error) | ||
} | ||
export { LogflareHttpClient, LogflareUserOptionsI } | ||
export {LogflareHttpClient, LogflareUserOptionsI} |
@@ -1,5 +0,4 @@ | ||
import moxios from "moxios" | ||
import {LogflareHttpClient} from "./main" | ||
const testApiKey = "testApiKey" | ||
const testBaseUrl = "http://non-existing.domain" | ||
@@ -11,43 +10,48 @@ const testSourceToken = "2222-2222" | ||
let httpClient | ||
let axiosInstance | ||
let nativeFetch | ||
beforeAll(() => { | ||
nativeFetch = global.fetch | ||
}) | ||
beforeEach(() => { | ||
httpClient = new LogflareHttpClient({ | ||
apiKey: "testApiKey", | ||
sourceToken: "2222-2222", | ||
apiKey: testApiKey, | ||
sourceToken: testSourceToken, | ||
apiBaseUrl: "http://non-existing.domain", | ||
}) | ||
const axiosInstance = httpClient.axiosInstance | ||
moxios.install(axiosInstance) | ||
}) | ||
afterEach(() => { | ||
moxios.uninstall(axiosInstance) | ||
global.fetch.mockClear() | ||
}) | ||
it("successfully send a post request", async (done) => { | ||
const le = {message: "info log msg", metadata: {p1: "v1"}} | ||
afterAll(() => { | ||
global.fetch = nativeFetch | ||
}) | ||
moxios.wait(async () => { | ||
let request = moxios.requests.mostRecent() | ||
expect(request.config.baseURL).toBe(testBaseUrl) | ||
expect(request.headers).toMatchObject({ | ||
Accept: "application/json, text/plain, */*", | ||
"Content-Type": "application/json", | ||
"X-API-KEY": "testApiKey", | ||
}) | ||
expect(request.config.data).toBe( | ||
JSON.stringify({batch: [le], source: testSourceToken}) | ||
) | ||
await request.respondWith({ | ||
it("successfully send a post request", async () => { | ||
global.fetch = jest.fn(() => | ||
Promise.resolve({ | ||
json: () => Promise.resolve(apiResponseSuccess), | ||
ok: true, | ||
status: 200, | ||
response: apiResponseSuccess, | ||
}) | ||
done() | ||
}) | ||
) | ||
const le = {message: "info log msg", metadata: {p1: "v1"}} | ||
const response = await httpClient.addLogEvent(le) | ||
expect(response).toMatchObject(apiResponseSuccess) | ||
expect(global.fetch).toHaveBeenCalledWith( | ||
`${testBaseUrl}/logs?api_key=${testApiKey}&source=${testSourceToken}`, | ||
{ | ||
body: JSON.stringify({batch: [le]}), | ||
method: "POST", | ||
headers: { | ||
Accept: "application/json, text/plain, */*", | ||
"Content-Type": "application/json", | ||
}, | ||
} | ||
) | ||
}) | ||
@@ -57,72 +61,23 @@ | ||
const storeLog = (inputs) => (consoleLogData += inputs) | ||
it("prints to console on error", async (done) => { | ||
it("prints to console on error", async () => { | ||
const errorResponse = {message: "Schema validation error"} | ||
console["error"] = jest.fn(storeLog) | ||
global.fetch = jest.fn(() => | ||
Promise.resolve({ | ||
json: () => Promise.resolve(errorResponse), | ||
ok: false, | ||
status: 406, | ||
}) | ||
) | ||
const le = {message: "info log msg", metadata: {p1: "v1"}} | ||
moxios.wait(async () => { | ||
let request = moxios.requests.mostRecent() | ||
await request.respondWith({ | ||
status: 406, | ||
response: {message: "Schema validation error"}, | ||
}) | ||
done() | ||
}) | ||
await httpClient.addLogEvent(le) | ||
expect(consoleLogData).toBe( | ||
'Logflare API request failed with 406 status: {"message":"Schema validation error"}' | ||
`Logflare API request failed with 406 status: ${JSON.stringify( | ||
errorResponse | ||
)}` | ||
) | ||
}) | ||
}) | ||
describe("LogflareHttpClient with options", () => { | ||
let httpClient | ||
let axiosInstance | ||
beforeEach(() => { | ||
httpClient = new LogflareHttpClient({ | ||
apiKey: "testApiKey", | ||
sourceToken: "2222-2222", | ||
apiBaseUrl: "http://non-existing.domain", | ||
transforms: {jsNumbers: true}, | ||
}) | ||
const axiosInstance = httpClient.axiosInstance | ||
moxios.install(axiosInstance) | ||
}) | ||
afterEach(() => { | ||
moxios.uninstall(axiosInstance) | ||
}) | ||
it("trarnsforms js numbers if configured", async (done) => { | ||
const le = { | ||
message: "info log msg", | ||
metadata: {number: 1, number2: 1.0}, | ||
} | ||
moxios.wait(async () => { | ||
let request = moxios.requests.mostRecent() | ||
expect(request.config.baseURL).toBe(testBaseUrl) | ||
expect(request.headers).toMatchObject({ | ||
Accept: "application/json, text/plain, */*", | ||
"Content-Type": "application/json", | ||
"X-API-KEY": "testApiKey", | ||
}) | ||
expect(request.config.data).toBe( | ||
'{"batch":[{"body":{"message":"info log msg","metadata":{"number":"1","number2":"1"}},"typecasts":[{"path":["metadata","number"],"from":"string","to":"float"},{"path":["metadata","number2"],"from":"string","to":"float"}]}],"source":"2222-2222"}' | ||
) | ||
await request.respondWith({ | ||
status: 200, | ||
response: apiResponseSuccess, | ||
}) | ||
done() | ||
}) | ||
const response = await httpClient.addLogEvent(le) | ||
expect(response).toMatchObject(apiResponseSuccess) | ||
}) | ||
}) |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
3
26477
14
466
3
- Removed@types/lodash@^4.14.153
- Removedaxios@^0.19.2
- Removedlodash@^4.17.15
- Removed@types/lodash@4.17.13(transitive)
- Removedaxios@0.19.2(transitive)
- Removedfollow-redirects@1.5.10(transitive)
- Removedlodash@4.17.21(transitive)