Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

piral-debug-utils

Package Overview
Dependencies
Maintainers
1
Versions
676
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

piral-debug-utils - npm Package Compare versions

Comparing version 1.0.0-pre.2096 to 1.0.0

debug.d.ts

9

lib/debug.d.ts

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

import { PiletApiCreator, PiletDependencyGetter, PiletLoader, PiletRequester } from 'piral-base';
export interface DebuggerOptions {
createApi: PiletApiCreator;
getDependencies: PiletDependencyGetter;
loadPilet: PiletLoader;
requestPilets: PiletRequester;
context?: any;
}
import { DebuggerOptions } from './types';
export declare function installPiralDebug(options: DebuggerOptions): void;
"use strict";
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.installPiralDebug = void 0;
const DebugTracker_1 = require("./DebugTracker");
const VisualizationWrapper_1 = require("./VisualizationWrapper");
const ExtensionCatalogue_1 = require("./ExtensionCatalogue");
const decycle_1 = require("./decycle");
const state_1 = require("./state");
function installPiralDebug(options) {
const { context } = options, pilets = __rest(options, ["context"]);
// the DEBUG_PIRAL env should contain the Piral CLI compatibility version
window['dbg:piral'] = {
debug: 'v0',
const { getGlobalState, getExtensions, getDependencies, getRoutes, getPilets, fireEvent, integrate, removePilet, updatePilet, addPilet, navigate, customSettings = {}, defaultSettings = {}, } = options;
const events = [];
const legacyBrowser = !new Error().stack;
const initialSettings = (0, state_1.getInitialSettings)(defaultSettings);
const excludedRoutes = [initialSettings.cataloguePath];
const selfSource = 'piral-debug-api';
const debugApiVersion = 'v1';
let setValue = state_1.initialSetter;
(0, state_1.setInitialState)(initialSettings);
const settings = Object.assign(Object.assign({}, customSettings), { viewState: {
value: initialSettings.viewState,
type: 'boolean',
label: 'State container logging',
onChange(value) {
setValue(state_1.settingsKeys.viewState, value ? 'on' : 'off');
},
}, loadPilets: {
value: initialSettings.loadPilets,
type: 'boolean',
label: 'Load available pilets',
onChange(value) {
setValue(state_1.settingsKeys.loadPilets, value ? 'on' : 'off');
},
}, hardRefresh: {
value: initialSettings.hardRefresh,
type: 'boolean',
label: 'Full refresh on change',
onChange(value) {
setValue(state_1.settingsKeys.hardRefresh, value ? 'on' : 'off');
},
}, viewOrigins: {
value: initialSettings.viewOrigins,
type: 'boolean',
label: 'Visualize component origins',
onChange(value, prev) {
setValue(state_1.settingsKeys.viewOrigins, value ? 'on' : 'off');
if (prev !== value) {
updateVisualize(value);
}
},
}, extensionCatalogue: {
value: initialSettings.extensionCatalogue,
type: 'boolean',
label: 'Enable extension catalogue',
onChange(value) {
setValue(state_1.settingsKeys.extensionCatalogue, value ? 'on' : 'off');
},
}, clearConsole: {
value: initialSettings.clearConsole,
type: 'boolean',
label: 'Clear console during HMR',
onChange(value) {
setValue(state_1.settingsKeys.clearConsole, value ? 'on' : 'off');
},
}, persistSettings: {
value: initialSettings.persistSettings,
type: 'boolean',
label: 'Persist settings',
onChange(value) {
setValue = value ? (0, state_1.enablePersistance)() : (0, state_1.disablePersistance)();
},
} });
const sendMessage = (content) => {
window.postMessage({
content,
source: selfSource,
version: debugApiVersion,
}, '*');
};
const getSettings = () => {
return Object.keys(settings).reduce((obj, key) => {
const setting = settings[key];
if (setting &&
typeof setting === 'object' &&
typeof setting.label === 'string' &&
typeof setting.type === 'string' &&
['boolean', 'string', 'number'].includes(typeof setting.value)) {
obj[key] = {
label: setting.label,
value: setting.value,
type: setting.type,
};
}
return obj;
}, {});
};
const updateSettings = (values) => {
Object.keys(values).forEach((key) => {
const setting = settings[key];
switch (setting.type) {
case 'boolean': {
const prev = setting.value;
const value = values[key];
setting.value = value;
setting.onChange(value, prev);
break;
}
case 'number': {
const prev = setting.value;
const value = values[key];
setting.value = value;
setting.onChange(value, prev);
break;
}
case 'string': {
const prev = setting.value;
const value = values[key];
setting.value = value;
setting.onChange(value, prev);
break;
}
}
});
sendMessage({
settings: getSettings(),
type: 'settings',
});
};
const togglePilet = (name) => {
const pilet = getPilets().find((m) => m.name === name);
if (!pilet) {
// nothing to do, obviously invalid call
}
else if (pilet.disabled) {
if (pilet.original) {
// everything is fine, let's use the cached version
updatePilet(pilet.original);
}
else {
// something fishy is going on - let's just try to activate the same pilet
updatePilet(Object.assign(Object.assign({}, pilet), { disabled: false }));
}
}
else {
updatePilet({ name, disabled: true, original: pilet });
}
};
const toggleVisualize = () => {
(0, state_1.setState)((s) => (Object.assign(Object.assign({}, s), { visualize: Object.assign(Object.assign({}, s.visualize), { force: !s.visualize.force }) })));
};
const updateVisualize = (active) => {
(0, state_1.setState)((s) => (Object.assign(Object.assign({}, s), { visualize: Object.assign(Object.assign({}, s.visualize), { active }) })));
};
const goToRoute = (path, state) => {
(0, state_1.setState)((s) => (Object.assign(Object.assign({}, s), { route: {
path,
state,
} })));
};
const eventDispatcher = document.body.dispatchEvent;
const systemResolve = System.constructor.prototype.resolve;
const depMap = {};
const subDeps = {};
const findAncestor = (parent) => {
while (subDeps[parent]) {
parent = subDeps[parent];
}
return parent;
};
System.constructor.prototype.resolve = function (...args) {
const [url, parent] = args;
const result = systemResolve.call(this, ...args);
if (!parent) {
return result;
}
const ancestor = findAncestor(parent);
if (url.startsWith('./')) {
subDeps[result] = ancestor;
}
else {
const deps = depMap[ancestor] || {};
deps[url] = result;
depMap[ancestor] = deps;
}
return result;
};
const debugApi = {
debug: debugApiVersion,
instance: {

@@ -24,3 +192,2 @@ name: process.env.BUILD_PCKG_NAME,

dependencies: process.env.SHARED_DEPENDENCIES,
context,
},

@@ -32,6 +199,208 @@ build: {

},
pilets,
};
const details = {
name: debugApi.instance.name,
version: debugApi.instance.version,
kind: debugApiVersion,
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
capabilities: [
'events',
'container',
'routes',
'pilets',
'settings',
'extensions',
'dependencies',
'dependency-map',
],
};
const start = () => {
const container = (0, decycle_1.decycle)(getGlobalState());
const routes = getRoutes().filter((r) => !excludedRoutes.includes(r));
const extensions = getExtensions();
const settings = getSettings();
const dependencies = getDependencies();
const pilets = getPilets().map((pilet) => ({
name: pilet.name,
version: pilet.version,
disabled: pilet.disabled,
}));
sendMessage(Object.assign(Object.assign({ type: 'available' }, details), { state: {
routes,
pilets,
container,
settings,
events,
extensions,
dependencies,
} }));
};
const check = () => {
sendMessage(Object.assign({ type: 'info' }, details));
};
const getDependencyMap = () => {
const dependencyMap = {};
const addDeps = (pilet, dependencies) => {
const deps = dependencyMap[pilet] || [];
for (const depName of Object.keys(dependencies)) {
if (!deps.some((m) => m.demanded === depName)) {
deps.push({
demanded: depName,
resolved: dependencies[depName],
});
}
}
dependencyMap[pilet] = deps;
};
const pilets = getPilets()
.map((pilet) => ({
name: pilet.name,
link: pilet.link,
base: pilet.base,
}))
.filter((m) => m.link);
Object.keys(depMap).forEach((url) => {
const dependencies = depMap[url];
const pilet = pilets.find((p) => p.link === url);
if (pilet) {
addDeps(pilet.name, dependencies);
}
else if (!pilet) {
const parent = pilets.find((p) => url.startsWith(p.base));
if (parent) {
addDeps(parent.name, dependencies);
}
}
});
sendMessage({
type: 'dependency-map',
dependencyMap,
});
};
document.body.dispatchEvent = function (ev) {
if (ev.type.startsWith('piral-')) {
events.unshift({
id: events.length.toString(),
name: ev.type.replace('piral-', ''),
args: (0, decycle_1.decycle)(ev.detail.arg),
time: Date.now(),
});
sendMessage({
events,
type: 'events',
});
}
return eventDispatcher.call(this, ev);
};
window.addEventListener('storage', (event) => {
if (!legacyBrowser && event.storageArea === sessionStorage) {
// potentially unknowingly updated settings
updateSettings({
viewState: sessionStorage.getItem(state_1.settingsKeys.viewState) !== 'off',
loadPilets: sessionStorage.getItem(state_1.settingsKeys.loadPilets) === 'on',
hardRefresh: sessionStorage.getItem(state_1.settingsKeys.hardRefresh) === 'on',
viewOrigins: sessionStorage.getItem(state_1.settingsKeys.viewOrigins) === 'on',
extensionCatalogue: sessionStorage.getItem(state_1.settingsKeys.extensionCatalogue) !== 'off',
clearConsole: sessionStorage.getItem(state_1.settingsKeys.clearConsole) === 'on',
});
}
});
window.addEventListener('message', (event) => {
const { source, version, content } = event.data;
if (source !== selfSource && version === debugApiVersion) {
switch (content.type) {
case 'init':
return start();
case 'check-piral':
return check();
case 'get-dependency-map':
return getDependencyMap();
case 'update-settings':
return updateSettings(content.settings);
case 'append-pilet':
return addPilet(content.meta);
case 'remove-pilet':
return removePilet(content.name);
case 'toggle-pilet':
return togglePilet(content.name);
case 'emit-event':
return fireEvent(content.name, content.args);
case 'goto-route':
return goToRoute(content.route, content.state);
case 'visualize-all':
return toggleVisualize();
}
}
});
(0, state_1.setNavigate)(navigate);
integrate({
components: {
Debug: DebugTracker_1.DebugTracker,
},
routes: {
[initialSettings.cataloguePath]: ExtensionCatalogue_1.ExtensionCatalogue,
},
wrappers: {
'*': VisualizationWrapper_1.VisualizationWrapper,
},
onChange(previous, current, changed) {
if (changed.state) {
if (settings.viewState.value) {
if (!legacyBrowser) {
// Chrome, Firefox, ... (full capability)
const err = new Error();
const lastLine = err.stack.split('\n')[6];
if (lastLine) {
const action = lastLine.replace(/^\s+at\s+(Atom\.|Object\.)?/, '');
console.group(`%c Piral State Change %c ${new Date().toLocaleTimeString()}`, 'color: gray; font-weight: lighter;', 'color: black; font-weight: bold;');
console.log('%c Previous', `color: #9E9E9E; font-weight: bold`, previous);
console.log('%c Action', `color: #03A9F4; font-weight: bold`, action);
console.log('%c Next', `color: #4CAF50; font-weight: bold`, current);
console.groupEnd();
}
}
else {
// IE 11, ... (does not know colors etc.)
console.log('Changed state', previous, current);
}
}
sendMessage({
type: 'container',
container: (0, decycle_1.decycle)(getGlobalState()),
});
}
if (changed.pilets) {
sendMessage({
type: 'pilets',
pilets: getPilets().map((pilet) => ({
name: pilet.name,
version: pilet.version,
disabled: !!pilet.disabled,
})),
});
}
if (changed.pages) {
sendMessage({
type: 'routes',
routes: getRoutes().filter((r) => !excludedRoutes.includes(r)),
});
}
if (changed.extensions) {
sendMessage({
type: 'extensions',
extensions: getExtensions(),
});
}
if (changed.dependencies) {
sendMessage({
type: 'dependencies',
dependencies: getDependencies(),
});
}
},
});
window['dbg:piral'] = debugApi;
start();
}
exports.installPiralDebug = installPiralDebug;
//# sourceMappingURL=debug.js.map

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

import { Pilet, PiletApiCreator, PiletLoader, PiletRequester } from 'piral-base';
export interface EmulatorConnectorOptions {
createApi: PiletApiCreator;
loadPilet: PiletLoader;
inject?(pilet: Pilet): void;
piletApiFallback?: string;
}
export declare function withEmulatorPilets(requestPilets: PiletRequester, options: EmulatorConnectorOptions): PiletRequester;
import type { PiletRequester } from 'piral-base';
import type { EmulatorConnectorOptions } from './types';
export declare function installPiletEmulator(requestPilets: PiletRequester, options: EmulatorConnectorOptions): void;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.withEmulatorPilets = void 0;
const piral_base_1 = require("piral-base");
function withEmulatorPilets(requestPilets, options) {
const { loadPilet, createApi, inject, piletApiFallback = '/$pilet-api' } = options;
// check if pilets should be loaded
const loadPilets = sessionStorage.getItem('dbg:load-pilets') === 'on';
const noPilets = () => Promise.resolve([]);
const requester = loadPilets ? requestPilets : noPilets;
return () => {
exports.installPiletEmulator = void 0;
const routeRefresh_1 = require("./routeRefresh");
function installPiletEmulator(requestPilets, options) {
const { addPilet, removePilet, integrate, piletApiFallback = '/$pilet-api' } = options;
integrate(() => {
// check if pilets should be loaded
const loadPilets = sessionStorage.getItem('dbg:load-pilets') === 'on';
const noPilets = () => Promise.resolve([]);
const requester = loadPilets ? requestPilets : noPilets;
const promise = requester();

@@ -21,2 +21,4 @@ // the window['dbg:pilet-api'] should point to an API address used as a proxy, fall back to '/$pilet-api' if unavailable

const ws = new WebSocket(updateTarget);
const timeoutCache = {};
const timeout = 150;
const appendix = fetch(initialTarget)

@@ -30,13 +32,24 @@ .then((res) => res.json())

const meta = JSON.parse(data);
loadPilet(meta).then((pilet) => {
try {
if (piral_base_1.isfunc(inject)) {
inject(pilet);
const name = meta.name;
// like a debounce; only one change of the current pilet should be actively processed
clearTimeout(timeoutCache[name]);
// some bundlers may have fired before writing to the disk
// so we give them a bit of time before actually loading the pilet
timeoutCache[name] = setTimeout(() => {
// we should make sure to only refresh the page / router if pilets have been loaded
const unfreeze = (0, routeRefresh_1.freezeRouteRefresh)();
// tear down pilet
removePilet(meta.name)
.then(() => {
const clearConsole = sessionStorage.getItem('dbg:clear-console') === 'on';
if (clearConsole) {
console.clear();
}
piral_base_1.setupPilet(pilet, createApi);
}
catch (error) {
console.error(error);
}
});
console.log('Updating pilet %c%s ...', 'color: green; background: white; font-weight: bold', name);
})
// load and evaluate pilet
.then(() => addPilet(meta))
// then disable route cache, should be zero again and lead to route refresh
.then(unfreeze, unfreeze);
}, timeout);
}

@@ -52,6 +65,10 @@ else {

})
.then((pilets) => appendix.then((debugPilets) => [...pilets, ...debugPilets]));
};
.then((pilets) => appendix.then((debugPilets) => {
const debugPiletNames = debugPilets.map((m) => m.name);
const feedPilets = pilets.filter((m) => !debugPiletNames.includes(m.name));
return [...feedPilets, ...debugPilets];
}));
});
}
exports.withEmulatorPilets = withEmulatorPilets;
exports.installPiletEmulator = installPiletEmulator;
//# sourceMappingURL=emulator.js.map
export * from './debug';
export * from './emulator';
export * from './types';
export * from './useDebugRouteFilter';
export * from './web';
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
__exportStar(require("./debug"), exports);
__exportStar(require("./emulator"), exports);
const tslib_1 = require("tslib");
tslib_1.__exportStar(require("./debug"), exports);
tslib_1.__exportStar(require("./emulator"), exports);
tslib_1.__exportStar(require("./types"), exports);
tslib_1.__exportStar(require("./useDebugRouteFilter"), exports);
tslib_1.__exportStar(require("./web"), exports);
//# sourceMappingURL=index.js.map
{
"name": "piral-debug-utils",
"version": "1.0.0-pre.2096",
"version": "1.0.0",
"description": "Utilities for debugging Piral instances.",

@@ -17,7 +17,39 @@ "keywords": [

"license": "MIT",
"module": "esm/index.js",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
"exports": {
".": {
"import": "./esm/index.js",
"require": "./lib/index.js"
},
"./esm/*": {
"import": "./esm/*"
},
"./lib/*": {
"require": "./lib/*"
},
"./debug": {
"import": "./esm/debug.js",
"require": "./lib/debug.js",
"types": "./lib/debug.d.ts"
},
"./emulator": {
"import": "./esm/emulator.js",
"require": "./lib/emulator.js",
"types": "./lib/emulator.d.ts"
},
"./_/*": {
"import": "./esm/*.js",
"require": "./lib/*.js"
},
"./package.json": "./package.json"
},
"sideEffects": false,
"files": [
"esm",
"lib",
"src"
"src",
"debug.d.ts",
"emulator.d.ts"
],

@@ -32,3 +64,6 @@ "repository": {

"scripts": {
"build": "tsc",
"cleanup": "rimraf esm lib",
"build": "yarn build:commonjs && yarn build:esnext",
"build:commonjs": "tsc --project tsconfig.json --outDir lib --module commonjs",
"build:esnext": "tsc --project tsconfig.json --outDir esm --module esnext",
"typedoc": "typedoc --json ../../../docs/types/piral-debug-utils.json src --exclude \"src/**/*.test.*\"",

@@ -38,8 +73,9 @@ "test": "echo \"Error: run tests from root\" && exit 1"

"devDependencies": {
"piral-base": "^1.0.0-pre.2096"
"piral-base": "^1.0.0"
},
"peerDependencies": {
"piral-base": "0.12.x || 1.x"
"react": ">=16.8.0",
"react-router": ">=5.0.0"
},
"gitHead": "9ac3626cc85b5937a50e039debd32c2697b49242"
"gitHead": "67d9a2920bd5231baf10bc87ae8985666b18fa3a"
}

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

[![Piral Logo](https://github.com/smapiot/piral/raw/master/docs/assets/logo.png)](https://piral.io)
[![Piral Logo](https://github.com/smapiot/piral/raw/main/docs/assets/logo.png)](https://piral.io)
# [Piral Debug Utils](https://piral.io) &middot; [![GitHub License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/smapiot/piral/blob/master/LICENSE) [![npm version](https://img.shields.io/npm/v/piral-debug-utils.svg?style=flat)](https://www.npmjs.com/package/piral-debug-utils) [![tested with jest](https://img.shields.io/badge/tested_with-jest-99424f.svg)](https://jestjs.io) [![Gitter Chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/piral-io/community)
# [Piral Debug Utils](https://piral.io) &middot; [![GitHub License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/smapiot/piral/blob/main/LICENSE) [![npm version](https://img.shields.io/npm/v/piral-debug-utils.svg?style=flat)](https://www.npmjs.com/package/piral-debug-utils) [![tested with jest](https://img.shields.io/badge/tested_with-jest-99424f.svg)](https://jestjs.io) [![Gitter Chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/piral-io/community)

@@ -11,3 +11,3 @@ This is a utility library that can be used for debugging Piral instances.

This should only be installed as a dependency (`dependencies`), but usually guarded to be active (or included in the bundle) only for development / emulation purposes (i.e., when developing pilets).
This should only be installed as a dependency (`dependencies`), but usually guarded to be active (or included in the bundle) only for development/emulation purposes (i.e., when developing pilets).

@@ -36,11 +36,17 @@ If you'd love to use yarn:

// if we build the debug version of piral (debug and emulator build)
if (process.env.DEBUG_PIRAL !== undefined) {
if (process.env.DEBUG_PIRAL) {
const { installPiralDebug } = require('piral-debug-utils');
installPiralDebug({
context,
createApi,
getDependencies,
loadPilet,
requestPilets,
fireEvent,
getGlobalState,
getPilets,
getExtensions,
getRoutes,
integrate,
addPilet,
removePilet,
updatePilet,
navigate,
});

@@ -50,3 +56,3 @@ }

We can use the `withEmulatorPilets` function to modify (or not) the provided `PiletRequester`, which will be handed over later to the `createInstance` options or `piral-base` directly.
We can use the `installPiletEmulator` function to modify (or not) the provided `PiletRequester`, which will be handed over later to the `createInstance` options or `piral-base` directly.

@@ -56,10 +62,10 @@ Usually, we'd guard it to make it only accessible under emulator conditions.

```js
// if we want to change `fetchPilets` (for an emulator) of the LoadPiletsOptions
if (process.env.DEBUG_PILET !== undefined) {
const { withEmulatorPilets } = require('piral-debug-utils');
// if we want to change `requestPilets` (for an emulator) of the LoadPiletsOptions
if (process.env.DEBUG_PILET) {
const { installPiletEmulator } = require('piral-debug-utils');
fetchPilets = withEmulatorPilets(fetchPilets, {
inject: context.injectPilet,
createApi,
loadPilet,
installPiletEmulator(requestPilets, {
addPilet,
removePilet,
integrate,
});

@@ -66,0 +72,0 @@ }

@@ -1,17 +0,260 @@

import { PiletApiCreator, PiletDependencyGetter, PiletLoader, PiletRequester } from 'piral-base';
import { DebugTracker } from './DebugTracker';
import { VisualizationWrapper } from './VisualizationWrapper';
import { ExtensionCatalogue } from './ExtensionCatalogue';
import { decycle } from './decycle';
import { DebugCustomSetting, DebuggerOptions } from './types';
import {
setState,
getInitialSettings,
setInitialState,
setNavigate,
initialSetter,
enablePersistance,
disablePersistance,
settingsKeys,
} from './state';
export interface DebuggerOptions {
createApi: PiletApiCreator;
getDependencies: PiletDependencyGetter;
loadPilet: PiletLoader;
requestPilets: PiletRequester;
context?: any;
}
export function installPiralDebug(options: DebuggerOptions) {
const { context, ...pilets } = options;
const {
getGlobalState,
getExtensions,
getDependencies,
getRoutes,
getPilets,
fireEvent,
integrate,
removePilet,
updatePilet,
addPilet,
navigate,
customSettings = {},
defaultSettings = {},
} = options;
const events = [];
const legacyBrowser = !new Error().stack;
const initialSettings = getInitialSettings(defaultSettings);
const excludedRoutes = [initialSettings.cataloguePath];
const selfSource = 'piral-debug-api';
const debugApiVersion = 'v1';
let setValue = initialSetter;
// the DEBUG_PIRAL env should contain the Piral CLI compatibility version
window['dbg:piral'] = {
debug: 'v0',
setInitialState(initialSettings);
const settings: Record<string, DebugCustomSetting> = {
...customSettings,
viewState: {
value: initialSettings.viewState,
type: 'boolean',
label: 'State container logging',
onChange(value) {
setValue(settingsKeys.viewState, value ? 'on' : 'off');
},
},
loadPilets: {
value: initialSettings.loadPilets,
type: 'boolean',
label: 'Load available pilets',
onChange(value) {
setValue(settingsKeys.loadPilets, value ? 'on' : 'off');
},
},
hardRefresh: {
value: initialSettings.hardRefresh,
type: 'boolean',
label: 'Full refresh on change',
onChange(value) {
setValue(settingsKeys.hardRefresh, value ? 'on' : 'off');
},
},
viewOrigins: {
value: initialSettings.viewOrigins,
type: 'boolean',
label: 'Visualize component origins',
onChange(value, prev) {
setValue(settingsKeys.viewOrigins, value ? 'on' : 'off');
if (prev !== value) {
updateVisualize(value);
}
},
},
extensionCatalogue: {
value: initialSettings.extensionCatalogue,
type: 'boolean',
label: 'Enable extension catalogue',
onChange(value) {
setValue(settingsKeys.extensionCatalogue, value ? 'on' : 'off');
},
},
clearConsole: {
value: initialSettings.clearConsole,
type: 'boolean',
label: 'Clear console during HMR',
onChange(value) {
setValue(settingsKeys.clearConsole, value ? 'on' : 'off');
},
},
persistSettings: {
value: initialSettings.persistSettings,
type: 'boolean',
label: 'Persist settings',
onChange(value) {
setValue = value ? enablePersistance() : disablePersistance();
},
},
};
const sendMessage = (content: any) => {
window.postMessage(
{
content,
source: selfSource,
version: debugApiVersion,
},
'*',
);
};
const getSettings = () => {
return Object.keys(settings).reduce((obj, key) => {
const setting = settings[key];
if (
setting &&
typeof setting === 'object' &&
typeof setting.label === 'string' &&
typeof setting.type === 'string' &&
['boolean', 'string', 'number'].includes(typeof setting.value)
) {
obj[key] = {
label: setting.label,
value: setting.value,
type: setting.type,
};
}
return obj;
}, {});
};
const updateSettings = (values: Record<string, any>) => {
Object.keys(values).forEach((key) => {
const setting = settings[key];
switch (setting.type) {
case 'boolean': {
const prev = setting.value;
const value = values[key];
setting.value = value;
setting.onChange(value, prev);
break;
}
case 'number': {
const prev = setting.value;
const value = values[key];
setting.value = value;
setting.onChange(value, prev);
break;
}
case 'string': {
const prev = setting.value;
const value = values[key];
setting.value = value;
setting.onChange(value, prev);
break;
}
}
});
sendMessage({
settings: getSettings(),
type: 'settings',
});
};
const togglePilet = (name: string) => {
const pilet: any = getPilets().find((m) => m.name === name);
if (!pilet) {
// nothing to do, obviously invalid call
} else if (pilet.disabled) {
if (pilet.original) {
// everything is fine, let's use the cached version
updatePilet(pilet.original);
} else {
// something fishy is going on - let's just try to activate the same pilet
updatePilet({ ...pilet, disabled: false });
}
} else {
updatePilet({ name, disabled: true, original: pilet });
}
};
const toggleVisualize = () => {
setState((s) => ({
...s,
visualize: {
...s.visualize,
force: !s.visualize.force,
},
}));
};
const updateVisualize = (active: boolean) => {
setState((s) => ({
...s,
visualize: {
...s.visualize,
active,
},
}));
};
const goToRoute = (path: string, state?: any) => {
setState((s) => ({
...s,
route: {
path,
state,
},
}));
};
const eventDispatcher = document.body.dispatchEvent;
const systemResolve = System.constructor.prototype.resolve;
const depMap: Record<string, Record<string, string>> = {};
const subDeps: Record<string, string> = {};
const findAncestor = (parent: string) => {
while (subDeps[parent]) {
parent = subDeps[parent];
}
return parent;
};
System.constructor.prototype.resolve = function (...args) {
const [url, parent] = args;
const result = systemResolve.call(this, ...args);
if (!parent) {
return result;
}
const ancestor = findAncestor(parent);
if (url.startsWith('./')) {
subDeps[result] = ancestor;
} else {
const deps = depMap[ancestor] || {};
deps[url] = result;
depMap[ancestor] = deps;
}
return result;
};
const debugApi = {
debug: debugApiVersion,
instance: {

@@ -21,3 +264,2 @@ name: process.env.BUILD_PCKG_NAME,

dependencies: process.env.SHARED_DEPENDENCIES,
context,
},

@@ -29,4 +271,241 @@ build: {

},
pilets,
};
const details = {
name: debugApi.instance.name,
version: debugApi.instance.version,
kind: debugApiVersion,
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
capabilities: [
'events',
'container',
'routes',
'pilets',
'settings',
'extensions',
'dependencies',
'dependency-map',
],
};
const start = () => {
const container = decycle(getGlobalState());
const routes = getRoutes().filter((r) => !excludedRoutes.includes(r));
const extensions = getExtensions();
const settings = getSettings();
const dependencies = getDependencies();
const pilets = getPilets().map((pilet: any) => ({
name: pilet.name,
version: pilet.version,
disabled: pilet.disabled,
}));
sendMessage({
type: 'available',
...details,
state: {
routes,
pilets,
container,
settings,
events,
extensions,
dependencies,
},
});
};
const check = () => {
sendMessage({
type: 'info',
...details,
});
};
const getDependencyMap = () => {
const dependencyMap: Record<string, Array<{ demanded: string; resolved: string }>> = {};
const addDeps = (pilet: string, dependencies: Record<string, string>) => {
const deps = dependencyMap[pilet] || [];
for (const depName of Object.keys(dependencies)) {
if (!deps.some((m) => m.demanded === depName)) {
deps.push({
demanded: depName,
resolved: dependencies[depName],
});
}
}
dependencyMap[pilet] = deps;
};
const pilets = getPilets()
.map((pilet: any) => ({
name: pilet.name,
link: pilet.link,
base: pilet.base,
}))
.filter((m) => m.link);
Object.keys(depMap).forEach((url) => {
const dependencies = depMap[url];
const pilet = pilets.find((p) => p.link === url);
if (pilet) {
addDeps(pilet.name, dependencies);
} else if (!pilet) {
const parent = pilets.find((p) => url.startsWith(p.base));
if (parent) {
addDeps(parent.name, dependencies);
}
}
});
sendMessage({
type: 'dependency-map',
dependencyMap,
});
};
document.body.dispatchEvent = function (ev: CustomEvent) {
if (ev.type.startsWith('piral-')) {
events.unshift({
id: events.length.toString(),
name: ev.type.replace('piral-', ''),
args: decycle(ev.detail.arg),
time: Date.now(),
});
sendMessage({
events,
type: 'events',
});
}
return eventDispatcher.call(this, ev);
};
window.addEventListener('storage', (event) => {
if (!legacyBrowser && event.storageArea === sessionStorage) {
// potentially unknowingly updated settings
updateSettings({
viewState: sessionStorage.getItem(settingsKeys.viewState) !== 'off',
loadPilets: sessionStorage.getItem(settingsKeys.loadPilets) === 'on',
hardRefresh: sessionStorage.getItem(settingsKeys.hardRefresh) === 'on',
viewOrigins: sessionStorage.getItem(settingsKeys.viewOrigins) === 'on',
extensionCatalogue: sessionStorage.getItem(settingsKeys.extensionCatalogue) !== 'off',
clearConsole: sessionStorage.getItem(settingsKeys.clearConsole) === 'on',
});
}
});
window.addEventListener('message', (event) => {
const { source, version, content } = event.data;
if (source !== selfSource && version === debugApiVersion) {
switch (content.type) {
case 'init':
return start();
case 'check-piral':
return check();
case 'get-dependency-map':
return getDependencyMap();
case 'update-settings':
return updateSettings(content.settings);
case 'append-pilet':
return addPilet(content.meta);
case 'remove-pilet':
return removePilet(content.name);
case 'toggle-pilet':
return togglePilet(content.name);
case 'emit-event':
return fireEvent(content.name, content.args);
case 'goto-route':
return goToRoute(content.route, content.state);
case 'visualize-all':
return toggleVisualize();
}
}
});
setNavigate(navigate);
integrate({
components: {
Debug: DebugTracker,
},
routes: {
[initialSettings.cataloguePath]: ExtensionCatalogue,
},
wrappers: {
'*': VisualizationWrapper,
},
onChange(previous, current, changed) {
if (changed.state) {
if (settings.viewState.value) {
if (!legacyBrowser) {
// Chrome, Firefox, ... (full capability)
const err = new Error();
const lastLine = err.stack.split('\n')[6];
if (lastLine) {
const action = lastLine.replace(/^\s+at\s+(Atom\.|Object\.)?/, '');
console.group(
`%c Piral State Change %c ${new Date().toLocaleTimeString()}`,
'color: gray; font-weight: lighter;',
'color: black; font-weight: bold;',
);
console.log('%c Previous', `color: #9E9E9E; font-weight: bold`, previous);
console.log('%c Action', `color: #03A9F4; font-weight: bold`, action);
console.log('%c Next', `color: #4CAF50; font-weight: bold`, current);
console.groupEnd();
}
} else {
// IE 11, ... (does not know colors etc.)
console.log('Changed state', previous, current);
}
}
sendMessage({
type: 'container',
container: decycle(getGlobalState()),
});
}
if (changed.pilets) {
sendMessage({
type: 'pilets',
pilets: getPilets().map((pilet: any) => ({
name: pilet.name,
version: pilet.version,
disabled: !!pilet.disabled,
})),
});
}
if (changed.pages) {
sendMessage({
type: 'routes',
routes: getRoutes().filter((r) => !excludedRoutes.includes(r)),
});
}
if (changed.extensions) {
sendMessage({
type: 'extensions',
extensions: getExtensions(),
});
}
if (changed.dependencies) {
sendMessage({
type: 'dependencies',
dependencies: getDependencies(),
});
}
},
});
window['dbg:piral'] = debugApi;
start();
}

@@ -1,18 +0,13 @@

import { isfunc, Pilet, PiletApiCreator, PiletLoader, PiletRequester, setupPilet } from 'piral-base';
import { freezeRouteRefresh } from './routeRefresh';
import type { PiletRequester } from 'piral-base';
import type { EmulatorConnectorOptions } from './types';
export interface EmulatorConnectorOptions {
createApi: PiletApiCreator;
loadPilet: PiletLoader;
inject?(pilet: Pilet): void;
piletApiFallback?: string;
}
export function installPiletEmulator(requestPilets: PiletRequester, options: EmulatorConnectorOptions) {
const { addPilet, removePilet, integrate, piletApiFallback = '/$pilet-api' } = options;
export function withEmulatorPilets(requestPilets: PiletRequester, options: EmulatorConnectorOptions): PiletRequester {
const { loadPilet, createApi, inject, piletApiFallback = '/$pilet-api' } = options;
// check if pilets should be loaded
const loadPilets = sessionStorage.getItem('dbg:load-pilets') === 'on';
const noPilets: PiletRequester = () => Promise.resolve([]);
const requester = loadPilets ? requestPilets : noPilets;
return () => {
integrate(() => {
// check if pilets should be loaded
const loadPilets = sessionStorage.getItem('dbg:load-pilets') === 'on';
const noPilets: PiletRequester = () => Promise.resolve([]);
const requester = loadPilets ? requestPilets : noPilets;
const promise = requester();

@@ -29,2 +24,4 @@

const ws = new WebSocket(updateTarget);
const timeoutCache = {};
const timeout = 150;

@@ -41,13 +38,29 @@ const appendix = fetch(initialTarget)

const meta = JSON.parse(data);
loadPilet(meta).then((pilet) => {
try {
if (isfunc(inject)) {
inject(pilet);
}
const name = meta.name;
setupPilet(pilet, createApi);
} catch (error) {
console.error(error);
}
});
// like a debounce; only one change of the current pilet should be actively processed
clearTimeout(timeoutCache[name]);
// some bundlers may have fired before writing to the disk
// so we give them a bit of time before actually loading the pilet
timeoutCache[name] = setTimeout(() => {
// we should make sure to only refresh the page / router if pilets have been loaded
const unfreeze = freezeRouteRefresh();
// tear down pilet
removePilet(meta.name)
.then(() => {
const clearConsole = sessionStorage.getItem('dbg:clear-console') === 'on';
if (clearConsole) {
console.clear();
}
console.log('Updating pilet %c%s ...', 'color: green; background: white; font-weight: bold', name);
})
// load and evaluate pilet
.then(() => addPilet(meta))
// then disable route cache, should be zero again and lead to route refresh
.then(unfreeze, unfreeze);
}, timeout);
} else {

@@ -63,4 +76,10 @@ location.reload();

})
.then((pilets) => appendix.then((debugPilets) => [...pilets, ...debugPilets]));
};
.then((pilets) =>
appendix.then((debugPilets) => {
const debugPiletNames = debugPilets.map((m) => m.name);
const feedPilets = pilets.filter((m) => !debugPiletNames.includes(m.name));
return [...feedPilets, ...debugPilets];
}),
);
});
}
export * from './debug';
export * from './emulator';
export * from './types';
export * from './useDebugRouteFilter';
export * from './web';

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