New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@appsignal/nodejs

Package Overview
Dependencies
Maintainers
8
Versions
136
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@appsignal/nodejs - npm Package Compare versions

Comparing version

to
2.2.5

17

dist/cli/diagnose.d.ts

@@ -10,4 +10,21 @@ import { HashMap } from "@appsignal/types";

agentDiagnosticTestDefinition(): HashMap<any>;
printConfiguration({ options, sources }: {
options: {
[key: string]: any;
};
sources: {
[source: string]: {
[key: string]: any;
};
};
}): void;
configurationKeySources(key: string, sources: {
[source: string]: {
[key: string]: any;
};
}): {
[source: string]: any;
};
print_newline(): void;
colorize(value: string): string;
}

54

dist/cli/diagnose.js

@@ -67,2 +67,4 @@ "use strict";

console.log(` Library type: ${format_value(data["installation"]["build"]["library_type"])}`);
console.log(` Dependencies: ${format_value(data["installation"]["build"]["dependencies"])}`);
console.log(` Flags: ${format_value(data["installation"]["build"]["flags"])}`);
console.log(` Host details`);

@@ -82,8 +84,3 @@ console.log(` Root user: ${format_value(data["installation"]["host"]["root_user"])}`);

this.print_newline();
console.log(`Configuration`);
Object.keys(data["config"]["options"])
.sort()
.forEach(key => {
console.log(` ${key}: ${format_value(data["config"]["options"][key])}`);
});
this.printConfiguration(data["config"]);
this.print_newline();

@@ -246,2 +243,40 @@ console.log(`Read more about how the diagnose config output is rendered`);

}
printConfiguration({ options, sources }) {
console.log(`Configuration`);
Object.keys(options)
.sort()
.forEach(key => {
let keySources = this.configurationKeySources(key, sources);
if (Object.keys(keySources).length == 1) {
const source = Object.keys(keySources)[0];
let extra = "";
if (source !== "default") {
extra = ` (Loaded from: ${source})`;
}
console.log(` ${key}: ${format_value(options[key])}${extra}`);
}
else {
console.log(` ${key}: ${format_value(options[key])}`);
console.log(` Sources:`);
const maxSourceLength = Object.keys(keySources)
// Adding one to account for the `:` after the source name.
.map(source => source.length + 1)
.reduce((max, source) => Math.max(max, source), 0);
Object.entries(keySources).forEach(([source, value]) => {
source = `${source}:`.padEnd(maxSourceLength, " ");
console.log(` ${source} ${format_value(value)}`);
});
}
});
}
configurationKeySources(key, sources) {
return Object.entries(sources).reduce((keySources, [source, sourceOptions]) => {
if (sourceOptions.hasOwnProperty(key)) {
return { ...keySources, [source]: sourceOptions[key] };
}
else {
return keySources;
}
}, {});
}
print_newline() {

@@ -264,3 +299,8 @@ console.log(``);

function format_value(value) {
return util.inspect(value);
if (typeof value == "object") {
return JSON.stringify(value);
}
else {
return util.inspect(value);
}
}

@@ -15,3 +15,3 @@ import { Client, Metrics, Plugin, Tracer, AppsignalOptions } from "./interfaces";

#private;
readonly VERSION = "2.2.4";
readonly VERSION = "2.2.5";
config: Configuration;

@@ -77,2 +77,6 @@ extension: Extension;

demo(): void;
/**
* Stores the client in global object after initializing
*/
private storeInGlobal;
}

@@ -42,2 +42,3 @@ "use strict";

bootstrap_1.initCoreProbes(this.metrics(), { enableMinutelyProbes });
this.storeInGlobal();
}

@@ -64,3 +65,3 @@ /**

else {
console.error("Not starting, no valid config for this environment");
console.error("Not starting, no valid AppSignal configuration found");
}

@@ -129,4 +130,10 @@ }

}
/**
* Stores the client in global object after initializing
*/
storeInGlobal() {
global.__APPSIGNAL__ = this;
}
}
exports.BaseClient = BaseClient;
_tracer = new WeakMap(), _metrics = new WeakMap();
import { AppsignalOptions } from "./interfaces/options";
import { HashMap } from "@appsignal/types";
/**

@@ -12,2 +13,3 @@ * The AppSignal configuration object.

data: Partial<AppsignalOptions>;
sources: HashMap<Partial<AppsignalOptions>>;
constructor(options: Partial<AppsignalOptions>);

@@ -20,7 +22,13 @@ /**

* Returns `true` if the current configuration is valid.
*
* @todo
*/
get isValid(): boolean;
get logFilePath(): string | undefined;
/**
* Returns default OS tmp dir. Uses OS package for Windows. Linux and macOS
* have `/tmp` hardcoded as a default
*
* @private
*/
private _tmpdir;
/**
* Explicit default configuration values

@@ -32,2 +40,8 @@ *

/**
* Config options based on the host environment.
*
* @private
*/
private _systemValues;
/**
* Loads environment variables into a key-value structure.

@@ -43,3 +57,11 @@ *

*/
private _write;
private writePrivateConfig;
/**
* Writes private environment variables that are not user configured,
* and static in the lifecycle of the agent.
*
* @function
* @private
*/
private writePrivateConstants;
}

139

dist/config.js

@@ -6,3 +6,5 @@ "use strict";

const path_1 = tslib_1.__importDefault(require("path"));
const os_1 = tslib_1.__importDefault(require("os"));
const version_1 = require("./version");
const utils_1 = require("./utils");
const configmap_1 = require("./config/configmap");

@@ -19,9 +21,17 @@ /**

constructor(options) {
writePrivateConstants();
this.data = {
...this._defaultValues(),
...this._loadFromEnvironment(),
...options
if (options.apiKey) {
console.warn("DEPRECATED: The `apiKey` config option was renamed to `pushApiKey`. Please rename the config option given to the Appsignal module.");
options.pushApiKey = options.apiKey;
delete options.apiKey;
}
this.sources = {
default: this._defaultValues(),
system: this._systemValues(),
env: this._loadFromEnvironment(),
initial: options
};
this._write(this.data);
this.data = Object.values(this.sources).reduce((data, options) => {
return { ...data, ...options };
}, {});
this.writePrivateConfig(this.data);
}

@@ -36,9 +46,49 @@ /**

* Returns `true` if the current configuration is valid.
*
* @todo
*/
get isValid() {
return true;
return (this.data.pushApiKey || "").trim() !== "";
}
get logFilePath() {
const filename = "appsignal.log";
let logPath = this.data["logPath"];
if (logPath && path_1.default.extname(logPath) != "") {
console.warn("DEPRECATED: File names are no longer supported in the 'logPath' config option. Changing the filename to 'appsignal.log'");
logPath = path_1.default.dirname(logPath);
}
if (logPath && utils_1.isWritable(logPath)) {
return path_1.default.join(logPath, filename);
}
else {
const tmpDir = this._tmpdir();
if (utils_1.isWritable(tmpDir)) {
if (logPath) {
console.warn(`Unable to log to '${logPath}'. Logging to '${tmpDir}' instead. Please check the permissions of the 'logPath' directory.`);
}
return path_1.default.join(tmpDir, filename);
}
else {
let configuredPath = "";
if (logPath) {
configuredPath = `'${logPath}' or `;
}
console.warn(`Unable to log to ${configuredPath}'${tmpDir}' fallback. Please check the permissions of these directories.`);
}
}
}
/**
* Returns default OS tmp dir. Uses OS package for Windows. Linux and macOS
* have `/tmp` hardcoded as a default
*
* @private
*/
_tmpdir() {
const isWindows = process.platform == "win32";
if (isWindows) {
return os_1.default.tmpdir();
}
else {
return "/tmp";
}
}
/**
* Explicit default configuration values

@@ -59,3 +109,2 @@ *

filesWorldAccessible: true,
filterDataKeys: [],
filterParameters: [],

@@ -67,3 +116,12 @@ filterSessionData: [],

log: "file",
logPath: "/tmp",
requestHeaders: [
"accept",
"accept-charset",
"accept-encoding",
"accept-language",
"cache-control",
"connection",
"content-length",
"range"
],
transactionDebugMode: false

@@ -73,2 +131,14 @@ };

/**
* Config options based on the host environment.
*
* @private
*/
_systemValues() {
const config = {};
if (process.env.DYNO) {
config["log"] = "stdout";
}
return config;
}
/**
* Loads environment variables into a key-value structure.

@@ -99,10 +169,8 @@ *

*/
_write(config) {
// First write log file path based on log path
if (config["logPath"].endsWith("appsignal.log")) {
config["logFilePath"] = config["logPath"];
writePrivateConfig(config) {
this.writePrivateConstants();
const logFilePath = this.logFilePath;
if (logFilePath) {
process.env["_APPSIGNAL_LOG_FILE_PATH"] = logFilePath;
}
else {
config["logFilePath"] = path_1.default.join(config["logPath"], "appsignal.log");
}
// write to a "private" environment variable if it exists in the

@@ -120,22 +188,21 @@ // config structure

});
return;
}
/**
* Writes private environment variables that are not user configured,
* and static in the lifecycle of the agent.
*
* @function
* @private
*/
writePrivateConstants() {
const priv = {
// @TODO: is this path always correct?
_APPSIGNAL_AGENT_PATH: path_1.default.join(__dirname, "/../../nodejs-ext/ext"),
_APPSIGNAL_PROCESS_NAME: process.title,
_APPSIGNAL_LANGUAGE_INTEGRATION_VERSION: `nodejs-${version_1.VERSION}`,
_APPSIGNAL_APP_PATH: process.cwd()
};
Object.entries(priv).forEach(([k, v]) => (process.env[k] = v));
}
}
exports.Configuration = Configuration;
/**
* Writes private environment variables that are not user configured,
* and static in the lifecycle of the agent.
*
* @function
* @private
*/
function writePrivateConstants() {
const priv = {
// @TODO: is this path always correct?
_APPSIGNAL_AGENT_PATH: path_1.default.join(__dirname, "/../../nodejs-ext/ext"),
_APPSIGNAL_PROCESS_NAME: process.title,
_APPSIGNAL_LANGUAGE_INTEGRATION_VERSION: `nodejs-${version_1.VERSION}`,
_APPSIGNAL_APP_PATH: process.cwd()
};
Object.entries(priv).forEach(([k, v]) => (process.env[k] = v));
}

@@ -26,3 +26,3 @@ "use strict";

APPSIGNAL_PUSH_API_ENDPOINT: "endpoint",
APPSIGNAL_PUSH_API_KEY: "apiKey",
APPSIGNAL_PUSH_API_KEY: "pushApiKey",
APPSIGNAL_REQUEST_HEADERS: "requestHeaders",

@@ -47,3 +47,4 @@ APPSIGNAL_RUNNING_IN_CONTAINER: "runningInContainer",

_APPSIGNAL_FILES_WORLD_ACCESSIBLE: "filesWorldAccessible",
_APPSIGNAL_FILTER_DATA_KEYS: "filterDataKeys",
_APPSIGNAL_FILTER_PARAMETERS: "filterParameters",
_APPSIGNAL_FILTER_SESSION_DATA: "filterSessionData",
_APPSIGNAL_HOSTNAME: "hostname",

@@ -55,5 +56,4 @@ _APPSIGNAL_HTTP_PROXY: "httpProxy",

_APPSIGNAL_LOG: "log",
_APPSIGNAL_LOG_FILE_PATH: "logFilePath",
_APPSIGNAL_PUSH_API_ENDPOINT: "endpoint",
_APPSIGNAL_PUSH_API_KEY: "apiKey",
_APPSIGNAL_PUSH_API_KEY: "pushApiKey",
_APPSIGNAL_RUNNING_IN_CONTAINER: "runningInContainer",

@@ -67,3 +67,3 @@ _APPSIGNAL_TRANSACTION_DEBUG_MODE: "debug",

active: "active",
apiKey: "push_api_key",
pushApiKey: "push_api_key",
caFilePath: "ca_file_path",

@@ -78,3 +78,2 @@ debug: "debug",

filesWorldAccessible: "files_world_accessible",
filterDataKeys: "filter_data_keys",
filterParameters: "filter_parameters",

@@ -88,4 +87,4 @@ filterSessionData: "filter_session_data",

logPath: "log_path",
logFilePath: "log_file_path",
name: "name",
requestHeaders: "request_headers",
revision: "revision",

@@ -92,0 +91,0 @@ runningInContainer: "running_in_container",

/// <reference types="node" />
import { AppsignalOptions } from ".";
import { HashMap } from "@appsignal/types";
interface FileMetadata {

@@ -41,6 +43,4 @@ content?: string[];

config: {
options: {
[key: string]: any;
};
sources: {};
options: Partial<AppsignalOptions>;
sources: HashMap<Partial<AppsignalOptions>>;
};

@@ -64,7 +64,18 @@ validation: {

* Reads all configuration and re-maps it to keys with
* snake_case names as they appear in our API.
* snake_case names.
*/
private getConfigData;
sendReport(data: object): void;
/**
* Converts an AppsignalOptions object into a plain JS object,
* re-mapping its keys to snake_case names as they appear
* in our API.
*/
private optionsObject;
/**
* Reads all configuration sources, remapping each source's
* option keys with snake_case names.
*/
private getSources;
sendReport(data: HashMap<any>): void;
}
export {};

@@ -12,2 +12,3 @@ "use strict";

const crypto_1 = require("crypto");
const utils_1 = require("./utils");
const extension_1 = require("./extension");

@@ -39,4 +40,4 @@ const config_1 = require("./config");

config: {
options: this.getConfigData(),
sources: {}
options: tslib_1.__classPrivateFieldGet(this, _config).data,
sources: tslib_1.__classPrivateFieldGet(this, _config).sources
},

@@ -94,6 +95,12 @@ validation: { push_api_key: pushApiKeyValidation },

const config = tslib_1.__classPrivateFieldGet(this, _config).data;
const params = new url_1.URLSearchParams({ api_key: config["apiKey"] });
const params = new url_1.URLSearchParams({
api_key: config["pushApiKey"] || "",
name: config["name"] || "",
environment: config["environment"] || "",
hostname: config["hostname"] || ""
});
const url = new url_1.URL(`/1/auth?${params.toString()}`, config["endpoint"]);
const options = { method: "POST" };
const request = https_1.default.request(url, options, function (response) {
const requestModule = url.protocol == "http:" ? http_1.default : https_1.default;
const request = requestModule.request(url, options, function (response) {
const status = response.statusCode;

@@ -107,6 +114,6 @@ if (status === 200) {

else {
reject(`Failed with status ${status}`);
reject(`Failed to validate: status ${status}`);
}
});
request.write("{}"); // Send empty JSON body
request.write(""); // Send empty body
request.end();

@@ -117,7 +124,4 @@ });

const paths = {};
// we want to fall over if this value isn't present
// (it should be)
const logFilePath = tslib_1.__classPrivateFieldGet(this, _config).data.logFilePath;
// add any paths we want to check to this object!
const files = {
const logFilePath = tslib_1.__classPrivateFieldGet(this, _config).logFilePath;
const pathsToCheck = {
working_dir: {

@@ -127,27 +131,37 @@ path: process.cwd()

log_dir_path: {
path: tslib_1.__classPrivateFieldGet(this, _config).data.logPath.replace("/appsignal.log", "")
path: logFilePath ? path_1.default.dirname(logFilePath) : ""
},
"appsignal.log": {
path: logFilePath,
content: safeReadFromPath(logFilePath).trimEnd().split("\n")
path: logFilePath || "",
content: logFilePath
? safeReadFromPath(logFilePath).trimEnd().split("\n")
: []
}
};
Object.entries(files).forEach(([key, data]) => {
Object.entries(pathsToCheck).forEach(([key, data]) => {
const { path } = data;
try {
const stats = fs_1.default.statSync(path);
const { mode, gid, uid } = stats;
paths[key] = {
...data,
exists: true,
mode: mode.toString(8),
ownership: {
gid,
uid
},
type: getPathType(stats),
writable: isWriteableFile(path)
};
if (fs_1.default.existsSync(path)) {
try {
let stats = fs_1.default.statSync(path);
const { mode, gid, uid } = stats;
paths[key] = {
...data,
exists: true,
mode: mode.toString(8),
ownership: {
gid,
uid
},
type: getPathType(stats),
writable: utils_1.isWritable(path)
};
}
catch (_) {
paths[key] = {
...data,
exists: true
};
}
}
catch (_) {
else {
paths[key] = {

@@ -163,16 +177,40 @@ ...data,

* Reads all configuration and re-maps it to keys with
* snake_case names as they appear in our API.
* snake_case names.
*/
getConfigData() {
return this.optionsObject(tslib_1.__classPrivateFieldGet(this, _config).data);
}
/**
* Converts an AppsignalOptions object into a plain JS object,
* re-mapping its keys to snake_case names as they appear
* in our API.
*/
optionsObject(options) {
const config = {};
Object.keys(tslib_1.__classPrivateFieldGet(this, _config).data).forEach(key => {
Object.keys(options).forEach(key => {
const newKey = configmap_1.JS_TO_RUBY_MAPPING[key];
config[newKey] = tslib_1.__classPrivateFieldGet(this, _config).data[key];
config[newKey] = options[key];
});
return config;
}
/**
* Reads all configuration sources, remapping each source's
* option keys with snake_case names.
*/
getSources() {
return Object.entries(tslib_1.__classPrivateFieldGet(this, _config).sources).reduce((sources, [name, options]) => {
return { ...sources, [name]: this.optionsObject(options) };
}, {});
}
sendReport(data) {
data.config.options = this.getConfigData();
data.config.sources = this.getSources();
const json = JSON.stringify({ diagnose: data });
const config = tslib_1.__classPrivateFieldGet(this, _config).data;
const params = new url_1.URLSearchParams({ api_key: config["apiKey"] || "" });
const params = new url_1.URLSearchParams({
api_key: config["pushApiKey"] || "",
name: config["name"] || "",
environment: config["environment"] || "",
hostname: config["hostname"] || ""
});
const diagnoseEndpoint = process.env.APPSIGNAL_DIAGNOSE_ENDPOINT || "https://appsignal.com/diag";

@@ -226,11 +264,2 @@ const url = new url_1.URL(diagnoseEndpoint);

}
function isWriteableFile(path) {
try {
fs_1.default.accessSync(path, fs_1.default.constants.R_OK);
return true;
}
catch (e) {
return false;
}
}
function getPathType(stats) {

@@ -237,0 +266,0 @@ if (stats.isDirectory()) {

@@ -29,4 +29,5 @@ "use strict";

const [req, res] = args;
const { method = "GET", url = "/" } = req;
const { method = "GET", url = "/", headers } = req;
const { pathname, query } = url_1.parse(url);
const allowedHeaders = filterHeaders(headers);
// don't start a span for ignored urls

@@ -54,2 +55,3 @@ if (url && DEFAULT_IGNORED_URLS.some(el => el.test(url))) {

.set("method", method)
.setSampleData("environment", allowedHeaders)
.setSampleData("params", query ? { query } : {});

@@ -73,2 +75,12 @@ return tracer.withSpan(rootSpan, span => {

}
function filterHeaders(headers) {
let filtered = {};
const headersAllowList = global.__APPSIGNAL__.config.data.requestHeaders || [];
headersAllowList.forEach(key => {
if (headers[key] != undefined) {
filtered[key] = headers[key];
}
});
return filtered;
}
function getPatchIncomingRequestFunction(tracer) {

@@ -75,0 +87,0 @@ return function (original) {

@@ -24,2 +24,3 @@ export interface AppsignalOptions {

name: string;
pushApiKey: string;
requestHeaders: string[];

@@ -26,0 +27,0 @@ revision: string;

import { HashMap } from "@appsignal/types";
import { datamap, dataarray } from "../extension_wrapper";
export declare class Data {
static generate(data: Array<any> | HashMap<any>, filtered?: boolean): any;
static generate(data: Array<any> | HashMap<any>): any;
static toJson(data: typeof datamap | typeof dataarray): any;

@@ -6,0 +6,0 @@ private static mapObject;

@@ -6,8 +6,8 @@ "use strict";

class Data {
static generate(data, filtered = false) {
static generate(data) {
if (data.constructor.name === "Object") {
return this.mapObject(data, filtered);
return this.mapObject(data);
}
else if (Array.isArray(data)) {
return this.mapArray(data, filtered);
return this.mapArray(data);
}

@@ -21,4 +21,4 @@ else {

}
static mapObject(hash_value, filtered) {
let map = filtered ? extension_wrapper_1.datamap.createFiltered() : extension_wrapper_1.datamap.create();
static mapObject(hash_value) {
let map = extension_wrapper_1.datamap.create();
Object.entries(hash_value).forEach(([key, value]) => {

@@ -51,6 +51,6 @@ switch (typeof value) {

else if (Array.isArray(value)) {
extension_wrapper_1.datamap.setData(key, this.mapArray(value, filtered), map);
extension_wrapper_1.datamap.setData(key, this.mapArray(value), map);
}
else if ((value === null || value === void 0 ? void 0 : value.constructor.name) === "Object") {
extension_wrapper_1.datamap.setData(key, this.mapObject(value, filtered), map);
extension_wrapper_1.datamap.setData(key, this.mapObject(value), map);
}

@@ -66,3 +66,3 @@ else {

}
static mapArray(array_value, filtered) {
static mapArray(array_value) {
let array = extension_wrapper_1.dataarray.create();

@@ -97,6 +97,6 @@ array_value.forEach(value => {

else if (Array.isArray(value)) {
extension_wrapper_1.dataarray.appendData(this.mapArray(value, filtered), array);
extension_wrapper_1.dataarray.appendData(this.mapArray(value), array);
}
else if ((value === null || value === void 0 ? void 0 : value.constructor.name) === "Object") {
extension_wrapper_1.dataarray.appendData(this.mapObject(value, filtered), array);
extension_wrapper_1.dataarray.appendData(this.mapObject(value), array);
}

@@ -103,0 +103,0 @@ else {

@@ -106,3 +106,3 @@ "use strict";

try {
extension_wrapper_1.span.setSpanSampleData(this._ref, key, data_1.Data.generate(data, true));
extension_wrapper_1.span.setSpanSampleData(this._ref, key, data_1.Data.generate(data));
}

@@ -109,0 +109,0 @@ catch (e) {

@@ -19,1 +19,5 @@ /**

};
/**
* Checks if the given path is writable by the process.
*/
export declare function isWritable(path: string): boolean;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getAgentTimestamps = exports.getPackageVerson = void 0;
exports.isWritable = exports.getAgentTimestamps = exports.getPackageVerson = void 0;
const tslib_1 = require("tslib");
const fs_1 = tslib_1.__importDefault(require("fs"));
const path_1 = tslib_1.__importDefault(require("path"));

@@ -37,1 +38,14 @@ /**

exports.getAgentTimestamps = getAgentTimestamps;
/**
* Checks if the given path is writable by the process.
*/
function isWritable(path) {
try {
fs_1.default.accessSync(path, fs_1.default.constants.W_OK);
return true;
}
catch (e) {
return false;
}
}
exports.isWritable = isWritable;

@@ -1,2 +0,2 @@

export declare const VERSION = "2.2.4";
export declare const AGENT_VERSION = "09308fb";
export declare const VERSION = "2.2.5";
export declare const AGENT_VERSION = "5b63505";

@@ -5,3 +5,3 @@ "use strict";

// Do not touch this file, auto-generated by scripts/create-versionfile
exports.VERSION = "2.2.4";
exports.AGENT_VERSION = "09308fb";
exports.VERSION = "2.2.5";
exports.AGENT_VERSION = "5b63505";
{
"name": "@appsignal/nodejs",
"version": "2.2.4",
"version": "2.2.5",
"main": "dist/index",

@@ -19,3 +19,3 @@ "types": "dist/index",

"optionalDependencies": {
"@appsignal/nodejs-ext": "=2.0.3"
"@appsignal/nodejs-ext": "=2.0.4"
},

@@ -22,0 +22,0 @@ "devDependencies": {

@@ -36,3 +36,3 @@ # `@appsignal/nodejs`

name: "<YOUR APPLICATION NAME>"
apiKey: "<YOUR API KEY>"
pushApiKey: "<YOUR API KEY>"
});

@@ -39,0 +39,0 @@