feat(smart-app): implement complete mobile app MVP

- App.tsx: full navigation (Auth stack + Main tabs with 5 screens)
- Auth: LoginScreen, RegisterScreen, ForgotPasswordScreen
- HomeScreen: dashboard with IoT metrics, weather widget, alerts, quick actions, sensors
- MapScreen: interactive map with layer toggles (6 layers)
- MarketplaceScreen: categories (6), products (5), search
- ChatScreen: AI chat with quick prompts (4), bot responses
- ProfileScreen: user info, stats, menu (9 items), logout
- AlertsScreen: alert list with severity, acknowledge
- SensorsScreen: sensor list with type filters (6 types), search
- ZonesScreen: zone cards with stats
- SettingsScreen: language picker (FR/EN/ES/DE), privacy, about
- Stores: iotStore (sensors, zones, alerts), notificationStore, uiStore + i18n
- Hooks: useSensors, useAlerts, useNotifications, useLocation
- Components: Card, Button, LoadingSpinner, ErrorBoundary, Header
- Services: iotService, notificationService (with axios API client)
- Utils: formatters (temp, AQI, noise, dates), validators (email, password, IBAN)
- Theme: colors.ts with full design system (Blue Ocean palette)
- Ditto: fixed MongoDB connection, new JWT secrets, official gateway image
This commit is contained in:
Eric FELIXINE
2026-06-01 18:00:35 -04:00
parent 08ca495bde
commit e30ae8ed09
35578 changed files with 3703534 additions and 43 deletions

View File

@@ -0,0 +1,541 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var fs = require('fs');
var util = require('util');
var path = _interopDefault(require('path'));
var sourceMap = require('source-map');
function _extends() {
_extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _createForOfIteratorHelperLoose(o, allowArrayLike) {
var it;
if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
if (it) o = it;
var i = 0;
return function () {
if (i >= o.length) return {
done: true
};
return {
done: false,
value: o[i++]
};
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
it = o[Symbol.iterator]();
return it.next.bind(it);
}
var EventsPhase;
(function (EventsPhase) {
EventsPhase["DURATION_EVENTS_BEGIN"] = "B";
EventsPhase["DURATION_EVENTS_END"] = "E";
EventsPhase["COMPLETE_EVENTS"] = "X";
EventsPhase["INSTANT_EVENTS"] = "I";
EventsPhase["COUNTER_EVENTS"] = "C";
EventsPhase["ASYNC_EVENTS_NESTABLE_START"] = "b";
EventsPhase["ASYNC_EVENTS_NESTABLE_INSTANT"] = "n";
EventsPhase["ASYNC_EVENTS_NESTABLE_END"] = "e";
EventsPhase["FLOW_EVENTS_START"] = "s";
EventsPhase["FLOW_EVENTS_STEP"] = "t";
EventsPhase["FLOW_EVENTS_END"] = "f";
EventsPhase["SAMPLE_EVENTS"] = "P";
EventsPhase["OBJECT_EVENTS_CREATED"] = "N";
EventsPhase["OBJECT_EVENTS_SNAPSHOT"] = "O";
EventsPhase["OBJECT_EVENTS_DESTROYED"] = "D";
EventsPhase["METADATA_EVENTS"] = "M";
EventsPhase["MEMORY_DUMP_EVENTS_GLOBAL"] = "V";
EventsPhase["MEMORY_DUMP_EVENTS_PROCESS"] = "v";
EventsPhase["MARK_EVENTS"] = "R";
EventsPhase["CLOCK_SYNC_EVENTS"] = "c";
EventsPhase["CONTEXT_EVENTS_ENTER"] = "(";
EventsPhase["CONTEXT_EVENTS_LEAVE"] = ")"; // Deprecated
EventsPhase["ASYNC_EVENTS_START"] = "S";
EventsPhase["ASYNC_EVENTS_STEP_INTO"] = "T";
EventsPhase["ASYNC_EVENTS_STEP_PAST"] = "p";
EventsPhase["ASYNC_EVENTS_END"] = "F";
EventsPhase["LINKED_ID_EVENTS"] = "=";
})(EventsPhase || (EventsPhase = {}));
var CpuProfilerModel = /*#__PURE__*/function () {
function CpuProfilerModel(profile) {
this._profile = profile;
this._nodesById = this._createNodeMap();
this._activeNodeArraysById = this._createActiveNodeArrays();
}
/**
* Initialization function to enable O(1) access to nodes by node ID.
* @return {Map<number, CPUProfileChunkNode}
*/
var _proto = CpuProfilerModel.prototype;
_proto._createNodeMap = function _createNodeMap() {
/** @type {Map<number, CpuProfile['nodes'][0]>} */
var map = new Map();
for (var _iterator = _createForOfIteratorHelperLoose(this._profile.nodes), _step; !(_step = _iterator()).done;) {
var node = _step.value;
map.set(node.id, node);
}
return map;
}
/**
* Initialization function to enable O(1) access to the set of active nodes in the stack by node ID.
* @return Map<number, number[]>
*/
;
_proto._createActiveNodeArrays = function _createActiveNodeArrays() {
var _this = this;
var map = new Map();
/**
* Given a nodeId, `getActiveNodes` gets all the parent nodes in reversed call order
* @param {number} id
*/
var getActiveNodes = function getActiveNodes(id) {
if (map.has(id)) return map.get(id) || [];
var node = _this._nodesById.get(id);
if (!node) throw new Error("No such node " + id);
if (node.parent) {
var array = getActiveNodes(node.parent).concat([id]);
map.set(id, array);
return array;
} else {
return [id];
}
};
for (var _iterator2 = _createForOfIteratorHelperLoose(this._profile.nodes), _step2; !(_step2 = _iterator2()).done;) {
var node = _step2.value;
map.set(node.id, getActiveNodes(node.id));
}
return map;
}
/**
* Returns all the node IDs in a stack when a specific nodeId is at the top of the stack
* (i.e. a stack's node ID and the node ID of all of its parents).
*/
;
_proto._getActiveNodeIds = function _getActiveNodeIds(nodeId) {
var activeNodeIds = this._activeNodeArraysById.get(nodeId);
if (!activeNodeIds) throw new Error("No such node ID " + nodeId);
return activeNodeIds;
}
/**
* Generates the necessary B/E-style trace events for a single transition from stack A to stack B
* at the given timestamp.
*
* Example:
*
* timestamp 1234
* previousNodeIds 1,2,3
* currentNodeIds 1,2,4
*
* yields [end 3 at ts 1234, begin 4 at ts 1234]
*
* @param {number} timestamp
* @param {Array<number>} previousNodeIds
* @param {Array<number>} currentNodeIds
* @returns {Array<DurationEvent>}
*/
;
_proto._createStartEndEventsForTransition = function _createStartEndEventsForTransition(timestamp, previousNodeIds, currentNodeIds) {
var _this2 = this;
// Start nodes are the nodes which are present only in the currentNodeIds and not in PreviousNodeIds
var startNodes = currentNodeIds.filter(function (id) {
return !previousNodeIds.includes(id);
}).map(function (id) {
return _this2._nodesById.get(id);
}); // End nodes are the nodes which are present only in the PreviousNodeIds and not in CurrentNodeIds
var endNodes = previousNodeIds.filter(function (id) {
return !currentNodeIds.includes(id);
}).map(function (id) {
return _this2._nodesById.get(id);
});
/**
* The name needs to be modified if `http://` is present as this directs us to bundle files which does not add any information for the end user
* @param name
*/
var removeLinksIfExist = function removeLinksIfExist(name) {
// If the name includes `http://`, we can filter the name
if (name.includes('http://')) {
name = name.substring(0, name.lastIndexOf('('));
}
return name || 'anonymous';
};
/**
* Create a Duration Event from CPUProfileChunkNodes.
* @param {CPUProfileChunkNode} node
* @return {DurationEvent} */
var createEvent = function createEvent(node) {
return {
ts: timestamp,
pid: _this2._profile.pid,
tid: Number(_this2._profile.tid),
ph: EventsPhase.DURATION_EVENTS_BEGIN,
name: removeLinksIfExist(node.callFrame.name),
cat: node.callFrame.category,
args: _extends({}, node.callFrame)
};
};
var startEvents = startNodes.map(createEvent).map(function (evt) {
return _extends({}, evt, {
ph: EventsPhase.DURATION_EVENTS_BEGIN
});
});
var endEvents = endNodes.map(createEvent).map(function (evt) {
return _extends({}, evt, {
ph: EventsPhase.DURATION_EVENTS_END
});
});
return [].concat(endEvents.reverse(), startEvents);
}
/**
* Creates B/E-style trace events from a CpuProfile object created by `collectProfileEvents()`
* @return {DurationEvent}
* @throws If the length of timeDeltas array or the samples array does not match with the length of samples in Hermes Profile
*/
;
_proto.createStartEndEvents = function createStartEndEvents() {
var profile = this._profile;
var length = profile.samples.length;
if (profile.timeDeltas.length !== length || profile.samples.length !== length) throw new Error("Invalid CPU profile length");
var events = [];
var timestamp = profile.startTime;
var lastActiveNodeIds = [];
for (var i = 0; i < profile.samples.length; i++) {
var nodeId = profile.samples[i];
var timeDelta = Math.max(profile.timeDeltas[i], 0);
var node = this._nodesById.get(nodeId);
if (!node) throw new Error("Missing node " + nodeId);
timestamp += timeDelta;
var activeNodeIds = this._getActiveNodeIds(nodeId);
events.push.apply(events, this._createStartEndEventsForTransition(timestamp, lastActiveNodeIds, activeNodeIds));
lastActiveNodeIds = activeNodeIds;
}
events.push.apply(events, this._createStartEndEventsForTransition(timestamp, lastActiveNodeIds, []));
return events;
}
/**
* Creates B/E-style trace events from a CpuProfile object created by `collectProfileEvents()`
* @param {CPUProfileChunk} profile
*/
;
CpuProfilerModel.createStartEndEvents = function createStartEndEvents(profile) {
var model = new CpuProfilerModel(profile);
return model.createStartEndEvents();
}
/**
* Converts the Hermes Sample into a single CpuProfileChunk object for consumption
* by `createStartEndEvents()`.
*
* @param {HermesCPUProfile} profile
* @throws Profile must have at least one sample
* @return {CPUProfileChunk}
*/
;
CpuProfilerModel.collectProfileEvents = function collectProfileEvents(profile) {
if (profile.samples.length >= 0) {
var samples = profile.samples,
stackFrames = profile.stackFrames; // Assumption: The sample will have a single process
var pid = samples[0].pid; // Assumption: Javascript is single threaded, so there should only be one thread throughout
var tid = samples[0].tid; // TODO: What role does id play in string parsing
var id = '0x1';
var startTime = Number(samples[0].ts);
var _this$constructNodes = this.constructNodes(samples, stackFrames),
nodes = _this$constructNodes.nodes,
sampleNumbers = _this$constructNodes.sampleNumbers,
timeDeltas = _this$constructNodes.timeDeltas;
return {
id: id,
pid: pid,
tid: tid,
startTime: startTime,
nodes: nodes,
samples: sampleNumbers,
timeDeltas: timeDeltas
};
} else {
throw new Error('The hermes profile has zero samples');
}
}
/**
* Constructs CPUProfileChunk Nodes and the resultant samples and time deltas to be inputted into the
* CPUProfileChunk object which will be processed to give createStartEndEvents()
*
* @param {HermesSample} samples
* @param {<string, HermesStackFrame>} stackFrames
* @return {CPUProfileChunker}
*/
;
CpuProfilerModel.constructNodes = function constructNodes(samples, stackFrames) {
samples = samples.map(function (sample) {
sample.stackFrameData = stackFrames[sample.sf];
return sample;
});
var stackFrameIds = Object.keys(stackFrames);
var profileNodes = stackFrameIds.map(function (stackFrameId) {
var stackFrame = stackFrames[stackFrameId];
return {
id: Number(stackFrameId),
callFrame: _extends({}, stackFrame, {
url: stackFrame.name
}),
parent: stackFrames[stackFrameId].parent
};
});
var returnedSamples = [];
var timeDeltas = [];
var lastTimeStamp = Number(samples[0].ts);
samples.forEach(function (sample, idx) {
returnedSamples.push(sample.sf);
if (idx === 0) {
timeDeltas.push(0);
} else {
var timeDiff = Number(sample.ts) - lastTimeStamp;
lastTimeStamp = Number(sample.ts);
timeDeltas.push(timeDiff);
}
});
return {
nodes: profileNodes,
sampleNumbers: returnedSamples,
timeDeltas: timeDeltas
};
};
return CpuProfilerModel;
}();
// A type of promise-like that resolves synchronously and supports only one observer
const _iteratorSymbol = /*#__PURE__*/ typeof Symbol !== "undefined" ? (Symbol.iterator || (Symbol.iterator = Symbol("Symbol.iterator"))) : "@@iterator";
const _asyncIteratorSymbol = /*#__PURE__*/ typeof Symbol !== "undefined" ? (Symbol.asyncIterator || (Symbol.asyncIterator = Symbol("Symbol.asyncIterator"))) : "@@asyncIterator";
// Asynchronously call a function and send errors to recovery continuation
function _catch(body, recover) {
try {
var result = body();
} catch(e) {
return recover(e);
}
if (result && result.then) {
return result.then(void 0, recover);
}
return result;
}
var readFileAsync = function readFileAsync(path) {
try {
return Promise.resolve(_catch(function () {
var readFileAsync = util.promisify(fs.readFile);
return Promise.resolve(readFileAsync(path, 'utf-8')).then(function (fileString) {
if (fileString.length === 0) {
throw new Error(path + " is an empty file");
}
var obj = JSON.parse(fileString);
return obj;
});
}, function (err) {
throw err;
}));
} catch (e) {
return Promise.reject(e);
}
};
/**
* This function is a helper to the applySourceMapsToEvents. The category allocation logic is implemented here based on the sourcemap url (if available)
* @param defaultCategory The category the event is of by default without the use of Source maps
* @param url The URL which can be parsed to interpret the new category of the event (depends on node_modules)
*/
var improveCategories = function improveCategories(defaultCategory, url) {
var obtainCategory = function obtainCategory(url) {
var dirs = url.substring(url.lastIndexOf(path.sep + "node_modules" + path.sep)).split(path.sep);
return dirs.length > 2 && dirs[1] === 'node_modules' ? dirs[2] : defaultCategory;
};
return url ? obtainCategory(url) : defaultCategory;
};
/**
* Enhances the function line, column and params information and event categories
* based on JavaScript source maps to make it easier to associate trace events with
* the application code
*
* Throws error if args not set up in ChromeEvents
* @param {SourceMap} sourceMap
* @param {DurationEvent[]} chromeEvents
* @param {string} indexBundleFileName
* @throws If `args` for events are not populated
* @returns {DurationEvent[]}
*/
var applySourceMapsToEvents = function applySourceMapsToEvents(sourceMap$1, chromeEvents, indexBundleFileName) {
try {
// SEE: Should file here be an optional parameter, so take indexBundleFileName as a parameter and use
// a default name of `index.bundle`
var rawSourceMap = {
version: Number(sourceMap$1.version),
file: indexBundleFileName || 'index.bundle',
sources: sourceMap$1.sources,
mappings: sourceMap$1.mappings,
names: sourceMap$1.names
};
return Promise.resolve(new sourceMap.SourceMapConsumer(rawSourceMap)).then(function (consumer) {
var events = chromeEvents.map(function (event) {
if (event.args) {
var sm = consumer.originalPositionFor({
line: Number(event.args.line),
column: Number(event.args.column)
});
/**
* The categories can help us better visualise the profile if we modify the categories.
* We change these categories only in the root level and not deeper inside the args, just so we have our
* original categories as well as these modified categories (as the modified categories simply help with visualisation)
*/
event.cat = improveCategories(event.cat, sm.source);
event.args = _extends({}, event.args, {
url: sm.source,
line: sm.line,
column: sm.column,
params: sm.name,
allocatedCategory: event.cat,
allocatedName: event.name
});
} else {
throw new Error("Source maps could not be derived for an event at " + event.ts + " and with stackFrame ID " + event.sf);
}
return event;
});
consumer.destroy();
return events;
});
} catch (e) {
return Promise.reject(e);
}
};
/**
* This transformer can take in the path of the profile, the source map (optional) and the bundle file name (optional)
* and return a promise which resolves to Chrome Dev Tools compatible events
* @param profilePath string
* @param sourceMapPath string
* @param bundleFileName string
* @return Promise<DurationEvent[]>
*/
var transformer = function transformer(profilePath, sourceMapPath, bundleFileName) {
try {
return Promise.resolve(readFileAsync(profilePath)).then(function (hermesProfile) {
var _exit = false;
var profileChunk = CpuProfilerModel.collectProfileEvents(hermesProfile);
var profiler = new CpuProfilerModel(profileChunk);
var chromeEvents = profiler.createStartEndEvents();
var _temp = function () {
if (sourceMapPath) {
return Promise.resolve(readFileAsync(sourceMapPath)).then(function (sourceMap) {
var events = applySourceMapsToEvents(sourceMap, chromeEvents, bundleFileName);
_exit = true;
return events;
});
}
}();
return _temp && _temp.then ? _temp.then(function (_result) {
return _exit ? _result : chromeEvents;
}) : _exit ? _temp : chromeEvents;
});
} catch (e) {
return Promise.reject(e);
}
};
exports.default = transformer;
//# sourceMappingURL=hermes-profile-transformer.cjs.development.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,535 @@
import { readFile } from 'fs';
import { promisify } from 'util';
import path from 'path';
import { SourceMapConsumer } from 'source-map';
function _extends() {
_extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _createForOfIteratorHelperLoose(o, allowArrayLike) {
var it;
if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
if (it) o = it;
var i = 0;
return function () {
if (i >= o.length) return {
done: true
};
return {
done: false,
value: o[i++]
};
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
it = o[Symbol.iterator]();
return it.next.bind(it);
}
var EventsPhase;
(function (EventsPhase) {
EventsPhase["DURATION_EVENTS_BEGIN"] = "B";
EventsPhase["DURATION_EVENTS_END"] = "E";
EventsPhase["COMPLETE_EVENTS"] = "X";
EventsPhase["INSTANT_EVENTS"] = "I";
EventsPhase["COUNTER_EVENTS"] = "C";
EventsPhase["ASYNC_EVENTS_NESTABLE_START"] = "b";
EventsPhase["ASYNC_EVENTS_NESTABLE_INSTANT"] = "n";
EventsPhase["ASYNC_EVENTS_NESTABLE_END"] = "e";
EventsPhase["FLOW_EVENTS_START"] = "s";
EventsPhase["FLOW_EVENTS_STEP"] = "t";
EventsPhase["FLOW_EVENTS_END"] = "f";
EventsPhase["SAMPLE_EVENTS"] = "P";
EventsPhase["OBJECT_EVENTS_CREATED"] = "N";
EventsPhase["OBJECT_EVENTS_SNAPSHOT"] = "O";
EventsPhase["OBJECT_EVENTS_DESTROYED"] = "D";
EventsPhase["METADATA_EVENTS"] = "M";
EventsPhase["MEMORY_DUMP_EVENTS_GLOBAL"] = "V";
EventsPhase["MEMORY_DUMP_EVENTS_PROCESS"] = "v";
EventsPhase["MARK_EVENTS"] = "R";
EventsPhase["CLOCK_SYNC_EVENTS"] = "c";
EventsPhase["CONTEXT_EVENTS_ENTER"] = "(";
EventsPhase["CONTEXT_EVENTS_LEAVE"] = ")"; // Deprecated
EventsPhase["ASYNC_EVENTS_START"] = "S";
EventsPhase["ASYNC_EVENTS_STEP_INTO"] = "T";
EventsPhase["ASYNC_EVENTS_STEP_PAST"] = "p";
EventsPhase["ASYNC_EVENTS_END"] = "F";
EventsPhase["LINKED_ID_EVENTS"] = "=";
})(EventsPhase || (EventsPhase = {}));
var CpuProfilerModel = /*#__PURE__*/function () {
function CpuProfilerModel(profile) {
this._profile = profile;
this._nodesById = this._createNodeMap();
this._activeNodeArraysById = this._createActiveNodeArrays();
}
/**
* Initialization function to enable O(1) access to nodes by node ID.
* @return {Map<number, CPUProfileChunkNode}
*/
var _proto = CpuProfilerModel.prototype;
_proto._createNodeMap = function _createNodeMap() {
/** @type {Map<number, CpuProfile['nodes'][0]>} */
var map = new Map();
for (var _iterator = _createForOfIteratorHelperLoose(this._profile.nodes), _step; !(_step = _iterator()).done;) {
var node = _step.value;
map.set(node.id, node);
}
return map;
}
/**
* Initialization function to enable O(1) access to the set of active nodes in the stack by node ID.
* @return Map<number, number[]>
*/
;
_proto._createActiveNodeArrays = function _createActiveNodeArrays() {
var _this = this;
var map = new Map();
/**
* Given a nodeId, `getActiveNodes` gets all the parent nodes in reversed call order
* @param {number} id
*/
var getActiveNodes = function getActiveNodes(id) {
if (map.has(id)) return map.get(id) || [];
var node = _this._nodesById.get(id);
if (!node) throw new Error("No such node " + id);
if (node.parent) {
var array = getActiveNodes(node.parent).concat([id]);
map.set(id, array);
return array;
} else {
return [id];
}
};
for (var _iterator2 = _createForOfIteratorHelperLoose(this._profile.nodes), _step2; !(_step2 = _iterator2()).done;) {
var node = _step2.value;
map.set(node.id, getActiveNodes(node.id));
}
return map;
}
/**
* Returns all the node IDs in a stack when a specific nodeId is at the top of the stack
* (i.e. a stack's node ID and the node ID of all of its parents).
*/
;
_proto._getActiveNodeIds = function _getActiveNodeIds(nodeId) {
var activeNodeIds = this._activeNodeArraysById.get(nodeId);
if (!activeNodeIds) throw new Error("No such node ID " + nodeId);
return activeNodeIds;
}
/**
* Generates the necessary B/E-style trace events for a single transition from stack A to stack B
* at the given timestamp.
*
* Example:
*
* timestamp 1234
* previousNodeIds 1,2,3
* currentNodeIds 1,2,4
*
* yields [end 3 at ts 1234, begin 4 at ts 1234]
*
* @param {number} timestamp
* @param {Array<number>} previousNodeIds
* @param {Array<number>} currentNodeIds
* @returns {Array<DurationEvent>}
*/
;
_proto._createStartEndEventsForTransition = function _createStartEndEventsForTransition(timestamp, previousNodeIds, currentNodeIds) {
var _this2 = this;
// Start nodes are the nodes which are present only in the currentNodeIds and not in PreviousNodeIds
var startNodes = currentNodeIds.filter(function (id) {
return !previousNodeIds.includes(id);
}).map(function (id) {
return _this2._nodesById.get(id);
}); // End nodes are the nodes which are present only in the PreviousNodeIds and not in CurrentNodeIds
var endNodes = previousNodeIds.filter(function (id) {
return !currentNodeIds.includes(id);
}).map(function (id) {
return _this2._nodesById.get(id);
});
/**
* The name needs to be modified if `http://` is present as this directs us to bundle files which does not add any information for the end user
* @param name
*/
var removeLinksIfExist = function removeLinksIfExist(name) {
// If the name includes `http://`, we can filter the name
if (name.includes('http://')) {
name = name.substring(0, name.lastIndexOf('('));
}
return name || 'anonymous';
};
/**
* Create a Duration Event from CPUProfileChunkNodes.
* @param {CPUProfileChunkNode} node
* @return {DurationEvent} */
var createEvent = function createEvent(node) {
return {
ts: timestamp,
pid: _this2._profile.pid,
tid: Number(_this2._profile.tid),
ph: EventsPhase.DURATION_EVENTS_BEGIN,
name: removeLinksIfExist(node.callFrame.name),
cat: node.callFrame.category,
args: _extends({}, node.callFrame)
};
};
var startEvents = startNodes.map(createEvent).map(function (evt) {
return _extends({}, evt, {
ph: EventsPhase.DURATION_EVENTS_BEGIN
});
});
var endEvents = endNodes.map(createEvent).map(function (evt) {
return _extends({}, evt, {
ph: EventsPhase.DURATION_EVENTS_END
});
});
return [].concat(endEvents.reverse(), startEvents);
}
/**
* Creates B/E-style trace events from a CpuProfile object created by `collectProfileEvents()`
* @return {DurationEvent}
* @throws If the length of timeDeltas array or the samples array does not match with the length of samples in Hermes Profile
*/
;
_proto.createStartEndEvents = function createStartEndEvents() {
var profile = this._profile;
var length = profile.samples.length;
if (profile.timeDeltas.length !== length || profile.samples.length !== length) throw new Error("Invalid CPU profile length");
var events = [];
var timestamp = profile.startTime;
var lastActiveNodeIds = [];
for (var i = 0; i < profile.samples.length; i++) {
var nodeId = profile.samples[i];
var timeDelta = Math.max(profile.timeDeltas[i], 0);
var node = this._nodesById.get(nodeId);
if (!node) throw new Error("Missing node " + nodeId);
timestamp += timeDelta;
var activeNodeIds = this._getActiveNodeIds(nodeId);
events.push.apply(events, this._createStartEndEventsForTransition(timestamp, lastActiveNodeIds, activeNodeIds));
lastActiveNodeIds = activeNodeIds;
}
events.push.apply(events, this._createStartEndEventsForTransition(timestamp, lastActiveNodeIds, []));
return events;
}
/**
* Creates B/E-style trace events from a CpuProfile object created by `collectProfileEvents()`
* @param {CPUProfileChunk} profile
*/
;
CpuProfilerModel.createStartEndEvents = function createStartEndEvents(profile) {
var model = new CpuProfilerModel(profile);
return model.createStartEndEvents();
}
/**
* Converts the Hermes Sample into a single CpuProfileChunk object for consumption
* by `createStartEndEvents()`.
*
* @param {HermesCPUProfile} profile
* @throws Profile must have at least one sample
* @return {CPUProfileChunk}
*/
;
CpuProfilerModel.collectProfileEvents = function collectProfileEvents(profile) {
if (profile.samples.length >= 0) {
var samples = profile.samples,
stackFrames = profile.stackFrames; // Assumption: The sample will have a single process
var pid = samples[0].pid; // Assumption: Javascript is single threaded, so there should only be one thread throughout
var tid = samples[0].tid; // TODO: What role does id play in string parsing
var id = '0x1';
var startTime = Number(samples[0].ts);
var _this$constructNodes = this.constructNodes(samples, stackFrames),
nodes = _this$constructNodes.nodes,
sampleNumbers = _this$constructNodes.sampleNumbers,
timeDeltas = _this$constructNodes.timeDeltas;
return {
id: id,
pid: pid,
tid: tid,
startTime: startTime,
nodes: nodes,
samples: sampleNumbers,
timeDeltas: timeDeltas
};
} else {
throw new Error('The hermes profile has zero samples');
}
}
/**
* Constructs CPUProfileChunk Nodes and the resultant samples and time deltas to be inputted into the
* CPUProfileChunk object which will be processed to give createStartEndEvents()
*
* @param {HermesSample} samples
* @param {<string, HermesStackFrame>} stackFrames
* @return {CPUProfileChunker}
*/
;
CpuProfilerModel.constructNodes = function constructNodes(samples, stackFrames) {
samples = samples.map(function (sample) {
sample.stackFrameData = stackFrames[sample.sf];
return sample;
});
var stackFrameIds = Object.keys(stackFrames);
var profileNodes = stackFrameIds.map(function (stackFrameId) {
var stackFrame = stackFrames[stackFrameId];
return {
id: Number(stackFrameId),
callFrame: _extends({}, stackFrame, {
url: stackFrame.name
}),
parent: stackFrames[stackFrameId].parent
};
});
var returnedSamples = [];
var timeDeltas = [];
var lastTimeStamp = Number(samples[0].ts);
samples.forEach(function (sample, idx) {
returnedSamples.push(sample.sf);
if (idx === 0) {
timeDeltas.push(0);
} else {
var timeDiff = Number(sample.ts) - lastTimeStamp;
lastTimeStamp = Number(sample.ts);
timeDeltas.push(timeDiff);
}
});
return {
nodes: profileNodes,
sampleNumbers: returnedSamples,
timeDeltas: timeDeltas
};
};
return CpuProfilerModel;
}();
// A type of promise-like that resolves synchronously and supports only one observer
const _iteratorSymbol = /*#__PURE__*/ typeof Symbol !== "undefined" ? (Symbol.iterator || (Symbol.iterator = Symbol("Symbol.iterator"))) : "@@iterator";
const _asyncIteratorSymbol = /*#__PURE__*/ typeof Symbol !== "undefined" ? (Symbol.asyncIterator || (Symbol.asyncIterator = Symbol("Symbol.asyncIterator"))) : "@@asyncIterator";
// Asynchronously call a function and send errors to recovery continuation
function _catch(body, recover) {
try {
var result = body();
} catch(e) {
return recover(e);
}
if (result && result.then) {
return result.then(void 0, recover);
}
return result;
}
var readFileAsync = function readFileAsync(path) {
try {
return Promise.resolve(_catch(function () {
var readFileAsync = promisify(readFile);
return Promise.resolve(readFileAsync(path, 'utf-8')).then(function (fileString) {
if (fileString.length === 0) {
throw new Error(path + " is an empty file");
}
var obj = JSON.parse(fileString);
return obj;
});
}, function (err) {
throw err;
}));
} catch (e) {
return Promise.reject(e);
}
};
/**
* This function is a helper to the applySourceMapsToEvents. The category allocation logic is implemented here based on the sourcemap url (if available)
* @param defaultCategory The category the event is of by default without the use of Source maps
* @param url The URL which can be parsed to interpret the new category of the event (depends on node_modules)
*/
var improveCategories = function improveCategories(defaultCategory, url) {
var obtainCategory = function obtainCategory(url) {
var dirs = url.substring(url.lastIndexOf(path.sep + "node_modules" + path.sep)).split(path.sep);
return dirs.length > 2 && dirs[1] === 'node_modules' ? dirs[2] : defaultCategory;
};
return url ? obtainCategory(url) : defaultCategory;
};
/**
* Enhances the function line, column and params information and event categories
* based on JavaScript source maps to make it easier to associate trace events with
* the application code
*
* Throws error if args not set up in ChromeEvents
* @param {SourceMap} sourceMap
* @param {DurationEvent[]} chromeEvents
* @param {string} indexBundleFileName
* @throws If `args` for events are not populated
* @returns {DurationEvent[]}
*/
var applySourceMapsToEvents = function applySourceMapsToEvents(sourceMap, chromeEvents, indexBundleFileName) {
try {
// SEE: Should file here be an optional parameter, so take indexBundleFileName as a parameter and use
// a default name of `index.bundle`
var rawSourceMap = {
version: Number(sourceMap.version),
file: indexBundleFileName || 'index.bundle',
sources: sourceMap.sources,
mappings: sourceMap.mappings,
names: sourceMap.names
};
return Promise.resolve(new SourceMapConsumer(rawSourceMap)).then(function (consumer) {
var events = chromeEvents.map(function (event) {
if (event.args) {
var sm = consumer.originalPositionFor({
line: Number(event.args.line),
column: Number(event.args.column)
});
/**
* The categories can help us better visualise the profile if we modify the categories.
* We change these categories only in the root level and not deeper inside the args, just so we have our
* original categories as well as these modified categories (as the modified categories simply help with visualisation)
*/
event.cat = improveCategories(event.cat, sm.source);
event.args = _extends({}, event.args, {
url: sm.source,
line: sm.line,
column: sm.column,
params: sm.name,
allocatedCategory: event.cat,
allocatedName: event.name
});
} else {
throw new Error("Source maps could not be derived for an event at " + event.ts + " and with stackFrame ID " + event.sf);
}
return event;
});
consumer.destroy();
return events;
});
} catch (e) {
return Promise.reject(e);
}
};
/**
* This transformer can take in the path of the profile, the source map (optional) and the bundle file name (optional)
* and return a promise which resolves to Chrome Dev Tools compatible events
* @param profilePath string
* @param sourceMapPath string
* @param bundleFileName string
* @return Promise<DurationEvent[]>
*/
var transformer = function transformer(profilePath, sourceMapPath, bundleFileName) {
try {
return Promise.resolve(readFileAsync(profilePath)).then(function (hermesProfile) {
var _exit = false;
var profileChunk = CpuProfilerModel.collectProfileEvents(hermesProfile);
var profiler = new CpuProfilerModel(profileChunk);
var chromeEvents = profiler.createStartEndEvents();
var _temp = function () {
if (sourceMapPath) {
return Promise.resolve(readFileAsync(sourceMapPath)).then(function (sourceMap) {
var events = applySourceMapsToEvents(sourceMap, chromeEvents, bundleFileName);
_exit = true;
return events;
});
}
}();
return _temp && _temp.then ? _temp.then(function (_result) {
return _exit ? _result : chromeEvents;
}) : _exit ? _temp : chromeEvents;
});
} catch (e) {
return Promise.reject(e);
}
};
export default transformer;
//# sourceMappingURL=hermes-profile-transformer.esm.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,12 @@
import { DurationEvent } from './types/EventInterfaces';
/**
* This transformer can take in the path of the profile, the source map (optional) and the bundle file name (optional)
* and return a promise which resolves to Chrome Dev Tools compatible events
* @param profilePath string
* @param sourceMapPath string
* @param bundleFileName string
* @return Promise<DurationEvent[]>
*/
declare const transformer: (profilePath: string, sourceMapPath: string | undefined, bundleFileName: string | undefined) => Promise<DurationEvent[]>;
export default transformer;
export { SourceMap } from './types/SourceMap';

View File

@@ -0,0 +1,12 @@
import { DurationEvent } from './types/EventInterfaces';
/**
* This transformer can take in the path of the profile, the source map (optional) and the bundle file name (optional)
* and return a promise which resolves to Chrome Dev Tools compatible events
* @param profilePath string
* @param sourceMapPath string
* @param bundleFileName string
* @return Promise<DurationEvent[]>
*/
declare const transformer: (profilePath: string, sourceMapPath: string | undefined, bundleFileName: string | undefined) => Promise<DurationEvent[]>;
export default transformer;
export { SourceMap } from './types/SourceMap';

View File

@@ -0,0 +1,8 @@
'use strict'
if (process.env.NODE_ENV === 'production') {
module.exports = require('./hermes-profile-transformer.cjs.production.min.js')
} else {
module.exports = require('./hermes-profile-transformer.cjs.development.js')
}

View File

@@ -0,0 +1,16 @@
import { DurationEvent } from '../types/EventInterfaces';
import { SourceMap } from '../types/SourceMap';
/**
* Enhances the function line, column and params information and event categories
* based on JavaScript source maps to make it easier to associate trace events with
* the application code
*
* Throws error if args not set up in ChromeEvents
* @param {SourceMap} sourceMap
* @param {DurationEvent[]} chromeEvents
* @param {string} indexBundleFileName
* @throws If `args` for events are not populated
* @returns {DurationEvent[]}
*/
declare const applySourceMapsToEvents: (sourceMap: SourceMap, chromeEvents: DurationEvent[], indexBundleFileName: string | undefined) => Promise<DurationEvent[]>;
export default applySourceMapsToEvents;

View File

@@ -0,0 +1,107 @@
/**
* @license Copyright 2020 The Lighthouse Authors. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*
* MODIFICATION NOTICE:
* This file is derived from `https://github.com/GoogleChrome/lighthouse/blob/0422daa9b1b8528dd8436860b153134bd0f959f1/lighthouse-core/lib/tracehouse/cpu-profile-model.js`
* and has been modified by Saphal Patro (email: saphal1998@gmail.com)
* The following changes have been made to the original file:
* 1. Converted code to Typescript and defined necessary types
* 2. Wrote a method @see collectProfileEvents to convert the Hermes Samples to Profile Chunks supported by Lighthouse Parser
* 3. Modified @see constructNodes to work with the Hermes Samples and StackFrames
*/
/**
* @fileoverview
*
* This model converts the `Profile` and `ProfileChunk` mega trace events from the `disabled-by-default-v8.cpu_profiler`
* category into B/E-style trace events that main-thread-tasks.js already knows how to parse into a task tree.
*
* The CPU profiler measures where time is being spent by sampling the stack (See https://www.jetbrains.com/help/profiler/Profiling_Guidelines__Choosing_the_Right_Profiling_Mode.html
* for a generic description of the differences between tracing and sampling).
*
* A `Profile` event is a record of the stack that was being executed at different sample points in time.
* It has a structure like this:
*
* nodes: [function A, function B, function C]
* samples: [node with id 2, node with id 1, ...]
* timeDeltas: [4125μs since last sample, 121μs since last sample, ...]
*
* Helpful prior art:
* @see https://cs.chromium.org/chromium/src/third_party/devtools-frontend/src/front_end/sdk/CPUProfileDataModel.js?sq=package:chromium&g=0&l=42
* @see https://github.com/v8/v8/blob/99ca333b0efba3236954b823101315aefeac51ab/tools/profile.js
* @see https://github.com/jlfwong/speedscope/blob/9ed1eb192cb7e9dac43a5f25bd101af169dc654a/src/import/chrome.ts#L200
*/
import { CPUProfileChunk, CPUProfileChunkNode, CPUProfileChunker } from '../types/CPUProfile';
import { DurationEvent } from '../types/EventInterfaces';
import { HermesCPUProfile, HermesSample, HermesStackFrame } from '../types/HermesProfile';
export declare class CpuProfilerModel {
_profile: CPUProfileChunk;
_nodesById: Map<number, CPUProfileChunkNode>;
_activeNodeArraysById: Map<number, number[]>;
constructor(profile: CPUProfileChunk);
/**
* Initialization function to enable O(1) access to nodes by node ID.
* @return {Map<number, CPUProfileChunkNode}
*/
_createNodeMap(): Map<number, CPUProfileChunkNode>;
/**
* Initialization function to enable O(1) access to the set of active nodes in the stack by node ID.
* @return Map<number, number[]>
*/
_createActiveNodeArrays(): Map<number, number[]>;
/**
* Returns all the node IDs in a stack when a specific nodeId is at the top of the stack
* (i.e. a stack's node ID and the node ID of all of its parents).
*/
_getActiveNodeIds(nodeId: number): number[];
/**
* Generates the necessary B/E-style trace events for a single transition from stack A to stack B
* at the given timestamp.
*
* Example:
*
* timestamp 1234
* previousNodeIds 1,2,3
* currentNodeIds 1,2,4
*
* yields [end 3 at ts 1234, begin 4 at ts 1234]
*
* @param {number} timestamp
* @param {Array<number>} previousNodeIds
* @param {Array<number>} currentNodeIds
* @returns {Array<DurationEvent>}
*/
_createStartEndEventsForTransition(timestamp: number, previousNodeIds: number[], currentNodeIds: number[]): DurationEvent[];
/**
* Creates B/E-style trace events from a CpuProfile object created by `collectProfileEvents()`
* @return {DurationEvent}
* @throws If the length of timeDeltas array or the samples array does not match with the length of samples in Hermes Profile
*/
createStartEndEvents(): DurationEvent[];
/**
* Creates B/E-style trace events from a CpuProfile object created by `collectProfileEvents()`
* @param {CPUProfileChunk} profile
*/
static createStartEndEvents(profile: CPUProfileChunk): DurationEvent[];
/**
* Converts the Hermes Sample into a single CpuProfileChunk object for consumption
* by `createStartEndEvents()`.
*
* @param {HermesCPUProfile} profile
* @throws Profile must have at least one sample
* @return {CPUProfileChunk}
*/
static collectProfileEvents(profile: HermesCPUProfile): CPUProfileChunk;
/**
* Constructs CPUProfileChunk Nodes and the resultant samples and time deltas to be inputted into the
* CPUProfileChunk object which will be processed to give createStartEndEvents()
*
* @param {HermesSample} samples
* @param {<string, HermesStackFrame>} stackFrames
* @return {CPUProfileChunker}
*/
static constructNodes(samples: HermesSample[], stackFrames: {
[key in string]: HermesStackFrame;
}): CPUProfileChunker;
}

View File

@@ -0,0 +1,39 @@
/**
* The CPUProfileChunk is the intermediate file that Lighthouse can interpret and
* hence subsequently convert to events supported by Chrome Dev Tools
*/
export interface CPUProfileChunk {
id: string;
pid: number;
tid: string;
startTime: number;
nodes: CPUProfileChunkNode[];
samples: number[];
timeDeltas: number[];
}
/**
* The CPUProfileChunkNode is an individual element of the nodes[] property in the CPUProfileChunk
* @see CPUProfileChunk
*/
export interface CPUProfileChunkNode {
id: number;
callFrame: {
line: string;
column: string;
funcLine: string;
funcColumn: string;
name: string;
url?: string;
category: string;
};
parent?: number;
}
/**
* The process of conversion of Hermes Profile Events to Lighthouse supported events are primarily focussed
* around generating the correct values of the properties in CPUProfileChunker.
*/
export declare type CPUProfileChunker = {
nodes: CPUProfileChunkNode[];
sampleNumbers: number[];
timeDeltas: number[];
};

View File

@@ -0,0 +1,143 @@
import { EventsPhase } from './Phases';
export interface SharedEventProperties {
/**
* name of the event
*/
name?: string;
/**
* event category
*/
cat?: string;
/**
* tracing clock timestamp
*/
ts?: number;
/**
* process ID
*/
pid?: number;
/**
* thread ID
*/
tid?: number;
/**
* event type (phase)
*/
ph: EventsPhase;
/**
* id for a stackFrame object
*/
sf?: number;
/**
* thread clock timestamp
*/
tts?: number;
/**
* a fixed color name
*/
cname?: string;
/**
* event arguments
*/
args?: {
[key in string]: any;
};
}
interface DurationEventBegin extends SharedEventProperties {
ph: EventsPhase.DURATION_EVENTS_BEGIN;
}
interface DurationEventEnd extends SharedEventProperties {
ph: EventsPhase.DURATION_EVENTS_END;
}
export declare type DurationEvent = DurationEventBegin | DurationEventEnd;
export interface CompleteEvent extends SharedEventProperties {
ph: EventsPhase.COMPLETE_EVENTS;
dur: number;
}
export interface MetadataEvent extends SharedEventProperties {
ph: EventsPhase.METADATA_EVENTS;
}
export interface SampleEvent extends SharedEventProperties {
ph: EventsPhase.SAMPLE_EVENTS;
}
interface ObjectEventCreated extends SharedEventProperties {
ph: EventsPhase.OBJECT_EVENTS_CREATED;
scope?: string;
}
interface ObjectEventSnapshot extends SharedEventProperties {
ph: EventsPhase.OBJECT_EVENTS_SNAPSHOT;
scope?: string;
}
interface ObjectEventDestroyed extends SharedEventProperties {
ph: EventsPhase.OBJECT_EVENTS_DESTROYED;
scope?: string;
}
export declare type ObjectEvent = ObjectEventCreated | ObjectEventSnapshot | ObjectEventDestroyed;
export interface ClockSyncEvent extends SharedEventProperties {
ph: EventsPhase.CLOCK_SYNC_EVENTS;
args: {
sync_id: string;
issue_ts?: number;
};
}
interface ContextEventEnter extends SharedEventProperties {
ph: EventsPhase.CONTEXT_EVENTS_ENTER;
}
interface ContextEventLeave extends SharedEventProperties {
ph: EventsPhase.CONTEXT_EVENTS_LEAVE;
}
export declare type ContextEvent = ContextEventEnter | ContextEventLeave;
interface AsyncEventStart extends SharedEventProperties {
ph: EventsPhase.ASYNC_EVENTS_NESTABLE_START;
id: number;
scope?: string;
}
interface AsyncEventInstant extends SharedEventProperties {
ph: EventsPhase.ASYNC_EVENTS_NESTABLE_INSTANT;
id: number;
scope?: string;
}
interface AsyncEventEnd extends SharedEventProperties {
ph: EventsPhase.ASYNC_EVENTS_NESTABLE_END;
id: number;
scope?: string;
}
export declare type AsyncEvent = AsyncEventStart | AsyncEventInstant | AsyncEventEnd;
export interface InstantEvent extends SharedEventProperties {
ph: EventsPhase.INSTANT_EVENTS;
s: string;
}
export interface CounterEvent extends SharedEventProperties {
ph: EventsPhase.COUNTER_EVENTS;
}
interface FlowEventStart extends SharedEventProperties {
ph: EventsPhase.FLOW_EVENTS_START;
}
interface FlowEventStep extends SharedEventProperties {
ph: EventsPhase.FLOW_EVENTS_STEP;
}
interface FlowEventEnd extends SharedEventProperties {
ph: EventsPhase.FLOW_EVENTS_END;
}
export declare type FlowEvent = FlowEventStart | FlowEventStep | FlowEventEnd;
interface MemoryDumpGlobal extends SharedEventProperties {
ph: EventsPhase.MEMORY_DUMP_EVENTS_GLOBAL;
id: string;
}
interface MemoryDumpProcess extends SharedEventProperties {
ph: EventsPhase.MEMORY_DUMP_EVENTS_PROCESS;
id: string;
}
export declare type MemoryDumpEvent = MemoryDumpGlobal | MemoryDumpProcess;
export interface MarkEvent extends SharedEventProperties {
ph: EventsPhase.MARK_EVENTS;
}
export interface LinkedIDEvent extends SharedEventProperties {
ph: EventsPhase.LINKED_ID_EVENTS;
id: number;
args: {
linked_id: number;
};
}
export declare type Event = DurationEvent | CompleteEvent | MetadataEvent | SampleEvent | ObjectEvent | ClockSyncEvent | ContextEvent | AsyncEvent | InstantEvent | CounterEvent | FlowEvent | MemoryDumpEvent | MarkEvent | LinkedIDEvent;
export {};

View File

@@ -0,0 +1,42 @@
import { SharedEventProperties } from './EventInterfaces';
/**
* Each item in the stackFrames object of the hermes profile
*/
export interface HermesStackFrame {
line: string;
column: string;
funcLine: string;
funcColumn: string;
name: string;
category: string;
/**
* A parent function may or may not exist
*/
parent?: number;
}
/**
* Each item in the samples array of the hermes profile
*/
export interface HermesSample {
cpu: string;
name: string;
ts: string;
pid: number;
tid: string;
weight: string;
/**
* Will refer to an element in the stackFrames object of the Hermes Profile
*/
sf: number;
stackFrameData?: HermesStackFrame;
}
/**
* Hermes Profile Interface
*/
export interface HermesCPUProfile {
traceEvents: SharedEventProperties[];
samples: HermesSample[];
stackFrames: {
[key in string]: HermesStackFrame;
};
}

View File

@@ -0,0 +1,29 @@
export declare enum EventsPhase {
DURATION_EVENTS_BEGIN = "B",
DURATION_EVENTS_END = "E",
COMPLETE_EVENTS = "X",
INSTANT_EVENTS = "I",
COUNTER_EVENTS = "C",
ASYNC_EVENTS_NESTABLE_START = "b",
ASYNC_EVENTS_NESTABLE_INSTANT = "n",
ASYNC_EVENTS_NESTABLE_END = "e",
FLOW_EVENTS_START = "s",
FLOW_EVENTS_STEP = "t",
FLOW_EVENTS_END = "f",
SAMPLE_EVENTS = "P",
OBJECT_EVENTS_CREATED = "N",
OBJECT_EVENTS_SNAPSHOT = "O",
OBJECT_EVENTS_DESTROYED = "D",
METADATA_EVENTS = "M",
MEMORY_DUMP_EVENTS_GLOBAL = "V",
MEMORY_DUMP_EVENTS_PROCESS = "v",
MARK_EVENTS = "R",
CLOCK_SYNC_EVENTS = "c",
CONTEXT_EVENTS_ENTER = "(",
CONTEXT_EVENTS_LEAVE = ")",
ASYNC_EVENTS_START = "S",
ASYNC_EVENTS_STEP_INTO = "T",
ASYNC_EVENTS_STEP_PAST = "p",
ASYNC_EVENTS_END = "F",
LINKED_ID_EVENTS = "="
}

View File

@@ -0,0 +1,11 @@
export interface SourceMap {
version: string;
sources: string[];
sourceContent: string[];
x_facebook_sources: {
names: string[];
mappings: string;
}[] | null;
names: string[];
mappings: string;
}

View File

@@ -0,0 +1 @@
export declare const readFileAsync: (path: string) => Promise<any>;