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

@atlassian/clientside-extensions-debug

Package Overview
Dependencies
Maintainers
0
Versions
233
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@atlassian/clientside-extensions-debug - npm Package Compare versions

Comparing version 3.1.2-test9-85e70efb to 4.0.0-jakarta-m001

./dist/cjs/index.js

120

dist/cjs/debug-state.js
"use strict";
/* eslint-disable no-underscore-dangle */
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.setDiscoveryEnabled = exports.setValidationEnabled = exports.setLoggingEnabled = exports.setDebugEnabled = exports.isDiscoveryEnabled = exports.isValidationEnabled = exports.isLoggingEnabled = exports.isDebugEnabled = exports.observeStateChange = void 0;
var clientside_extensions_base_1 = require("@atlassian/clientside-extensions-base");
var debug_subjects_1 = require("./debug-subjects");
var ClientPluginDebugTypes;
(function (ClientPluginDebugTypes) {
ClientPluginDebugTypes["debug"] = "debug";
ClientPluginDebugTypes["logging"] = "logging";
ClientPluginDebugTypes["validation"] = "validation";
ClientPluginDebugTypes["discovery"] = "discovery";
})(ClientPluginDebugTypes || (ClientPluginDebugTypes = {}));
var defineDebugGlobal = function (previousGlobal) {
exports.setLogLevel = exports.setDiscoveryEnabled = exports.setValidationEnabled = exports.setLoggingEnabled = exports.setDebugEnabled = exports.getLogLevel = exports.isDiscoveryEnabled = exports.isValidationEnabled = exports.isLoggingEnabled = exports.isDebugEnabled = exports.observeStateChange = void 0;
const clientside_extensions_base_1 = require("@atlassian/clientside-extensions-base");
const debug_subjects_1 = require("./debug-subjects");
const logger_1 = require("./logger/logger");
var ClientExtensionDebugTypes;
(function (ClientExtensionDebugTypes) {
ClientExtensionDebugTypes["debug"] = "debug";
ClientExtensionDebugTypes["logging"] = "logging";
ClientExtensionDebugTypes["validation"] = "validation";
ClientExtensionDebugTypes["discovery"] = "discovery";
/** @since 2.1.0 */
ClientExtensionDebugTypes["logLevel"] = "logLevel";
})(ClientExtensionDebugTypes || (ClientExtensionDebugTypes = {}));
const defineDebugGlobal = (previousGlobal) => {
// initialize as boolean
var debugGlobal = Object.create(null);
var debugStates = {
const debugGlobal = Object.create(null);
const debugStates = {
debug: false,

@@ -22,10 +26,13 @@ logging: false,

discovery: false,
/** @since 2.1.0 */
// In dev mode we set default loglevel to INFO
logLevel: process.env.NODE_ENV === 'production' ? logger_1.LogLevel.error : logger_1.LogLevel.info,
};
var debugStateSubject = debug_subjects_1.registerDebugSubject('state', function () { return new clientside_extensions_base_1.ReplaySubject(1); });
var properties = {
const debugStateSubject = (0, debug_subjects_1.registerDebugSubject)("state" /* State */, () => new clientside_extensions_base_1.ReplaySubject(1));
const properties = {
debug: {
get: function () {
get() {
return debugStates.debug;
},
set: function (val) {
set(val) {
debugStates.debug = Boolean(val);

@@ -36,6 +43,6 @@ debugStateSubject.notify(debugStates);

logging: {
get: function () {
get() {
return debugStates.logging;
},
set: function (val) {
set(val) {
debugStates.logging = Boolean(val);

@@ -46,6 +53,6 @@ debugStateSubject.notify(debugStates);

validation: {
get: function () {
get() {
return debugStates.validation;
},
set: function (val) {
set(val) {
debugStates.validation = Boolean(val);

@@ -56,6 +63,6 @@ debugStateSubject.notify(debugStates);

discovery: {
get: function () {
get() {
return debugStates.discovery;
},
set: function (val) {
set(val) {
debugStates.discovery = Boolean(val);

@@ -65,2 +72,17 @@ debugStateSubject.notify(debugStates);

},
/** @since 2.1.0 */
logLevel: {
get() {
return debugStates.logLevel;
},
set(val) {
let level = String(val).toUpperCase();
// Handle runtime errors
if (!Object.values(logger_1.LogLevel).includes(level)) {
level = logger_1.LogLevel.info;
}
debugStates.logLevel = level;
debugStateSubject.notify(debugStates);
},
},
__initialized: { value: true, writable: false },

@@ -71,6 +93,6 @@ };

configurable: true,
get: function () {
get() {
return debugGlobal;
},
set: function (val) {
set(val) {
// its a boolean

@@ -89,3 +111,4 @@ if (val === true || val === false) {

}
['debug', 'logging', 'validation', 'discovery'].forEach(function (key) {
const clientExtensionDebugKeys = Object.keys(ClientExtensionDebugTypes);
clientExtensionDebugKeys.forEach((key) => {
if (key in val) {

@@ -97,32 +120,55 @@ debugGlobal[key] = val[key];

});
// Now, we can use the previous value e.g. boolean, to set the value for all flags
window.____c_p_d = previousGlobal;
};
if (!window.____c_p_d || !window.____c_p_d.__initialized) {
defineDebugGlobal(window.____c_p_d || process.env.NODE_ENV !== 'production');
// Register global value only once
if (!('____c_p_d' in window) || !window.____c_p_d.__initialized) {
defineDebugGlobal((_a = window.____c_p_d) !== null && _a !== void 0 ? _a : process.env.NODE_ENV !== 'production');
}
exports.observeStateChange = function (observer) { return debug_subjects_1.observeDebugSubject('state', observer); };
exports.isDebugEnabled = function () {
const observeStateChange = (observer) => (0, debug_subjects_1.observeDebugSubject)("state" /* State */, observer);
exports.observeStateChange = observeStateChange;
const isDebugEnabled = () => {
return window.____c_p_d.debug;
};
exports.isLoggingEnabled = function () {
exports.isDebugEnabled = isDebugEnabled;
const isLoggingEnabled = () => {
return window.____c_p_d.logging;
};
exports.isValidationEnabled = function () {
exports.isLoggingEnabled = isLoggingEnabled;
const isValidationEnabled = () => {
return window.____c_p_d.validation;
};
exports.isDiscoveryEnabled = function () {
exports.isValidationEnabled = isValidationEnabled;
const isDiscoveryEnabled = () => {
return window.____c_p_d.discovery;
};
exports.setDebugEnabled = function (value) {
exports.isDiscoveryEnabled = isDiscoveryEnabled;
/** @since 2.1.0 */
const getLogLevel = () => {
const logLevel = window.____c_p_d.logLevel;
return logLevel !== null && logLevel !== void 0 ? logLevel : logger_1.LogLevel.info;
};
exports.getLogLevel = getLogLevel;
const setDebugEnabled = (value) => {
window.____c_p_d.debug = value;
};
exports.setLoggingEnabled = function (value) {
exports.setDebugEnabled = setDebugEnabled;
const setLoggingEnabled = (value) => {
window.____c_p_d.logging = value;
};
exports.setValidationEnabled = function (value) {
exports.setLoggingEnabled = setLoggingEnabled;
const setValidationEnabled = (value) => {
window.____c_p_d.validation = value;
};
exports.setDiscoveryEnabled = function (value) {
exports.setValidationEnabled = setValidationEnabled;
const setDiscoveryEnabled = (value) => {
window.____c_p_d.discovery = value;
};
exports.setDiscoveryEnabled = setDiscoveryEnabled;
/** @since 2.1.0 */
const setLogLevel = (value) => {
const level = value.toUpperCase();
window.____c_p_d.logLevel = level;
};
exports.setLogLevel = setLogLevel;
//# sourceMappingURL=debug-state.js.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.observeDebugSubject = exports.registerDebugSubject = void 0;
/* eslint-disable no-underscore-dangle */
var clientside_extensions_base_1 = require("@atlassian/clientside-extensions-base");
var defineSubjectGlobal = function () {
const defineSubjectGlobal = () => {
// initialize as boolean
var subjectGlobal = Object.create(null);
var properties = {
const subjectGlobal = Object.create(null);
const properties = {
__initialized: { value: true, writable: false },

@@ -19,19 +17,29 @@ subjects: {

};
if (!window.____c_p_s || !window.____c_p_s.__initialized) {
if (!('____c_p_s' in window) || !window.____c_p_s.__initialized) {
defineSubjectGlobal();
}
exports.registerDebugSubject = function (key, subjectFactory) {
/**
* Registers a debug subject as singleton
*
* @param key
* @param subjectFactory
*/
const registerDebugSubject = (key, subjectFactory) => {
const debugSubjects = window.____c_p_s.subjects;
// good old singletons - ensure we do not register the same subject twice.
// we also can't fail as multiple instances might try to access the same, so instead we return the previously registered one.
if (!window.____c_p_s.subjects[key]) {
window.____c_p_s.subjects[key] = subjectFactory ? subjectFactory() : new clientside_extensions_base_1.Subject();
if (!(key in debugSubjects)) {
debugSubjects[key] = subjectFactory();
}
return window.____c_p_s.subjects[key];
return debugSubjects[key];
};
exports.observeDebugSubject = function (key, observer) {
if (!window.____c_p_s.subjects[key]) {
throw new Error("No subject registered for key: \"" + key + "\"");
exports.registerDebugSubject = registerDebugSubject;
const observeDebugSubject = (key, observer) => {
const debugSubjects = window.____c_p_s.subjects;
if (!(key in debugSubjects)) {
throw new Error(`No subject registered for key: "${key}"`);
}
return window.____c_p_s.subjects[key].subscribe(observer);
return debugSubjects[key].subscribe(observer);
};
exports.observeDebugSubject = observeDebugSubject;
//# sourceMappingURL=debug-subjects.js.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.onDebug = exports.observeLogger = exports.LogLevel = void 0;
/**
* We share a logger with the callback that the consumer can use.
* For now, we are using `console` directly, but we might proxy it latter to add more info.
*/
var clientside_extensions_base_1 = require("@atlassian/clientside-extensions-base");
var debug_state_1 = require("./debug-state");
var debug_subjects_1 = require("./debug-subjects");
var LogLevel;
(function (LogLevel) {
LogLevel["debug"] = "DEBUG";
LogLevel["info"] = "INFO";
LogLevel["warn"] = "WARN";
LogLevel["error"] = "ERROR";
LogLevel["trace"] = "TRACE";
})(LogLevel = exports.LogLevel || (exports.LogLevel = {}));
var debuggerSubject = debug_subjects_1.registerDebugSubject('logger', function () { return new clientside_extensions_base_1.ReplaySubject(20); });
exports.observeLogger = function (observer) { return debug_subjects_1.observeDebugSubject('logger', observer); };
var onDebug = function (callback) {
if (debug_state_1.isDebugEnabled()) {
var payload = callback(LogLevel);
if (payload && debug_state_1.isLoggingEnabled()) {
debuggerSubject.notify(payload);
}
exports.onDebug = void 0;
const debug_state_1 = require("./debug-state");
const logger_1 = require("./logger/logger");
// eslint-disable-next-line import/prefer-default-export
const onDebug = (callback) => {
// Return early if both debug and logging is disabled
if (!(0, debug_state_1.isDebugEnabled)() || !(0, debug_state_1.isLoggingEnabled)()) {
return;
}
let payload;
try {
payload = callback(logger_1.LogLevel);
}
catch (e) {
// eslint-disable-next-line no-empty
}
if (payload) {
logger_1._loggerSubject.notify(payload);
}
};
exports.onDebug = onDebug;
//# sourceMappingURL=debug.js.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports._deregisterDefaultLogger = void 0;
var tslib_1 = require("tslib");
var console_1 = tslib_1.__importDefault(require("./logger/console"));
tslib_1.__exportStar(require("./debug"), exports);
tslib_1.__exportStar(require("./debug-state"), exports);
var consoleLogger = console_1.default();
var deregisterDefaultLogger = function () { return consoleLogger.unsubscribe(); };
exports._deregisterDefaultLogger = deregisterDefaultLogger;
exports.observeStateChange = exports.setValidationEnabled = exports.setDiscoveryEnabled = exports.setLoggingEnabled = exports.setDebugEnabled = exports.isValidationEnabled = exports.isDiscoveryEnabled = exports.isLoggingEnabled = exports.isDebugEnabled = exports.consoleLogger = exports._deregisterDefaultLogger = exports.setLogger = exports.observeLogger = exports.LogLevel = exports.onDebug = void 0;
var debug_1 = require("./debug");
Object.defineProperty(exports, "onDebug", { enumerable: true, get: function () { return debug_1.onDebug; } });
var logger_1 = require("./logger/logger");
Object.defineProperty(exports, "LogLevel", { enumerable: true, get: function () { return logger_1.LogLevel; } });
var default_logger_1 = require("./logger/default-logger");
/** @deprecated in 2.1.0 */ Object.defineProperty(exports, "observeLogger", { enumerable: true, get: function () { return default_logger_1.observeLogger; } });
/** @since in 2.1.0 */ Object.defineProperty(exports, "setLogger", { enumerable: true, get: function () { return default_logger_1.setLogger; } });
Object.defineProperty(exports, "_deregisterDefaultLogger", { enumerable: true, get: function () { return default_logger_1._deregisterDefaultLogger; } });
var console_1 = require("./logger/console");
Object.defineProperty(exports, "consoleLogger", { enumerable: true, get: function () { return console_1.consoleLogger; } });
var debug_state_1 = require("./debug-state");
Object.defineProperty(exports, "isDebugEnabled", { enumerable: true, get: function () { return debug_state_1.isDebugEnabled; } });
Object.defineProperty(exports, "isLoggingEnabled", { enumerable: true, get: function () { return debug_state_1.isLoggingEnabled; } });
Object.defineProperty(exports, "isDiscoveryEnabled", { enumerable: true, get: function () { return debug_state_1.isDiscoveryEnabled; } });
Object.defineProperty(exports, "isValidationEnabled", { enumerable: true, get: function () { return debug_state_1.isValidationEnabled; } });
Object.defineProperty(exports, "setDebugEnabled", { enumerable: true, get: function () { return debug_state_1.setDebugEnabled; } });
Object.defineProperty(exports, "setLoggingEnabled", { enumerable: true, get: function () { return debug_state_1.setLoggingEnabled; } });
Object.defineProperty(exports, "setDiscoveryEnabled", { enumerable: true, get: function () { return debug_state_1.setDiscoveryEnabled; } });
Object.defineProperty(exports, "setValidationEnabled", { enumerable: true, get: function () { return debug_state_1.setValidationEnabled; } });
Object.defineProperty(exports, "observeStateChange", { enumerable: true, get: function () { return debug_state_1.observeStateChange; } });
//# sourceMappingURL=index.js.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var debug_1 = require("../debug");
var getLoggingFromLevel = function (level) {
exports.consoleLogger = void 0;
const logger_1 = require("./logger");
const debug_state_1 = require("../debug-state");
const getLoggingFromLevel = (level) => {
switch (level) {
case debug_1.LogLevel.error:
case logger_1.LogLevel.error:
return 'error';
case debug_1.LogLevel.debug:
case logger_1.LogLevel.debug:
return 'debug';
case debug_1.LogLevel.info:
case logger_1.LogLevel.info:
return 'info';
case debug_1.LogLevel.trace:
return 'trace';
case debug_1.LogLevel.warn:
case logger_1.LogLevel.warn:
case logger_1.LogLevel.deprecation:
return 'warn';

@@ -20,50 +21,46 @@ default:

};
var componentsToReadable = function (components) {
if (!components) {
return '';
}
var componentsArray = Array.isArray(components) ? components : components.split('.');
return "Component: " + componentsArray.join(' → ');
// Naive implementation but we can't use bitwise operators :(
const debugLevels = Object.values(logger_1.LogLevel);
const errorLevels = debugLevels.filter((level) => level !== logger_1.LogLevel.debug);
const warnLevels = errorLevels.filter((level) => level !== logger_1.LogLevel.error);
const deprecationLevels = warnLevels.filter((level) => level !== logger_1.LogLevel.warn);
const infoLevels = deprecationLevels.filter((level) => level !== logger_1.LogLevel.deprecation);
const levelsMap = {
[logger_1.LogLevel.debug]: debugLevels,
[logger_1.LogLevel.error]: errorLevels,
[logger_1.LogLevel.warn]: warnLevels,
[logger_1.LogLevel.deprecation]: deprecationLevels,
[logger_1.LogLevel.info]: infoLevels,
};
var metaFormatter = function (_, value) {
if (value === null) {
return 'null';
function shouldDisplayLog(logLevel, eventLogLevel) {
if (logLevel === logger_1.LogLevel.debug) {
return true;
}
if (value === undefined) {
return 'undefined';
const levels = levelsMap[logLevel];
return Array.isArray(levels) ? levels.includes(eventLogLevel) : false;
}
// eslint-disable-next-line import/prefer-default-export
const consoleLogger = (payload) => {
const eventLogLevel = payload.level;
const logLevel = (0, debug_state_1.getLogLevel)();
if (!shouldDisplayLog(logLevel, eventLogLevel)) {
return;
}
if (Array.isArray(value)) {
return value.join(', ');
const consoleKey = getLoggingFromLevel(eventLogLevel);
const deprecationWarning = payload.level === logger_1.LogLevel.deprecation
? `⚠️⚠️⚠️ DEPRECATION WARNING ⚠️⚠️⚠️
`
: '';
console[consoleKey](`${deprecationWarning}[Atlassian Client-side Extensions]: ${payload.message}`);
// Verbose logging
if (logLevel === logger_1.LogLevel.debug) {
console.groupCollapsed(' <click here for more details about above message>');
console.log({
components: payload.components,
meta: payload.meta,
});
console.groupEnd();
}
if (typeof value === 'function') {
return value.toString();
}
return value;
};
var metaValueToReadable = function (value) { return JSON.stringify(value, metaFormatter).replace(/^"|"$/g, '').replace(/"/g, ' '); };
var metaToReadable = function (meta) {
if (!meta) {
return '';
}
var separator = '\n\t\t';
return "Meta information:" + separator + Object.keys(meta)
.map(function (key) { return key + ": " + metaValueToReadable(meta[key]); })
.join('\n\t\t');
};
/* eslint-disable no-underscore-dangle */
var registerConsoleLogger = function () {
// Singleton workaround as this module may be executed more than once.
// We only ever want one global default logger, however.
if (window.____c_p_d_l_d) {
return window.____c_p_d_l_d;
}
window.____c_p_d_l_d = debug_1.observeLogger(function (payload) {
var consoleKey = getLoggingFromLevel(payload.level);
// eslint-disable-next-line no-console
console[consoleKey]("[Atlassian Client-side Extensions]\n" + componentsToReadable(payload.components) + "\n\n" + payload.message + "\n\n" + metaToReadable(payload.meta) + "\n");
});
return window.____c_p_d_l_d;
};
/* eslint-enable no-underscore-dangle */
exports.default = registerConsoleLogger;
exports.consoleLogger = consoleLogger;
//# sourceMappingURL=console.js.map
/* eslint-disable no-underscore-dangle */
var _a;
import { ReplaySubject } from '@atlassian/clientside-extensions-base';
import { observeDebugSubject, registerDebugSubject } from './debug-subjects';
var ClientPluginDebugTypes;
(function (ClientPluginDebugTypes) {
ClientPluginDebugTypes["debug"] = "debug";
ClientPluginDebugTypes["logging"] = "logging";
ClientPluginDebugTypes["validation"] = "validation";
ClientPluginDebugTypes["discovery"] = "discovery";
})(ClientPluginDebugTypes || (ClientPluginDebugTypes = {}));
var defineDebugGlobal = function (previousGlobal) {
import { LogLevel } from './logger/logger';
var ClientExtensionDebugTypes;
(function (ClientExtensionDebugTypes) {
ClientExtensionDebugTypes["debug"] = "debug";
ClientExtensionDebugTypes["logging"] = "logging";
ClientExtensionDebugTypes["validation"] = "validation";
ClientExtensionDebugTypes["discovery"] = "discovery";
/** @since 2.1.0 */
ClientExtensionDebugTypes["logLevel"] = "logLevel";
})(ClientExtensionDebugTypes || (ClientExtensionDebugTypes = {}));
const defineDebugGlobal = (previousGlobal) => {
// initialize as boolean
var debugGlobal = Object.create(null);
var debugStates = {
const debugGlobal = Object.create(null);
const debugStates = {
debug: false,

@@ -19,10 +23,13 @@ logging: false,

discovery: false,
/** @since 2.1.0 */
// In dev mode we set default loglevel to INFO
logLevel: process.env.NODE_ENV === 'production' ? LogLevel.error : LogLevel.info,
};
var debugStateSubject = registerDebugSubject('state', function () { return new ReplaySubject(1); });
var properties = {
const debugStateSubject = registerDebugSubject("state" /* State */, () => new ReplaySubject(1));
const properties = {
debug: {
get: function () {
get() {
return debugStates.debug;
},
set: function (val) {
set(val) {
debugStates.debug = Boolean(val);

@@ -33,6 +40,6 @@ debugStateSubject.notify(debugStates);

logging: {
get: function () {
get() {
return debugStates.logging;
},
set: function (val) {
set(val) {
debugStates.logging = Boolean(val);

@@ -43,6 +50,6 @@ debugStateSubject.notify(debugStates);

validation: {
get: function () {
get() {
return debugStates.validation;
},
set: function (val) {
set(val) {
debugStates.validation = Boolean(val);

@@ -53,6 +60,6 @@ debugStateSubject.notify(debugStates);

discovery: {
get: function () {
get() {
return debugStates.discovery;
},
set: function (val) {
set(val) {
debugStates.discovery = Boolean(val);

@@ -62,2 +69,17 @@ debugStateSubject.notify(debugStates);

},
/** @since 2.1.0 */
logLevel: {
get() {
return debugStates.logLevel;
},
set(val) {
let level = String(val).toUpperCase();
// Handle runtime errors
if (!Object.values(LogLevel).includes(level)) {
level = LogLevel.info;
}
debugStates.logLevel = level;
debugStateSubject.notify(debugStates);
},
},
__initialized: { value: true, writable: false },

@@ -68,6 +90,6 @@ };

configurable: true,
get: function () {
get() {
return debugGlobal;
},
set: function (val) {
set(val) {
// its a boolean

@@ -86,3 +108,4 @@ if (val === true || val === false) {

}
['debug', 'logging', 'validation', 'discovery'].forEach(function (key) {
const clientExtensionDebugKeys = Object.keys(ClientExtensionDebugTypes);
clientExtensionDebugKeys.forEach((key) => {
if (key in val) {

@@ -94,32 +117,44 @@ debugGlobal[key] = val[key];

});
// Now, we can use the previous value e.g. boolean, to set the value for all flags
window.____c_p_d = previousGlobal;
};
if (!window.____c_p_d || !window.____c_p_d.__initialized) {
defineDebugGlobal(window.____c_p_d || process.env.NODE_ENV !== 'production');
// Register global value only once
if (!('____c_p_d' in window) || !window.____c_p_d.__initialized) {
defineDebugGlobal((_a = window.____c_p_d) !== null && _a !== void 0 ? _a : process.env.NODE_ENV !== 'production');
}
export var observeStateChange = function (observer) { return observeDebugSubject('state', observer); };
export var isDebugEnabled = function () {
export const observeStateChange = (observer) => observeDebugSubject("state" /* State */, observer);
export const isDebugEnabled = () => {
return window.____c_p_d.debug;
};
export var isLoggingEnabled = function () {
export const isLoggingEnabled = () => {
return window.____c_p_d.logging;
};
export var isValidationEnabled = function () {
export const isValidationEnabled = () => {
return window.____c_p_d.validation;
};
export var isDiscoveryEnabled = function () {
export const isDiscoveryEnabled = () => {
return window.____c_p_d.discovery;
};
export var setDebugEnabled = function (value) {
/** @since 2.1.0 */
export const getLogLevel = () => {
const logLevel = window.____c_p_d.logLevel;
return logLevel !== null && logLevel !== void 0 ? logLevel : LogLevel.info;
};
export const setDebugEnabled = (value) => {
window.____c_p_d.debug = value;
};
export var setLoggingEnabled = function (value) {
export const setLoggingEnabled = (value) => {
window.____c_p_d.logging = value;
};
export var setValidationEnabled = function (value) {
export const setValidationEnabled = (value) => {
window.____c_p_d.validation = value;
};
export var setDiscoveryEnabled = function (value) {
export const setDiscoveryEnabled = (value) => {
window.____c_p_d.discovery = value;
};
/** @since 2.1.0 */
export const setLogLevel = (value) => {
const level = value.toUpperCase();
window.____c_p_d.logLevel = level;
};
//# sourceMappingURL=debug-state.js.map

@@ -1,7 +0,5 @@

/* eslint-disable no-underscore-dangle */
import { Subject } from '@atlassian/clientside-extensions-base';
var defineSubjectGlobal = function () {
const defineSubjectGlobal = () => {
// initialize as boolean
var subjectGlobal = Object.create(null);
var properties = {
const subjectGlobal = Object.create(null);
const properties = {
__initialized: { value: true, writable: false },

@@ -16,19 +14,27 @@ subjects: {

};
if (!window.____c_p_s || !window.____c_p_s.__initialized) {
if (!('____c_p_s' in window) || !window.____c_p_s.__initialized) {
defineSubjectGlobal();
}
export var registerDebugSubject = function (key, subjectFactory) {
/**
* Registers a debug subject as singleton
*
* @param key
* @param subjectFactory
*/
export const registerDebugSubject = (key, subjectFactory) => {
const debugSubjects = window.____c_p_s.subjects;
// good old singletons - ensure we do not register the same subject twice.
// we also can't fail as multiple instances might try to access the same, so instead we return the previously registered one.
if (!window.____c_p_s.subjects[key]) {
window.____c_p_s.subjects[key] = subjectFactory ? subjectFactory() : new Subject();
if (!(key in debugSubjects)) {
debugSubjects[key] = subjectFactory();
}
return window.____c_p_s.subjects[key];
return debugSubjects[key];
};
export var observeDebugSubject = function (key, observer) {
if (!window.____c_p_s.subjects[key]) {
throw new Error("No subject registered for key: \"" + key + "\"");
export const observeDebugSubject = (key, observer) => {
const debugSubjects = window.____c_p_s.subjects;
if (!(key in debugSubjects)) {
throw new Error(`No subject registered for key: "${key}"`);
}
return window.____c_p_s.subjects[key].subscribe(observer);
return debugSubjects[key].subscribe(observer);
};
//# sourceMappingURL=debug-subjects.js.map

@@ -1,28 +0,20 @@

/**
* We share a logger with the callback that the consumer can use.
* For now, we are using `console` directly, but we might proxy it latter to add more info.
*/
import { ReplaySubject } from '@atlassian/clientside-extensions-base';
import { isDebugEnabled, isLoggingEnabled } from './debug-state';
import { observeDebugSubject, registerDebugSubject } from './debug-subjects';
export var LogLevel;
(function (LogLevel) {
LogLevel["debug"] = "DEBUG";
LogLevel["info"] = "INFO";
LogLevel["warn"] = "WARN";
LogLevel["error"] = "ERROR";
LogLevel["trace"] = "TRACE";
})(LogLevel || (LogLevel = {}));
var debuggerSubject = registerDebugSubject('logger', function () { return new ReplaySubject(20); });
export var observeLogger = function (observer) { return observeDebugSubject('logger', observer); };
var onDebug = function (callback) {
if (isDebugEnabled()) {
var payload = callback(LogLevel);
if (payload && isLoggingEnabled()) {
debuggerSubject.notify(payload);
}
import { _loggerSubject, LogLevel } from './logger/logger';
// eslint-disable-next-line import/prefer-default-export
export const onDebug = (callback) => {
// Return early if both debug and logging is disabled
if (!isDebugEnabled() || !isLoggingEnabled()) {
return;
}
let payload;
try {
payload = callback(LogLevel);
}
catch (e) {
// eslint-disable-next-line no-empty
}
if (payload) {
_loggerSubject.notify(payload);
}
};
// eslint-disable-next-line import/prefer-default-export
export { onDebug };
//# sourceMappingURL=debug.js.map

@@ -1,8 +0,8 @@

import registerConsoleLogger from './logger/console';
export * from './debug';
export * from './debug-state';
var consoleLogger = registerConsoleLogger();
var deregisterDefaultLogger = function () { return consoleLogger.unsubscribe(); };
// @VisibleForTesting
export { deregisterDefaultLogger as _deregisterDefaultLogger };
export { onDebug } from './debug';
export { LogLevel } from './logger/logger';
export {
/** @deprecated in 2.1.0 */ observeLogger,
/** @since in 2.1.0 */ setLogger, _deregisterDefaultLogger, } from './logger/default-logger';
export { /** @since in 2.1.0 */ consoleLogger } from './logger/console';
export { isDebugEnabled, isLoggingEnabled, isDiscoveryEnabled, isValidationEnabled, setDebugEnabled, setLoggingEnabled, setDiscoveryEnabled, setValidationEnabled, observeStateChange, } from './debug-state';
//# sourceMappingURL=index.js.map

@@ -1,3 +0,4 @@

import { LogLevel, observeLogger } from '../debug';
var getLoggingFromLevel = function (level) {
import { LogLevel } from './logger';
import { getLogLevel } from '../debug-state';
const getLoggingFromLevel = (level) => {
switch (level) {

@@ -10,5 +11,4 @@ case LogLevel.error:

return 'info';
case LogLevel.trace:
return 'trace';
case LogLevel.warn:
case LogLevel.deprecation:
return 'warn';

@@ -19,50 +19,45 @@ default:

};
var componentsToReadable = function (components) {
if (!components) {
return '';
}
var componentsArray = Array.isArray(components) ? components : components.split('.');
return "Component: " + componentsArray.join(' → ');
// Naive implementation but we can't use bitwise operators :(
const debugLevels = Object.values(LogLevel);
const errorLevels = debugLevels.filter((level) => level !== LogLevel.debug);
const warnLevels = errorLevels.filter((level) => level !== LogLevel.error);
const deprecationLevels = warnLevels.filter((level) => level !== LogLevel.warn);
const infoLevels = deprecationLevels.filter((level) => level !== LogLevel.deprecation);
const levelsMap = {
[LogLevel.debug]: debugLevels,
[LogLevel.error]: errorLevels,
[LogLevel.warn]: warnLevels,
[LogLevel.deprecation]: deprecationLevels,
[LogLevel.info]: infoLevels,
};
var metaFormatter = function (_, value) {
if (value === null) {
return 'null';
function shouldDisplayLog(logLevel, eventLogLevel) {
if (logLevel === LogLevel.debug) {
return true;
}
if (value === undefined) {
return 'undefined';
const levels = levelsMap[logLevel];
return Array.isArray(levels) ? levels.includes(eventLogLevel) : false;
}
// eslint-disable-next-line import/prefer-default-export
export const consoleLogger = (payload) => {
const eventLogLevel = payload.level;
const logLevel = getLogLevel();
if (!shouldDisplayLog(logLevel, eventLogLevel)) {
return;
}
if (Array.isArray(value)) {
return value.join(', ');
const consoleKey = getLoggingFromLevel(eventLogLevel);
const deprecationWarning = payload.level === LogLevel.deprecation
? `⚠️⚠️⚠️ DEPRECATION WARNING ⚠️⚠️⚠️
`
: '';
console[consoleKey](`${deprecationWarning}[Atlassian Client-side Extensions]: ${payload.message}`);
// Verbose logging
if (logLevel === LogLevel.debug) {
console.groupCollapsed(' <click here for more details about above message>');
console.log({
components: payload.components,
meta: payload.meta,
});
console.groupEnd();
}
if (typeof value === 'function') {
return value.toString();
}
return value;
};
var metaValueToReadable = function (value) { return JSON.stringify(value, metaFormatter).replace(/^"|"$/g, '').replace(/"/g, ' '); };
var metaToReadable = function (meta) {
if (!meta) {
return '';
}
var separator = '\n\t\t';
return "Meta information:" + separator + Object.keys(meta)
.map(function (key) { return key + ": " + metaValueToReadable(meta[key]); })
.join('\n\t\t');
};
/* eslint-disable no-underscore-dangle */
var registerConsoleLogger = function () {
// Singleton workaround as this module may be executed more than once.
// We only ever want one global default logger, however.
if (window.____c_p_d_l_d) {
return window.____c_p_d_l_d;
}
window.____c_p_d_l_d = observeLogger(function (payload) {
var consoleKey = getLoggingFromLevel(payload.level);
// eslint-disable-next-line no-console
console[consoleKey]("[Atlassian Client-side Extensions]\n" + componentsToReadable(payload.components) + "\n\n" + payload.message + "\n\n" + metaToReadable(payload.meta) + "\n");
});
return window.____c_p_d_l_d;
};
/* eslint-enable no-underscore-dangle */
export default registerConsoleLogger;
//# sourceMappingURL=console.js.map

@@ -1,13 +0,19 @@

import { Observer } from '@atlassian/clientside-extensions-base';
declare enum ClientPluginDebugTypes {
import type { Observer } from '@atlassian/clientside-extensions-base';
import { LogLevel } from './logger/logger';
declare enum ClientExtensionDebugTypes {
debug = "debug",
logging = "logging",
validation = "validation",
discovery = "discovery"
discovery = "discovery",
/** @since 2.1.0 */
logLevel = "logLevel"
}
export declare type ClientPluginDebug = {
[key in ClientPluginDebugTypes]: boolean;
declare type DebugTypeKeys = Exclude<keyof typeof ClientExtensionDebugTypes, 'logLevel'>;
export declare type ClientExtensionDebug = {
[key in DebugTypeKeys]: boolean;
} & {
[ClientExtensionDebugTypes.logLevel]: LogLevel;
};
declare type ExposedClientPluginDebug = {
[key in keyof ClientPluginDebug]: PropertyDescriptor;
export declare type ExposedClientExtensionDebug = {
[key in keyof ClientExtensionDebug]: PropertyDescriptor;
} & {

@@ -18,6 +24,6 @@ __initialized: PropertyDescriptor;

interface Window {
____c_p_d: ExposedClientPluginDebug;
____c_p_d: ExposedClientExtensionDebug;
}
}
export declare const observeStateChange: (observer: Observer<ClientPluginDebug>) => import("@atlassian/clientside-extensions-base").Subscription;
export declare const observeStateChange: (observer: Observer<ClientExtensionDebug>) => import("@atlassian/clientside-extensions-base").Subscription;
export declare const isDebugEnabled: () => boolean;

@@ -27,2 +33,4 @@ export declare const isLoggingEnabled: () => boolean;

export declare const isDiscoveryEnabled: () => boolean;
/** @since 2.1.0 */
export declare const getLogLevel: () => LogLevel;
export declare const setDebugEnabled: (value: boolean) => void;

@@ -32,3 +40,5 @@ export declare const setLoggingEnabled: (value: boolean) => void;

export declare const setDiscoveryEnabled: (value: boolean) => void;
/** @since 2.1.0 */
export declare const setLogLevel: (value: string) => void;
export {};
//# sourceMappingURL=debug-state.d.ts.map

@@ -1,14 +0,25 @@

import { Observer, Subject } from '@atlassian/clientside-extensions-base';
declare type ExposedClientPluginSubjects = {
import type { Observer, Subject } from '@atlassian/clientside-extensions-base';
declare type ExposedClientExtensionSubjects = {
__initialized: PropertyDescriptor;
subjects: PropertyDescriptor;
};
export declare const enum DebugSubjects {
Logger = "logger",
State = "state"
}
declare global {
interface Window {
____c_p_s: ExposedClientPluginSubjects;
____c_p_s: ExposedClientExtensionSubjects;
}
}
export declare const registerDebugSubject: <T>(key: string, subjectFactory?: () => Subject<T>) => Subject<T>;
export declare const observeDebugSubject: <T>(key: string, observer: Observer<T>) => import("@atlassian/clientside-extensions-base").Subscription;
declare type UnpackPayloadType<SubjectType> = SubjectType extends Subject<infer U> ? U : never;
/**
* Registers a debug subject as singleton
*
* @param key
* @param subjectFactory
*/
export declare const registerDebugSubject: <SubjectType extends Subject<PayloadType>, PayloadType = UnpackPayloadType<SubjectType>>(key: DebugSubjects, subjectFactory: () => SubjectType) => SubjectType;
export declare const observeDebugSubject: <PayloadType>(key: DebugSubjects, observer: Observer<PayloadType>) => import("@atlassian/clientside-extensions-base").Subscription;
export {};
//# sourceMappingURL=debug-subjects.d.ts.map

@@ -1,25 +0,3 @@

/**
* We share a logger with the callback that the consumer can use.
* For now, we are using `console` directly, but we might proxy it latter to add more info.
*/
import { Observer } from '@atlassian/clientside-extensions-base';
export declare enum LogLevel {
debug = "DEBUG",
info = "INFO",
warn = "WARN",
error = "ERROR",
trace = "TRACE"
}
export declare type LoggerPayload = {
level: LogLevel;
message: string;
components?: string | string[];
meta?: {
[key: string]: unknown;
};
};
declare type LoggerCallback = (levels: typeof LogLevel) => LoggerPayload;
export declare const observeLogger: (observer: Observer<LoggerPayload>) => import("@atlassian/clientside-extensions-base").Subscription;
declare const onDebug: (callback: LoggerCallback) => void;
export { onDebug };
import type { LoggerCallback } from './logger/logger';
export declare const onDebug: (callback: LoggerCallback) => void;
//# sourceMappingURL=debug.d.ts.map

@@ -1,5 +0,9 @@

export * from './debug';
export * from './debug-state';
declare const deregisterDefaultLogger: () => void;
export { deregisterDefaultLogger as _deregisterDefaultLogger };
export { onDebug } from './debug';
export type { LoggerPayload } from './logger/logger';
export { LogLevel } from './logger/logger';
export {
/** @deprecated in 2.1.0 */ observeLogger,
/** @since in 2.1.0 */ setLogger, _deregisterDefaultLogger, } from './logger/default-logger';
export { /** @since in 2.1.0 */ consoleLogger } from './logger/console';
export { isDebugEnabled, isLoggingEnabled, isDiscoveryEnabled, isValidationEnabled, setDebugEnabled, setLoggingEnabled, setDiscoveryEnabled, setValidationEnabled, observeStateChange, } from './debug-state';
//# sourceMappingURL=index.d.ts.map

@@ -1,9 +0,3 @@

import { Subscription } from '@atlassian/clientside-extensions-base';
declare global {
interface Window {
____c_p_d_l_d: Subscription;
}
}
declare const registerConsoleLogger: () => Subscription;
export default registerConsoleLogger;
import type { LoggerPayload } from './logger';
export declare const consoleLogger: (payload: LoggerPayload) => void;
//# sourceMappingURL=console.d.ts.map
/* eslint-disable no-underscore-dangle */
import { LogLevel } from './logger/logger';
/**

@@ -14,2 +16,3 @@ * Using async imports in order to test process.env.NODE_ENV usage in module

// with the new NODE_ENV value
// @ts-expect-error We don't care about the TS2790 issue here
delete window.____c_p_d;

@@ -22,4 +25,3 @@ jest.resetModules();

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const debugStateModule = await import('./debug-state');
await import('./debug-state');

@@ -34,14 +36,21 @@ expect(window.____c_p_d.__initialized).toBe(true);

it('should be set to TRUE if process.env.NODE_ENV is different than "production"', async () => {
process.env.NODE_ENV = 'test';
it('should set the default log level to "ERROR" if process.env.NODE_ENV is "production"', async () => {
process.env.NODE_ENV = 'production';
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const debugStateModule = await import('./debug-state');
await import('./debug-state');
expect(window.____c_p_d.__initialized).toBe(true);
expect(window.____c_p_d.logLevel).toBe(LogLevel.error);
});
expect(window.____c_p_d.debug).toBe(true);
expect(window.____c_p_d.logging).toBe(true);
expect(window.____c_p_d.validation).toBe(true);
expect(window.____c_p_d.discovery).toBe(true);
it('should be set the default log level to "INFO" if process.env.NODE_ENV is different than "production"', async () => {
process.env.NODE_ENV = 'development';
// eslint-disable-next-line @typescript-eslint/no-unused-vars
await import('./debug-state');
expect(window.____c_p_d.__initialized).toBe(true);
expect(window.____c_p_d.logLevel).toBe(LogLevel.info);
});
});
/* eslint-disable no-underscore-dangle, jest/no-standalone-expect */
import cases from 'jest-in-case';
import { isDebugEnabled, isDiscoveryEnabled, isLoggingEnabled, isValidationEnabled } from './debug-state';
import type { ExposedClientExtensionDebug } from './debug-state';
import { isDebugEnabled, isDiscoveryEnabled, isLoggingEnabled, isValidationEnabled, getLogLevel, setLogLevel } from './debug-state';
import { LogLevel } from './logger/logger';
describe('is* utils', () => {
describe('debug utils', () => {
beforeEach(() => {

@@ -12,3 +14,3 @@ (window.____c_p_d as unknown) = false;

'should be active if respective flag is set to TRUE',
opts => {
(opts) => {
expect(opts.isUtil()).toBe(false);

@@ -38,2 +40,50 @@

);
describe('log levels', () => {
let prevDebugState: ExposedClientExtensionDebug;
beforeEach(() => {
prevDebugState = window.____c_p_d;
});
afterEach(() => {
window.____c_p_d = prevDebugState;
});
it('should allow to change the default log level using utils', () => {
expect(getLogLevel()).toBe(LogLevel.info);
setLogLevel(LogLevel.debug);
expect(getLogLevel()).toBe(LogLevel.debug);
});
it('should allow to change log level using global variable', () => {
// Change with enum
(window.____c_p_d.logLevel as LogLevel) = LogLevel.error;
expect(getLogLevel()).toBe(LogLevel.error);
// Change with string value
(window.____c_p_d.logLevel as string) = 'warn';
expect(getLogLevel()).toBe(LogLevel.warn);
});
it('should fallback to a default "INFO" level when using unsupported runtime value', () => {
(window.____c_p_d.logLevel as string) = 'show-me-all-the-things';
expect(getLogLevel()).toBe(LogLevel.info);
});
});
describe('compatibility mode', () => {
it('should fallback to a default "INFO" level when "logLevel" property is missing e.g. CSE < 2.1.0', () => {
Object.defineProperty(window, '____c_p_d', {
value: {},
configurable: true,
writable: true,
});
expect(getLogLevel()).toBe(LogLevel.info);
});
});
});
/* eslint-disable no-underscore-dangle */
import { Observer, ReplaySubject } from '@atlassian/clientside-extensions-base';
import { observeDebugSubject, registerDebugSubject } from './debug-subjects';
import type { Observer } from '@atlassian/clientside-extensions-base';
import { ReplaySubject } from '@atlassian/clientside-extensions-base';
import { DebugSubjects, observeDebugSubject, registerDebugSubject } from './debug-subjects';
import { LogLevel } from './logger/logger';
enum ClientPluginDebugTypes {
enum ClientExtensionDebugTypes {
debug = 'debug',

@@ -11,9 +13,15 @@ logging = 'logging',

discovery = 'discovery',
/** @since 2.1.0 */
logLevel = 'logLevel',
}
export type ClientPluginDebug = {
[key in ClientPluginDebugTypes]: boolean;
type DebugTypeKeys = Exclude<keyof typeof ClientExtensionDebugTypes, 'logLevel'>;
export type ClientExtensionDebug = {
[key in DebugTypeKeys]: boolean;
} & {
[ClientExtensionDebugTypes.logLevel]: LogLevel;
};
type ExposedClientPluginDebug = { [key in keyof ClientPluginDebug]: PropertyDescriptor } & {
export type ExposedClientExtensionDebug = { [key in keyof ClientExtensionDebug]: PropertyDescriptor } & {
__initialized: PropertyDescriptor;

@@ -23,4 +31,7 @@ };

declare global {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface Window {
____c_p_d: ExposedClientPluginDebug;
// The global ____c_p_d is a primitive boolean value that holds additional properties
// Due to historical name changes the "p" still represents the old "plugin" nomenclature
____c_p_d: ExposedClientExtensionDebug;
}

@@ -32,3 +43,3 @@ }

const debugGlobal = Object.create(null);
const debugStates: ClientPluginDebug = {
const debugStates: ClientExtensionDebug = {
debug: false,

@@ -38,7 +49,10 @@ logging: false,

discovery: false,
/** @since 2.1.0 */
// In dev mode we set default loglevel to INFO
logLevel: process.env.NODE_ENV === 'production' ? LogLevel.error : LogLevel.info,
};
const debugStateSubject = registerDebugSubject<ClientPluginDebug>('state', () => new ReplaySubject(1));
const debugStateSubject = registerDebugSubject(DebugSubjects.State, () => new ReplaySubject(1));
const properties: ExposedClientPluginDebug = {
const properties: ExposedClientExtensionDebug = {
debug: {

@@ -80,2 +94,19 @@ get() {

},
/** @since 2.1.0 */
logLevel: {
get() {
return debugStates.logLevel;
},
set(val: unknown) {
let level = String(val).toUpperCase() as LogLevel;
// Handle runtime errors
if (!Object.values(LogLevel).includes(level)) {
level = LogLevel.info;
}
debugStates.logLevel = level;
debugStateSubject.notify(debugStates);
},
},
__initialized: { value: true, writable: false },

@@ -106,5 +137,5 @@ };

// we now have an object
type KeysOfClientPluginDebug = keyof ClientPluginDebug;
(['debug', 'logging', 'validation', 'discovery'] as KeysOfClientPluginDebug[]).forEach(key => {
const clientExtensionDebugKeys = Object.keys(ClientExtensionDebugTypes) as (keyof ClientExtensionDebug)[];
clientExtensionDebugKeys.forEach((key) => {
if (key in val) {

@@ -116,10 +147,14 @@ debugGlobal[key] = val[key];

});
window.____c_p_d = previousGlobal as ExposedClientPluginDebug;
// Now, we can use the previous value e.g. boolean, to set the value for all flags
window.____c_p_d = previousGlobal as ExposedClientExtensionDebug;
};
if (!window.____c_p_d || !window.____c_p_d.__initialized) {
defineDebugGlobal(window.____c_p_d || process.env.NODE_ENV !== 'production');
// Register global value only once
if (!('____c_p_d' in window) || !window.____c_p_d.__initialized) {
defineDebugGlobal(window.____c_p_d ?? process.env.NODE_ENV !== 'production');
}
export const observeStateChange = (observer: Observer<ClientPluginDebug>) => observeDebugSubject<ClientPluginDebug>('state', observer);
export const observeStateChange = (observer: Observer<ClientExtensionDebug>) =>
observeDebugSubject<ClientExtensionDebug>(DebugSubjects.State, observer);

@@ -142,2 +177,9 @@ export const isDebugEnabled = () => {

/** @since 2.1.0 */
export const getLogLevel = (): LogLevel => {
const logLevel = window.____c_p_d.logLevel as LogLevel;
return logLevel ?? LogLevel.info;
};
export const setDebugEnabled = (value: boolean) => {

@@ -158,1 +200,8 @@ (window.____c_p_d.debug as boolean) = value;

};
/** @since 2.1.0 */
export const setLogLevel = (value: string) => {
const level = value.toUpperCase() as LogLevel;
(window.____c_p_d.logLevel as LogLevel) = level;
};
/* eslint-disable no-underscore-dangle */
import { Observer, Subject } from '@atlassian/clientside-extensions-base';
import type { Observer, Subject } from '@atlassian/clientside-extensions-base';
type ExposedClientPluginSubjects = {
type ExposedClientExtensionSubjects = {
__initialized: PropertyDescriptor;

@@ -9,9 +9,16 @@ subjects: PropertyDescriptor;

type DebugSubjects = {
[key: string]: Subject<unknown>;
export const enum DebugSubjects {
Logger = 'logger',
State = 'state',
}
type DebugSubjectsMap<SubjectT> = {
[key in DebugSubjects]: SubjectT;
};
declare global {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface Window {
____c_p_s: ExposedClientPluginSubjects;
// Due to historical name changes the "p" still represents the old "plugin" nomenclature
____c_p_s: ExposedClientExtensionSubjects;
}

@@ -24,3 +31,3 @@ }

const properties: ExposedClientPluginSubjects = {
const properties: ExposedClientExtensionSubjects = {
__initialized: { value: true, writable: false },

@@ -32,2 +39,3 @@ subjects: {

};
Object.defineProperties(subjectGlobal, properties);

@@ -38,20 +46,37 @@

if (!window.____c_p_s || !window.____c_p_s.__initialized) {
if (!('____c_p_s' in window) || !window.____c_p_s.__initialized) {
defineSubjectGlobal();
}
export const registerDebugSubject = <T>(key: string, subjectFactory?: () => Subject<T>): Subject<T> => {
type UnpackPayloadType<SubjectType> = SubjectType extends Subject<infer U> ? U : never;
/**
* Registers a debug subject as singleton
*
* @param key
* @param subjectFactory
*/
export const registerDebugSubject = <SubjectType extends Subject<PayloadType>, PayloadType = UnpackPayloadType<SubjectType>>(
key: DebugSubjects,
subjectFactory: () => SubjectType,
): SubjectType => {
const debugSubjects = window.____c_p_s.subjects as DebugSubjectsMap<SubjectType>;
// good old singletons - ensure we do not register the same subject twice.
// we also can't fail as multiple instances might try to access the same, so instead we return the previously registered one.
if (!(window.____c_p_s.subjects as DebugSubjects)[key]) {
(window.____c_p_s.subjects as DebugSubjects)[key] = subjectFactory ? subjectFactory() : new Subject<T>();
if (!(key in debugSubjects)) {
debugSubjects[key] = subjectFactory();
}
return (window.____c_p_s.subjects as DebugSubjects)[key] as Subject<T>;
return debugSubjects[key];
};
export const observeDebugSubject = <T>(key: string, observer: Observer<T>) => {
if (!(window.____c_p_s.subjects as DebugSubjects)[key]) {
export const observeDebugSubject = <PayloadType>(key: DebugSubjects, observer: Observer<PayloadType>) => {
const debugSubjects = window.____c_p_s.subjects as DebugSubjectsMap<Subject<PayloadType>>;
if (!(key in debugSubjects)) {
throw new Error(`No subject registered for key: "${key}"`);
}
return (window.____c_p_s.subjects as DebugSubjects)[key].subscribe(observer);
return debugSubjects[key].subscribe(observer);
};
import { mocked } from 'ts-jest/utils';
import { isDebugEnabled, isLoggingEnabled } from './debug-state';
import { LogLevel, observeLogger, onDebug } from './debug';
import { getLogLevel, isDebugEnabled, isLoggingEnabled } from './debug-state';
import { onDebug } from './debug';
import { LogLevel } from './logger/logger';
import { observeLogger } from './logger/default-logger';

@@ -8,12 +10,32 @@ jest.mock('./debug-state');

describe('onDebug util', () => {
const orgConsole = global.console;
beforeEach(() => {
mocked(isDebugEnabled).mockReturnValue(false);
mocked(isLoggingEnabled).mockReturnValue(false);
mocked(getLogLevel).mockReturnValue(LogLevel.debug);
// Silent down console
global.console = {
...orgConsole,
error: jest.fn(),
log: jest.fn(),
groupCollapsed: jest.fn(),
};
});
afterEach(() => {
mocked(isDebugEnabled).mockClear();
mocked(isLoggingEnabled).mockClear();
mocked(getLogLevel).mockClear();
global.console = orgConsole;
});
it('should only execute the given callback when debug is enabled', () => {
it('should only execute the given callback when debug and logging is enabled', () => {
const debugCallbackSpy = jest.fn();
// disable
mocked(isDebugEnabled).mockReturnValueOnce(false);
mocked(isDebugEnabled).mockReturnValue(false);
mocked(isLoggingEnabled).mockReturnValue(false);

@@ -25,3 +47,4 @@ onDebug(debugCallbackSpy);

// enable
mocked(isDebugEnabled).mockReturnValueOnce(true);
mocked(isDebugEnabled).mockReturnValue(true);
mocked(isLoggingEnabled).mockReturnValue(true);

@@ -44,3 +67,3 @@ onDebug(debugCallbackSpy);

// disable
mocked(isLoggingEnabled).mockReturnValueOnce(false);
mocked(isLoggingEnabled).mockReturnValue(false);

@@ -50,12 +73,27 @@ observeLogger(loggerObserver);

expect(loggerCallback).toBeCalledTimes(1);
expect(loggerObserver).not.toBeCalled();
expect(loggerCallback).not.toHaveBeenCalled();
expect(loggerObserver).not.toHaveBeenCalled();
// enable
mocked(isLoggingEnabled).mockReturnValueOnce(true);
mocked(isLoggingEnabled).mockReturnValue(true);
onDebug(loggerCallback);
expect(loggerCallback).toBeCalledTimes(2);
expect(loggerObserver).toBeCalledWith(payload);
expect(loggerCallback).toHaveBeenCalledTimes(1);
expect(loggerObserver).toHaveBeenCalledWith(payload);
});
it('should not throw an error when logger callback fails', () => {
mocked(isDebugEnabled).mockReturnValue(true);
mocked(isLoggingEnabled).mockReturnValue(true);
const callOnDebug = () => {
const loggerCallback = () => {
throw new Error('ups');
};
onDebug(loggerCallback);
};
expect(callOnDebug).not.toThrow();
});
});

@@ -1,42 +0,24 @@

/**
* We share a logger with the callback that the consumer can use.
* For now, we are using `console` directly, but we might proxy it latter to add more info.
*/
import { Observer, ReplaySubject } from '@atlassian/clientside-extensions-base';
import { isDebugEnabled, isLoggingEnabled } from './debug-state';
import { observeDebugSubject, registerDebugSubject } from './debug-subjects';
export enum LogLevel {
debug = 'DEBUG',
info = 'INFO',
warn = 'WARN',
error = 'ERROR',
trace = 'TRACE',
}
import type { LoggerCallback, LoggerPayload } from './logger/logger';
import { _loggerSubject, LogLevel } from './logger/logger';
export type LoggerPayload = {
level: LogLevel;
message: string;
components?: string | string[];
meta?: {
[key: string]: unknown;
};
};
// eslint-disable-next-line import/prefer-default-export
export const onDebug = (callback: LoggerCallback) => {
// Return early if both debug and logging is disabled
if (!isDebugEnabled() || !isLoggingEnabled()) {
return;
}
type LoggerCallback = (levels: typeof LogLevel) => LoggerPayload;
let payload: LoggerPayload | undefined;
const debuggerSubject = registerDebugSubject<LoggerPayload>('logger', () => new ReplaySubject(20));
try {
payload = callback(LogLevel);
} catch (e) {
// eslint-disable-next-line no-empty
}
export const observeLogger = (observer: Observer<LoggerPayload>) => observeDebugSubject<LoggerPayload>('logger', observer);
const onDebug = (callback: LoggerCallback) => {
if (isDebugEnabled()) {
const payload = callback(LogLevel);
if (payload && isLoggingEnabled()) {
debuggerSubject.notify(payload);
}
if (payload) {
_loggerSubject.notify(payload);
}
};
// eslint-disable-next-line import/prefer-default-export
export { onDebug };

@@ -1,11 +0,23 @@

import registerConsoleLogger from './logger/console';
export { onDebug } from './debug';
export type { LoggerPayload } from './logger/logger';
export { LogLevel } from './logger/logger';
export * from './debug';
export * from './debug-state';
export {
/** @deprecated in 2.1.0 */ observeLogger,
/** @since in 2.1.0 */ setLogger,
_deregisterDefaultLogger,
} from './logger/default-logger';
const consoleLogger = registerConsoleLogger();
export { /** @since in 2.1.0 */ consoleLogger } from './logger/console';
const deregisterDefaultLogger = () => consoleLogger.unsubscribe();
// @VisibleForTesting
export { deregisterDefaultLogger as _deregisterDefaultLogger };
export {
isDebugEnabled,
isLoggingEnabled,
isDiscoveryEnabled,
isValidationEnabled,
setDebugEnabled,
setLoggingEnabled,
setDiscoveryEnabled,
setValidationEnabled,
observeStateChange,
} from './debug-state';

@@ -1,5 +0,9 @@

import { Subscription } from '@atlassian/clientside-extensions-base';
import { LoggerPayload, LogLevel, observeLogger } from '../debug';
import type { LoggerPayload } from './logger';
import { LogLevel } from './logger';
import { getLogLevel } from '../debug-state';
const getLoggingFromLevel = (level: LogLevel): keyof typeof console => {
// We need to pick the callable keys from the console object
type ConsoleLogsTypes = keyof Pick<typeof console, 'log' | 'warn' | 'error' | 'info' | 'debug'>;
const getLoggingFromLevel = (level: LogLevel): ConsoleLogsTypes => {
switch (level) {

@@ -12,5 +16,4 @@ case LogLevel.error:

return 'info';
case LogLevel.trace:
return 'trace';
case LogLevel.warn:
case LogLevel.deprecation:
return 'warn';

@@ -22,75 +25,54 @@ default:

const componentsToReadable = (components?: string | string[]) => {
if (!components) {
return '';
}
// Naive implementation but we can't use bitwise operators :(
const debugLevels = Object.values(LogLevel);
const errorLevels = debugLevels.filter((level) => level !== LogLevel.debug);
const warnLevels = errorLevels.filter((level) => level !== LogLevel.error);
const deprecationLevels = warnLevels.filter((level) => level !== LogLevel.warn);
const infoLevels = deprecationLevels.filter((level) => level !== LogLevel.deprecation);
const componentsArray = Array.isArray(components) ? components : components.split('.');
return `Component: ${componentsArray.join(' → ')}`;
const levelsMap: { [key: string]: string[] } = {
[LogLevel.debug]: debugLevels,
[LogLevel.error]: errorLevels,
[LogLevel.warn]: warnLevels,
[LogLevel.deprecation]: deprecationLevels,
[LogLevel.info]: infoLevels,
};
const metaFormatter = (_: unknown, value: unknown): string => {
if (value === null) {
return 'null';
function shouldDisplayLog(logLevel: LogLevel, eventLogLevel: LogLevel) {
if (logLevel === LogLevel.debug) {
return true;
}
if (value === undefined) {
return 'undefined';
}
const levels = levelsMap[logLevel];
if (Array.isArray(value)) {
return value.join(', ');
}
return Array.isArray(levels) ? levels.includes(eventLogLevel) : false;
}
if (typeof value === 'function') {
return value.toString();
}
// eslint-disable-next-line import/prefer-default-export
export const consoleLogger = (payload: LoggerPayload) => {
const eventLogLevel = payload.level;
const logLevel = getLogLevel();
return value as string;
};
const metaValueToReadable = (value: unknown) => JSON.stringify(value, metaFormatter).replace(/^"|"$/g, '').replace(/"/g, ' ');
const metaToReadable = (meta?: LoggerPayload['meta']) => {
if (!meta) {
return '';
if (!shouldDisplayLog(logLevel, eventLogLevel)) {
return;
}
const separator = '\n\t\t';
return `Meta information:${separator}${Object.keys(meta)
.map(key => `${key}: ${metaValueToReadable(meta[key])}`)
.join('\n\t\t')}`;
};
const consoleKey = getLoggingFromLevel(eventLogLevel);
const deprecationWarning =
payload.level === LogLevel.deprecation
? `⚠️⚠️⚠️ DEPRECATION WARNING ⚠️⚠️⚠️
`
: '';
declare global {
interface Window {
// clientside extension default logging deregister
____c_p_d_l_d: Subscription;
}
}
console[consoleKey](`${deprecationWarning}[Atlassian Client-side Extensions]: ${payload.message}`);
/* eslint-disable no-underscore-dangle */
const registerConsoleLogger = () => {
// Singleton workaround as this module may be executed more than once.
// We only ever want one global default logger, however.
if (window.____c_p_d_l_d) {
return window.____c_p_d_l_d;
// Verbose logging
if (logLevel === LogLevel.debug) {
console.groupCollapsed(' <click here for more details about above message>');
console.log({
components: payload.components,
meta: payload.meta,
});
console.groupEnd();
}
window.____c_p_d_l_d = observeLogger(payload => {
const consoleKey = getLoggingFromLevel(payload.level);
// eslint-disable-next-line no-console
console[consoleKey](`[Atlassian Client-side Extensions]
${componentsToReadable(payload.components)}
${payload.message}
${metaToReadable(payload.meta)}
`);
});
return window.____c_p_d_l_d;
};
/* eslint-enable no-underscore-dangle */
export default registerConsoleLogger;
{
"name": "@atlassian/clientside-extensions-debug",
"version": "3.1.2-test9-85e70efb",
"version": "4.0.0-jakarta-m001",
"description": "Implements debug capabilities for client-side extensions.",

@@ -62,2 +62,3 @@ "license": "BSD-3-Clause",

"build:cjs": "tsc -p tsconfig.cjs.json",
"verify": "tsc --noEmit -p tsconfig.all.json",
"watch": "tsc --watch",

@@ -68,13 +69,15 @@ "test": "jest",

"devDependencies": {
"@types/ajv-keywords": "3.4.0",
"@types/jest-in-case": "1.0.1",
"@types/json-schema": "7.0.3",
"jest": "^24.9",
"jest-in-case": "^1.0",
"ts-jest": "^24.2"
"@types/jest-in-case": "1.0.5",
"jest": "27.3.1",
"jest-in-case": "1.0.2",
"ts-jest": "27.0.7"
},
"dependencies": {
"@atlassian/clientside-extensions-base": "^3.1.2-test9-85e70efb"
"@atlassian/clientside-extensions-base": "^4.0.0-jakarta-m001",
"tslib": "^2.2.0"
},
"gitHead": "85e70efbde55c09445ba190f07cac9938d63129f"
"engines": {
"node": ">=20.16.0"
},
"gitHead": "6cdaaa67ca52b745429b250585aae83fe244fe41"
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc