@atlassian/clientside-extensions-debug
Advanced tools
Comparing version 3.1.2-test9-85e70efb to 4.0.0-jakarta-m001
"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
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
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
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
4
72
1732
0
135341
2
4
+ Addedtslib@^2.2.0
+ Added@atlassian/clientside-extensions-base@4.0.0-m01-8612d31-m4igvz6q(transitive)
+ Addedtslib@2.8.1(transitive)
- Removed@atlassian/clientside-extensions-base@3.1.2-test9-85e70efb(transitive)
Updated@atlassian/clientside-extensions-base@^4.0.0-jakarta-m001