Merge branch 'dev' into dynamic-css-support
This commit is contained in:
commit
90a77f739f
72 changed files with 636 additions and 473 deletions
|
|
@ -80,12 +80,7 @@ def get_traces_group(project_id, payload):
|
|||
payloads = {}
|
||||
all_exists = True
|
||||
for i, u in enumerate(frames):
|
||||
print("===============================")
|
||||
print(u["absPath"])
|
||||
print("converted to:")
|
||||
key = __get_key(project_id, u["absPath"]) # use filename instead?
|
||||
print(key)
|
||||
print("===============================")
|
||||
if key not in payloads:
|
||||
file_exists = s3.exists(config('sourcemaps_bucket'), key)
|
||||
all_exists = all_exists and file_exists
|
||||
|
|
|
|||
|
|
@ -9,13 +9,21 @@ def get_original_trace(key, positions):
|
|||
"positions": positions,
|
||||
"padding": 5,
|
||||
"bucket": config('sourcemaps_bucket'),
|
||||
"S3_HOST": config('S3_HOST'),
|
||||
"S3_KEY": config('S3_KEY'),
|
||||
"S3_SECRET": config('S3_SECRET'),
|
||||
"region": config('sessions_region')
|
||||
"S3_KEY": config('S3_KEY', default=config('AWS_ACCESS_KEY_ID')),
|
||||
"S3_SECRET": config('S3_SECRET', default=config('AWS_SECRET_ACCESS_KEY')),
|
||||
"region": config('sessions_region', default=config('AWS_DEFAULT_REGION'))
|
||||
}
|
||||
r = requests.post(config("sourcemaps_reader"), json=payload)
|
||||
if r.status_code != 200:
|
||||
if len(config('S3_HOST', default="")) > 0:
|
||||
payload["S3_HOST"] = config('S3_HOST')
|
||||
try:
|
||||
r = requests.post(config("sourcemaps_reader"), json=payload,
|
||||
timeout=config("sourcemapTimeout", cast=int, default=5))
|
||||
if r.status_code != 200:
|
||||
return {}
|
||||
return r.json()
|
||||
except requests.exceptions.Timeout:
|
||||
print("Timeout getting sourcemap")
|
||||
return {}
|
||||
except Exception as e:
|
||||
print("issue getting sourcemap")
|
||||
return {}
|
||||
|
||||
return r.json()
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ func main() {
|
|||
pgDur := time.Now().Sub(start).Milliseconds()
|
||||
|
||||
start = time.Now()
|
||||
if err := saver.CommitStats(); err != nil {
|
||||
if err := saver.CommitStats(consumer.HasFirstPartition()); err != nil {
|
||||
log.Printf("Error on stats commit: %v", err)
|
||||
}
|
||||
chDur := time.Now().Sub(start).Milliseconds()
|
||||
|
|
|
|||
|
|
@ -22,6 +22,6 @@ func (si *Saver) InsertStats(session *Session, msg Message) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (si *Saver) CommitStats() error {
|
||||
func (si *Saver) CommitStats(optimize bool) error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ type Consumer interface {
|
|||
Commit() error
|
||||
CommitBack(gap int64) error
|
||||
Close()
|
||||
HasFirstPartition() bool
|
||||
}
|
||||
|
||||
type Producer interface {
|
||||
|
|
|
|||
|
|
@ -161,3 +161,7 @@ func (c *Consumer) CommitBack(gap int64) error {
|
|||
func (c *Consumer) Close() {
|
||||
// noop
|
||||
}
|
||||
|
||||
func (c *Consumer) HasFirstPartition() bool {
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,3 +42,6 @@ if config("EXP_FUNNELS", cast=bool, default=False):
|
|||
from . import significance_exp as significance
|
||||
else:
|
||||
from . import significance as significance
|
||||
|
||||
if config("EXP_RESOURCES", cast=bool, default=False):
|
||||
print(">>> Using experimental resources for session-replay")
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from chalicelib.utils import helper
|
||||
from chalicelib.utils import helper, exp_ch_helper
|
||||
from chalicelib.utils import ch_client
|
||||
from chalicelib.utils.TimeUTC import TimeUTC
|
||||
from decouple import config
|
||||
|
|
@ -9,14 +9,26 @@ def get_by_session_id(session_id, project_id, start_ts, duration):
|
|||
if duration is None or (type(duration) != 'int' and type(duration) != 'float') or duration < 0:
|
||||
duration = 0
|
||||
delta = config("events_ts_delta", cast=int, default=60 * 60) * 1000
|
||||
ch_query = """\
|
||||
SELECT
|
||||
datetime,url,type,duration,ttfb,header_size,encoded_body_size,decoded_body_size,success,coalesce(status,if(success, 200, status)) AS status
|
||||
FROM resources
|
||||
WHERE session_id = toUInt64(%(session_id)s)
|
||||
AND project_id=%(project_id)s
|
||||
AND datetime >= toDateTime(%(res_start_ts)s / 1000)
|
||||
AND datetime <= toDateTime(%(res_end_ts)s / 1000);"""
|
||||
if config("EXP_RESOURCES", cast=bool, default=False):
|
||||
ch_query = f"""SELECT
|
||||
datetime,url,type,duration,ttfb,header_size,
|
||||
encoded_body_size,decoded_body_size,success,
|
||||
if(success, 200, 400) AS status
|
||||
FROM {exp_ch_helper.get_main_resources_table(start_ts)}
|
||||
WHERE session_id = toUInt64(%(session_id)s)
|
||||
AND project_id = toUInt16(%(project_id)s)
|
||||
AND datetime >= toDateTime(%(res_start_ts)s / 1000)
|
||||
AND datetime <= toDateTime(%(res_end_ts)s / 1000);"""
|
||||
else:
|
||||
ch_query = """SELECT
|
||||
datetime,url,type,duration,ttfb,header_size,
|
||||
encoded_body_size,decoded_body_size,success,
|
||||
coalesce(status,if(success, 200, status)) AS status
|
||||
FROM resources
|
||||
WHERE session_id = toUInt64(%(session_id)s)
|
||||
AND project_id = toUInt64(%(project_id)s)
|
||||
AND datetime >= toDateTime(%(res_start_ts)s / 1000)
|
||||
AND datetime <= toDateTime(%(res_end_ts)s / 1000);"""
|
||||
params = {"session_id": session_id, "project_id": project_id, "start_ts": start_ts, "duration": duration,
|
||||
"res_start_ts": start_ts - delta, "res_end_ts": start_ts + duration + delta, }
|
||||
rows = ch.execute(query=ch_query, params=params)
|
||||
|
|
|
|||
|
|
@ -66,4 +66,5 @@ EXP_ERRORS_SEARCH=false
|
|||
EXP_METRICS=false
|
||||
EXP_7D_MV=false
|
||||
EXP_ALERTS=false
|
||||
EXP_FUNNELS=false
|
||||
EXP_FUNNELS=false
|
||||
EXP_RESOURCES=true
|
||||
|
|
@ -43,7 +43,10 @@ func (si *Saver) InsertStats(session *types.Session, msg messages.Message) error
|
|||
return nil
|
||||
}
|
||||
|
||||
func (si *Saver) CommitStats() error {
|
||||
func (si *Saver) CommitStats(optimize bool) error {
|
||||
if !optimize {
|
||||
return si.ch.Commit()
|
||||
}
|
||||
select {
|
||||
case <-finalizeTicker:
|
||||
if err := si.ch.FinaliseSessionsTable(); err != nil {
|
||||
|
|
|
|||
|
|
@ -194,3 +194,16 @@ func (consumer *Consumer) Close() {
|
|||
log.Printf("Kafka consumer close error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (consumer *Consumer) HasFirstPartition() bool {
|
||||
assigned, err := consumer.c.Assignment()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for _, p := range assigned {
|
||||
if p.Partition == 1 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ if (process.env.redis === "true") {
|
|||
socket = require("./servers/websocket");
|
||||
}
|
||||
|
||||
const HOST = '0.0.0.0';
|
||||
const HOST = process.env.LISTEN_HOST || '0.0.0.0';
|
||||
const PORT = process.env.LISTEN_PORT || 9001;
|
||||
|
||||
let debug = process.env.debug === "1" || false;
|
||||
|
|
|
|||
|
|
@ -283,6 +283,7 @@ module.exports = {
|
|||
start: (server, prefix) => {
|
||||
createSocketIOServer(server, prefix);
|
||||
io.on('connection', async (socket) => {
|
||||
socket.on(EVENTS_DEFINITION.listen.ERROR, err => errorHandler(EVENTS_DEFINITION.listen.ERROR, err));
|
||||
debug && console.log(`WS started:${socket.id}, Query:${JSON.stringify(socket.handshake.query)}`);
|
||||
socket._connectedAt = new Date();
|
||||
socket.peerId = socket.handshake.query.peerId;
|
||||
|
|
@ -351,7 +352,6 @@ module.exports = {
|
|||
|
||||
socket.on(EVENTS_DEFINITION.listen.CONNECT_ERROR, err => errorHandler(EVENTS_DEFINITION.listen.CONNECT_ERROR, err));
|
||||
socket.on(EVENTS_DEFINITION.listen.CONNECT_FAILED, err => errorHandler(EVENTS_DEFINITION.listen.CONNECT_FAILED, err));
|
||||
socket.on(EVENTS_DEFINITION.listen.ERROR, err => errorHandler(EVENTS_DEFINITION.listen.ERROR, err));
|
||||
|
||||
socket.onAny(async (eventName, ...args) => {
|
||||
if (Object.values(EVENTS_DEFINITION.listen).indexOf(eventName) >= 0) {
|
||||
|
|
|
|||
|
|
@ -261,6 +261,7 @@ module.exports = {
|
|||
start: (server, prefix) => {
|
||||
createSocketIOServer(server, prefix);
|
||||
io.on('connection', async (socket) => {
|
||||
socket.on(EVENTS_DEFINITION.listen.ERROR, err => errorHandler(EVENTS_DEFINITION.listen.ERROR, err));
|
||||
debug && console.log(`WS started:${socket.id}, Query:${JSON.stringify(socket.handshake.query)}`);
|
||||
socket._connectedAt = new Date();
|
||||
socket.peerId = socket.handshake.query.peerId;
|
||||
|
|
@ -327,7 +328,6 @@ module.exports = {
|
|||
|
||||
socket.on(EVENTS_DEFINITION.listen.CONNECT_ERROR, err => errorHandler(EVENTS_DEFINITION.listen.CONNECT_ERROR, err));
|
||||
socket.on(EVENTS_DEFINITION.listen.CONNECT_FAILED, err => errorHandler(EVENTS_DEFINITION.listen.CONNECT_FAILED, err));
|
||||
socket.on(EVENTS_DEFINITION.listen.ERROR, err => errorHandler(EVENTS_DEFINITION.listen.ERROR, err));
|
||||
|
||||
socket.onAny(async (eventName, ...args) => {
|
||||
if (Object.values(EVENTS_DEFINITION.listen).indexOf(eventName) >= 0) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||
import { connect } from 'react-redux';
|
||||
import { Input, Form, Button, Checkbox, Loader } from 'UI';
|
||||
import SiteDropdown from 'Shared/SiteDropdown';
|
||||
import { save, init, edit, remove, fetchList } from 'Duck/integrations/actions';
|
||||
import { save, init, edit, remove } from 'Duck/integrations/actions';
|
||||
import { fetchIntegrationList } from 'Duck/integrations/integrations';
|
||||
|
||||
@connect(
|
||||
|
|
@ -21,7 +21,7 @@ import { fetchIntegrationList } from 'Duck/integrations/integrations';
|
|||
init,
|
||||
edit,
|
||||
remove,
|
||||
fetchList,
|
||||
// fetchList,
|
||||
fetchIntegrationList,
|
||||
}
|
||||
)
|
||||
|
|
@ -33,6 +33,16 @@ export default class IntegrationForm extends React.PureComponent {
|
|||
// this.init(currentSiteId);
|
||||
}
|
||||
|
||||
fetchList = () => {
|
||||
alert('calling...');
|
||||
const { siteId, initialSiteId } = this.props;
|
||||
if (!siteId) {
|
||||
this.props.fetchIntegrationList(initialSiteId);
|
||||
} else {
|
||||
this.props.fetchIntegrationList(siteId);
|
||||
}
|
||||
}
|
||||
|
||||
write = ({ target: { value, name: key, type, checked } }) => {
|
||||
if (type === 'checkbox') this.props.edit(this.props.name, { [key]: checked });
|
||||
else this.props.edit(this.props.name, { [key]: value });
|
||||
|
|
@ -57,6 +67,7 @@ export default class IntegrationForm extends React.PureComponent {
|
|||
// const { currentSiteId } = this.state;
|
||||
this.props.save(customPath || name, !ignoreProject ? this.props.siteId : null, config).then(() => {
|
||||
// this.props.fetchList(name);
|
||||
this.fetchList();
|
||||
this.props.onClose();
|
||||
if (isExists) return;
|
||||
});
|
||||
|
|
@ -67,7 +78,7 @@ export default class IntegrationForm extends React.PureComponent {
|
|||
this.props.remove(name, !ignoreProject ? config.projectId : null).then(
|
||||
function () {
|
||||
this.props.onClose();
|
||||
this.props.fetchList(name);
|
||||
this.fetchList();
|
||||
}.bind(this)
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,112 +7,126 @@ import { CLIENT_TABS, client as clientRoute } from 'App/routes';
|
|||
import { withRouter } from 'react-router-dom';
|
||||
|
||||
function PreferencesMenu({ account, activeTab, history, isEnterprise }) {
|
||||
const isAdmin = account.admin || account.superAdmin;
|
||||
const setTab = (tab) => {
|
||||
history.push(clientRoute(tab));
|
||||
};
|
||||
const isAdmin = account.admin || account.superAdmin;
|
||||
const setTab = (tab) => {
|
||||
history.push(clientRoute(tab));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={cn(stl.wrapper, 'h-full overflow-y-auto pb-24')}>
|
||||
<div className={cn(stl.header, 'flex items-end')}>
|
||||
<div className={stl.label}>
|
||||
<span>Preferences</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mb-2">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.PROFILE}
|
||||
title="Account"
|
||||
iconName="user-circle"
|
||||
onClick={() => setTab(CLIENT_TABS.PROFILE)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-2">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.INTEGRATIONS}
|
||||
title="Integrations"
|
||||
iconName="puzzle-piece"
|
||||
onClick={() => setTab(CLIENT_TABS.INTEGRATIONS)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-2">
|
||||
<SideMenuitem
|
||||
iconName="tags"
|
||||
active={activeTab === CLIENT_TABS.CUSTOM_FIELDS}
|
||||
onClick={() => setTab(CLIENT_TABS.CUSTOM_FIELDS)}
|
||||
title="Metadata"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{
|
||||
<div className="mb-2">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.WEBHOOKS}
|
||||
title="Webhooks"
|
||||
iconName="anchor"
|
||||
onClick={() => setTab(CLIENT_TABS.WEBHOOKS)}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div className="mb-2">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.SITES}
|
||||
title="Projects"
|
||||
iconName="window-restore"
|
||||
onClick={() => setTab(CLIENT_TABS.SITES)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{isEnterprise && isAdmin && (
|
||||
<div className="mb-2">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.MANAGE_ROLES}
|
||||
title="Roles & Access"
|
||||
iconName="diagram-3"
|
||||
onClick={() => setTab(CLIENT_TABS.MANAGE_ROLES)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isEnterprise && isAdmin && (
|
||||
<div className="mb-2">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.AUDIT}
|
||||
title="Audit"
|
||||
iconName="list-ul"
|
||||
onClick={() => setTab(CLIENT_TABS.AUDIT)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isAdmin && (
|
||||
<div className="mb-2">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.MANAGE_USERS}
|
||||
title="Team"
|
||||
iconName="users"
|
||||
onClick={() => setTab(CLIENT_TABS.MANAGE_USERS)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mb-2">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.NOTIFICATIONS}
|
||||
title="Notifications"
|
||||
iconName="bell"
|
||||
onClick={() => setTab(CLIENT_TABS.NOTIFICATIONS)}
|
||||
/>
|
||||
</div>
|
||||
return (
|
||||
<div className={cn(stl.wrapper, 'h-full overflow-y-auto pb-24')}>
|
||||
<div className={cn(stl.header, 'flex items-end')}>
|
||||
<div className={stl.label}>
|
||||
<span>Preferences</span>
|
||||
</div>
|
||||
);
|
||||
</div>
|
||||
|
||||
<div className="mb-2">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.PROFILE}
|
||||
title="Account"
|
||||
iconName="user-circle"
|
||||
onClick={() => setTab(CLIENT_TABS.PROFILE)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-2">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.INTEGRATIONS}
|
||||
title="Integrations"
|
||||
iconName="puzzle-piece"
|
||||
onClick={() => setTab(CLIENT_TABS.INTEGRATIONS)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-2">
|
||||
<SideMenuitem
|
||||
iconName="tags"
|
||||
active={activeTab === CLIENT_TABS.CUSTOM_FIELDS}
|
||||
onClick={() => setTab(CLIENT_TABS.CUSTOM_FIELDS)}
|
||||
title="Metadata"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{
|
||||
<div className="mb-2">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.WEBHOOKS}
|
||||
title="Webhooks"
|
||||
iconName="anchor"
|
||||
onClick={() => setTab(CLIENT_TABS.WEBHOOKS)}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div className="mb-2">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.SITES}
|
||||
title="Projects"
|
||||
iconName="window-restore"
|
||||
onClick={() => setTab(CLIENT_TABS.SITES)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{isEnterprise && isAdmin && (
|
||||
<div className="mb-2 relative">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.MANAGE_ROLES}
|
||||
title="Roles & Access"
|
||||
iconName="diagram-3"
|
||||
onClick={() => setTab(CLIENT_TABS.MANAGE_ROLES)}
|
||||
leading={<AdminOnlyBadge />}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isEnterprise && isAdmin && (
|
||||
<div className="mb-2 relative">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.AUDIT}
|
||||
title="Audit"
|
||||
iconName="list-ul"
|
||||
onClick={() => setTab(CLIENT_TABS.AUDIT)}
|
||||
leading={<AdminOnlyBadge />}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isAdmin && (
|
||||
<div className="mb-2 relative">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.MANAGE_USERS}
|
||||
title="Team"
|
||||
iconName="users"
|
||||
onClick={() => setTab(CLIENT_TABS.MANAGE_USERS)}
|
||||
leading={<AdminOnlyBadge />}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mb-2">
|
||||
<SideMenuitem
|
||||
active={activeTab === CLIENT_TABS.NOTIFICATIONS}
|
||||
title="Notifications"
|
||||
iconName="bell"
|
||||
onClick={() => setTab(CLIENT_TABS.NOTIFICATIONS)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect((state) => ({
|
||||
isEnterprise: state.getIn(['user', 'account', 'edition']) === 'ee',
|
||||
account: state.getIn(['user', 'account']),
|
||||
isEnterprise: state.getIn(['user', 'account', 'edition']) === 'ee',
|
||||
account: state.getIn(['user', 'account']),
|
||||
}))(withRouter(PreferencesMenu));
|
||||
|
||||
function AdminOnlyBadge() {
|
||||
return (
|
||||
<div
|
||||
className="ml-1 rounded-full bg-gray-light text-xs flex items-center px-2 color-gray-medium"
|
||||
style={{ marginTop: '', height: '20px', whiteSpace: 'nowrap' }}
|
||||
>
|
||||
Admin Only
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
.wrapper {
|
||||
position: fixed;
|
||||
top: 81px;
|
||||
width: 200px;
|
||||
width: 210px;
|
||||
}
|
||||
|
||||
.header {
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ function Roles(props: Props) {
|
|||
|
||||
useEffect(() => {
|
||||
if (removeErrors && removeErrors.size > 0) {
|
||||
removeErrors.forEach((e) => {
|
||||
removeErrors.forEach((e: any) => {
|
||||
toast.error(e);
|
||||
});
|
||||
}
|
||||
|
|
@ -47,21 +47,20 @@ function Roles(props: Props) {
|
|||
};
|
||||
}, [removeErrors]);
|
||||
|
||||
const closeModal = (showToastMessage) => {
|
||||
if (showToastMessage) {
|
||||
toast.success(showToastMessage);
|
||||
props.fetchList();
|
||||
}
|
||||
setShowmModal(false);
|
||||
setTimeout(() => {
|
||||
init();
|
||||
}, 100);
|
||||
};
|
||||
// const closeModal = (showToastMessage: boolean) => {
|
||||
// if (showToastMessage) {
|
||||
// toast.success(showToastMessage);
|
||||
// props.fetchList();
|
||||
// }
|
||||
// // setShowmModal(false);
|
||||
// setTimeout(() => {
|
||||
// init();
|
||||
// }, 100);
|
||||
// };
|
||||
|
||||
const editHandler = (role: any) => {
|
||||
init(role);
|
||||
showModal(<RoleForm closeModal={hideModal} permissionsMap={permissionsMap} deleteHandler={deleteHandler} />, { right: true });
|
||||
// setShowmModal(true);
|
||||
};
|
||||
|
||||
const deleteHandler = async (role: any) => {
|
||||
|
|
@ -71,7 +70,7 @@ function Roles(props: Props) {
|
|||
confirmation: `Are you sure you want to remove this role?`,
|
||||
})
|
||||
) {
|
||||
deleteRole(role.roleId);
|
||||
deleteRole(role.roleId).then(hideModal);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -83,7 +82,7 @@ function Roles(props: Props) {
|
|||
<div className="flex items-center mr-auto px-5 pt-5">
|
||||
<h3 className={cn(stl.tabTitle, 'text-2xl')}>Roles and Access</h3>
|
||||
<Popup content="You don’t have the permissions to perform this action." disabled={isAdmin}>
|
||||
<Button variant="primary" onClick={() => setShowmModal(true)}>Add</Button>
|
||||
<Button variant="primary" onClick={() => editHandler({})}>Add</Button>
|
||||
</Popup>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -123,7 +122,7 @@ function Roles(props: Props) {
|
|||
export default connect(
|
||||
(state: any) => {
|
||||
const permissions = state.getIn(['roles', 'permissions']);
|
||||
const permissionsMap = {};
|
||||
const permissionsMap: any = {};
|
||||
permissions.forEach((p: any) => {
|
||||
permissionsMap[p.value] = p.text;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -27,11 +27,15 @@ function UserListItem(props: Props) {
|
|||
<div className="grid grid-cols-12 py-4 px-5 border-t items-center select-none hover:bg-active-blue group cursor-pointer" onClick={editHandler}>
|
||||
<div className="col-span-5">
|
||||
<span className="mr-2">{user.name}</span>
|
||||
{isEnterprise && <AdminPrivilegeLabel user={user} />}
|
||||
{/* {isEnterprise && <AdminPrivilegeLabel user={user} />} */}
|
||||
</div>
|
||||
<div className="col-span-3">
|
||||
{!isEnterprise && <AdminPrivilegeLabel user={user} />}
|
||||
{isEnterprise && <span className="px-2 py-1 bg-gray-lightest rounded border text-sm capitalize">{user.roleName}</span>}
|
||||
{isEnterprise && (
|
||||
<>
|
||||
<span className="px-2 py-1 bg-gray-lightest rounded border text-sm capitalize">{user.roleName}</span>
|
||||
{ user.isSuperAdmin || user.isAdmin && <><span className="ml-2" /><AdminPrivilegeLabel user={user} /></> }
|
||||
</>)}
|
||||
</div>
|
||||
{!isOnboarding && (
|
||||
<div className="col-span-2">
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
/* min-height: calc(100vh - 81px); */
|
||||
|
||||
& .tabMenu {
|
||||
width: 240px;
|
||||
width: 250px;
|
||||
margin: 0;
|
||||
background-color: $gray-lightest;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import SelectDateRange from 'Shared/SelectDateRange';
|
|||
import { Tooltip } from 'react-tippy';
|
||||
import Breadcrumb from 'Shared/Breadcrumb';
|
||||
import AddMetricContainer from '../DashboardWidgetGrid/AddMetricContainer';
|
||||
import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv';
|
||||
|
||||
interface IProps {
|
||||
siteId: string;
|
||||
|
|
@ -32,6 +33,7 @@ function DashboardView(props: Props) {
|
|||
const { dashboardStore } = useStore();
|
||||
const { showModal } = useModal();
|
||||
|
||||
const [showTooltip, setShowTooltip] = React.useState(false);
|
||||
const [focusTitle, setFocusedInput] = React.useState(true);
|
||||
const [showEditModal, setShowEditModal] = React.useState(false);
|
||||
|
||||
|
|
@ -125,7 +127,8 @@ function DashboardView(props: Props) {
|
|||
className="mr-3 select-none border-b border-b-borderColor-transparent hover:border-dotted hover:border-gray-medium cursor-pointer"
|
||||
actionButton={
|
||||
/* @ts-ignore */
|
||||
<Tooltip
|
||||
<Tooltip
|
||||
open={showTooltip}
|
||||
interactive
|
||||
useContext
|
||||
// @ts-ignore
|
||||
|
|
@ -134,9 +137,15 @@ function DashboardView(props: Props) {
|
|||
hideDelay={200}
|
||||
duration={0}
|
||||
distance={20}
|
||||
html={<div style={{ padding: 0 }}><AddMetricContainer isPopup siteId={siteId} /></div>}
|
||||
html={
|
||||
<div style={{ padding: 0 }}>
|
||||
<OutsideClickDetectingDiv onClickOutside={() => setShowTooltip(false)}>
|
||||
<AddMetricContainer onAction={() => setShowTooltip(false)} isPopup siteId={siteId} />
|
||||
</OutsideClickDetectingDiv>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Button variant="primary">
|
||||
<Button variant="primary" onClick={() => setShowTooltip(true)}>
|
||||
Add Metric
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
|
|
|||
|
|
@ -47,11 +47,18 @@ function AddMetricButton({ iconName, title, description, onClick, isPremade, isP
|
|||
);
|
||||
}
|
||||
|
||||
function AddMetricContainer({ siteId, isPopup }: any) {
|
||||
interface Props {
|
||||
siteId: string
|
||||
isPopup: boolean
|
||||
onAction: () => void
|
||||
}
|
||||
|
||||
function AddMetricContainer({ siteId, isPopup, onAction }: Props) {
|
||||
const { showModal } = useModal();
|
||||
const { dashboardStore } = useStore();
|
||||
|
||||
const onAddCustomMetrics = () => {
|
||||
onAction()
|
||||
dashboardStore.initDashboard(dashboardStore.selectedDashboard);
|
||||
showModal(
|
||||
<AddMetric
|
||||
|
|
@ -64,6 +71,7 @@ function AddMetricContainer({ siteId, isPopup }: any) {
|
|||
};
|
||||
|
||||
const onAddPredefinedMetrics = () => {
|
||||
onAction()
|
||||
dashboardStore.initDashboard(dashboardStore.selectedDashboard);
|
||||
showModal(
|
||||
<AddPredefinedMetric
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ function ErrorDetailsModal(props: Props) {
|
|||
style={{ width: '85vw', maxWidth: '1200px' }}
|
||||
className="bg-white h-screen p-4 overflow-y-auto"
|
||||
>
|
||||
<ErrorInfo errorId={props.errorId} list={[]} />
|
||||
<ErrorInfo errorId={props.errorId} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
|
|||
@connect(
|
||||
(state) => ({
|
||||
errorIdInStore: state.getIn(['errors', 'instance']).errorId,
|
||||
list: state.getIn(['errors', 'instanceTrace']),
|
||||
loading: state.getIn(['errors', 'fetch', 'loading']) || state.getIn(['errors', 'fetchTrace', 'loading']),
|
||||
errorOnFetch: state.getIn(['errors', 'fetch', 'errors']) || state.getIn(['errors', 'fetchTrace', 'errors']),
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ export default class MainSection extends React.PureComponent {
|
|||
|
||||
render() {
|
||||
const { error, trace, sourcemapUploaded, ignoreLoading, resolveToggleLoading, toggleFavoriteLoading, className, traceLoading } = this.props;
|
||||
const isPlayer = window.location.pathname.includes('/session/')
|
||||
|
||||
return (
|
||||
<div className={cn(className, 'bg-white border-radius-3 thin-gray-border mb-6')}>
|
||||
|
|
@ -143,15 +144,17 @@ export default class MainSection extends React.PureComponent {
|
|||
/>
|
||||
</div> */}
|
||||
<Divider />
|
||||
<div className="m-4">
|
||||
<h3 className="text-xl inline-block mr-2">Last session with this error</h3>
|
||||
<span className="font-thin text-sm">{resentOrDate(error.lastOccurrence)}</span>
|
||||
<SessionBar className="my-4" session={error.lastHydratedSession} />
|
||||
<Button variant="text-primary" onClick={this.findSessions}>
|
||||
Find all sessions with this error
|
||||
<Icon className="ml-1" name="next1" color="teal" />
|
||||
</Button>
|
||||
</div>
|
||||
{!isPlayer && (
|
||||
<div className="m-4">
|
||||
<h3 className="text-xl inline-block mr-2">Last session with this error</h3>
|
||||
<span className="font-thin text-sm">{resentOrDate(error.lastOccurrence)}</span>
|
||||
<SessionBar className="my-4" session={error.lastHydratedSession} />
|
||||
<Button variant="text-primary" onClick={this.findSessions}>
|
||||
Find all sessions with this error
|
||||
<Icon className="ml-1" name="next1" color="teal" />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
<Divider />
|
||||
<div className="m-4">
|
||||
<Loader loading={traceLoading}>
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ export default class Autoscroll extends React.PureComponent<Props, {
|
|||
</div>
|
||||
|
||||
<div className={stl.navButtons}>
|
||||
<label><input type={'checkbox'} checked={this.state.autoScroll} onChange={(e) => this.setState({ autoScroll: !this.state.autoScroll })} /> Autoscroll</label>
|
||||
{/* <label><input type={'checkbox'} checked={this.state.autoScroll} onChange={(e) => this.setState({ autoScroll: !this.state.autoScroll })} /> Autoscroll</label> */}
|
||||
{navigation && (
|
||||
<>
|
||||
<IconButton size="small" icon="chevron-up" onClick={this.onPrevClick} />
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ export default class Exceptions extends React.PureComponent {
|
|||
error={e}
|
||||
key={e.key}
|
||||
selected={lastIndex === index}
|
||||
inactive={index > lastIndex}
|
||||
// inactive={index > lastIndex}
|
||||
onErrorClick={(jsEvent) => {
|
||||
jsEvent.stopPropagation();
|
||||
jsEvent.preventDefault();
|
||||
|
|
|
|||
|
|
@ -141,7 +141,6 @@ export default connect(
|
|||
stackEventList: state.stackList,
|
||||
performanceChartData: state.performanceChartData,
|
||||
endTime: state.endTime,
|
||||
// endTime: 30000000,
|
||||
}))(OverviewPanel)
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ const VERY_LOW_FPS = 20;
|
|||
const LOW_FPS_MARKER_VALUE = 5;
|
||||
const HIDDEN_SCREEN_MARKER_VALUE = 20;
|
||||
function addFpsMetadata(data) {
|
||||
return data.map((point, i) => {
|
||||
return [...data].map((point, i) => {
|
||||
let fpsVeryLowMarker = null;
|
||||
let fpsLowMarker = null;
|
||||
let hiddenScreenMarker = 0;
|
||||
|
|
|
|||
|
|
@ -11,9 +11,14 @@ export default class JsonViewer extends React.PureComponent {
|
|||
<Icon name={icon} size="24" />
|
||||
<h4 className="my-5 mx-2 font-semibold text-xl"> {title}</h4>
|
||||
</div>
|
||||
{isObjectData ? (
|
||||
<JSONTree src={data} collapsed={false} />
|
||||
) : (
|
||||
{isObjectData && <JSONTree src={data} collapsed={false} />}
|
||||
{!isObjectData && Array.isArray(data) && (
|
||||
<div>
|
||||
<div className="text-lg">{data[0]}</div>
|
||||
<JSONTree src={data[1]} collapsed={false} />
|
||||
</div>
|
||||
)}
|
||||
{typeof data === 'string' && (
|
||||
<>
|
||||
<div className="-ml-2 text-disabled-text">Payload: </div>
|
||||
<div className="mx-2">{data}</div>
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ export default class UserEvent extends React.PureComponent {
|
|||
// onClick={ this.props.switchOpen } //
|
||||
onClick={this.props.onJump} //
|
||||
className={cn('group flex py-2 px-4 ', stl.userEvent, this.getLevelClassname(), {
|
||||
[stl.inactive]: inactive,
|
||||
// [stl.inactive]: inactive,
|
||||
[stl.selected]: selected,
|
||||
})}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ const ProjectCodeSnippet = props => {
|
|||
|
||||
export default connect(state => ({
|
||||
// siteId: state.getIn([ 'site', 'siteId' ]),
|
||||
site: state.getIn([ 'site', 'instance' ]),
|
||||
// site: state.getIn([ 'site', 'instance' ]),
|
||||
gdpr: state.getIn([ 'site', 'instance', 'gdpr' ]),
|
||||
saving: state.getIn([ 'site', 'saveGDPR', 'loading' ])
|
||||
}), { editGDPR, saveGDPR })(ProjectCodeSnippet)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class TrackingCodeModal extends React.PureComponent {
|
|||
const { site } = this.props;
|
||||
switch (this.state.activeTab) {
|
||||
case PROJECT:
|
||||
return <ProjectCodeSnippet />;
|
||||
return <ProjectCodeSnippet site={site} />;
|
||||
case DOCUMENTATION:
|
||||
return <InstallDocs site={site} />;
|
||||
}
|
||||
|
|
@ -46,32 +46,14 @@ class TrackingCodeModal extends React.PureComponent {
|
|||
<div className="p-5">{this.renderActiveTab()}</div>
|
||||
</div>
|
||||
</div>
|
||||
// displayed &&
|
||||
// <Modal size="large" onClose={ onClose } open={ displayed } style={{ top: "85px" }} >
|
||||
// <Modal.Header className={ styles.modalHeader }>
|
||||
// <div>{ title } { subTitle && <span className="text-sm color-gray-dark">{subTitle}</span>}</div>
|
||||
// <div className={ cn(styles.closeButton, { 'hidden' : !onClose }) } role="button" tabIndex="-1" onClick={ onClose }>
|
||||
// <Icon name="close" size="14" />
|
||||
// </div>
|
||||
// </Modal.Header>
|
||||
// <Modal.Content className={ cn(styles.content, 'overflow-y-auto') }>
|
||||
// <Tabs
|
||||
// className="px-5"
|
||||
// tabs={ TABS }
|
||||
// active={ activeTab } onClick={ this.setActiveTab } />
|
||||
// <div className="p-5">
|
||||
// { this.renderActiveTab() }
|
||||
// </div>
|
||||
// </Modal.Content>
|
||||
// </Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(
|
||||
(state) => ({
|
||||
site: state.getIn(['site', 'instance']),
|
||||
gdpr: state.getIn(['site', 'instance', 'gdpr']),
|
||||
// site: state.getIn(['site', 'instance']),
|
||||
// gdpr: state.getIn(['site', 'instance', 'gdpr']),
|
||||
saving: state.getIn(['site', 'saveGDPR', 'loading']),
|
||||
}),
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ function ErrorDetails(props: Props) {
|
|||
const { error, sessionId, message = '', errorStack = [], sourcemapUploaded = false } = props;
|
||||
const [showRaw, setShowRaw] = useState(false);
|
||||
const firstFunc = errorStack.first() && errorStack.first().function;
|
||||
|
||||
|
||||
const openDocs = () => {
|
||||
window.open(docLink, '_blank');
|
||||
|
|
@ -77,7 +78,8 @@ function ErrorDetails(props: Props) {
|
|||
ErrorDetails.displayName = 'ErrorDetails';
|
||||
export default connect(
|
||||
(state: any) => ({
|
||||
errorStack: state.getIn(['sessions', 'errorStack']),
|
||||
// errorStack: state.getIn(['sessions', 'errorStack']),
|
||||
errorStack: state.getIn(['errors', 'instanceTrace']),
|
||||
sessionId: state.getIn(['sessions', 'current', 'sessionId']),
|
||||
}),
|
||||
{ fetchErrorStackList }
|
||||
|
|
|
|||
|
|
@ -3,8 +3,15 @@ import cn from 'classnames';
|
|||
import { IconButton } from 'UI';
|
||||
import stl from './errorItem.module.css';
|
||||
import { Duration } from 'luxon';
|
||||
import { useModal } from 'App/components/Modal';
|
||||
import ErrorDetailsModal from 'App/components/Dashboard/components/Errors/ErrorDetailsModal';
|
||||
|
||||
function ErrorItem({ error = {}, onErrorClick, onJump, inactive, selected }) {
|
||||
function ErrorItem({ error = {}, onJump, inactive, selected }) {
|
||||
const { showModal } = useModal();
|
||||
|
||||
const onErrorClick = () => {
|
||||
showModal(<ErrorDetailsModal errorId={error.errorId} />, { right: true });
|
||||
}
|
||||
return (
|
||||
<div
|
||||
className={cn(stl.wrapper, 'py-2 px-4 flex cursor-pointer', {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ function SideMenuitem({
|
|||
className={ cn(
|
||||
className,
|
||||
stl.menuItem,
|
||||
"flex items-center py-2 justify-between",
|
||||
"flex items-center py-2 justify-between shrink-0",
|
||||
{ [stl.active] : active }
|
||||
)}
|
||||
onClick={disabled ? null : onClick}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ export default class DOMManager extends ListWalker<Message> {
|
|||
private vTexts: Map<number, VText> = new Map() // map vs object here?
|
||||
private vElements: Map<number, VElement> = new Map()
|
||||
private vRoots: Map<number, VShadowRoot | VDocument> = new Map()
|
||||
private activeIframeRoots: Map<number, number> = new Map()
|
||||
private styleSheets: Map<number, CSSStyleSheet> = new Map()
|
||||
|
||||
|
||||
|
|
@ -145,7 +146,7 @@ export default class DOMManager extends ListWalker<Message> {
|
|||
case "create_document":
|
||||
doc = this.screen.document;
|
||||
if (!doc) {
|
||||
logger.error("No iframe document found", msg)
|
||||
logger.error("No root iframe document found", msg)
|
||||
return;
|
||||
}
|
||||
doc.open();
|
||||
|
|
@ -162,6 +163,7 @@ export default class DOMManager extends ListWalker<Message> {
|
|||
// this is done for the AdoptedCSS logic
|
||||
// todo: start from 0 (sync logic with tracker)
|
||||
this.stylesManager.reset()
|
||||
this.activeIframeRoots.clear()
|
||||
return
|
||||
case "create_text_node":
|
||||
vn = new VText()
|
||||
|
|
@ -293,14 +295,18 @@ export default class DOMManager extends ListWalker<Message> {
|
|||
vn.enforceInsertion()
|
||||
const host = vn.node
|
||||
if (host instanceof HTMLIFrameElement) {
|
||||
const vDoc = new VDocument()
|
||||
this.vRoots.set(msg.id, vDoc)
|
||||
const doc = host.contentDocument
|
||||
if (!doc) {
|
||||
logger.warn("No iframe doc onload", msg, host)
|
||||
logger.warn("No default iframe doc", msg, host)
|
||||
return
|
||||
}
|
||||
vDoc.setDocument(doc)
|
||||
// remove old root of the same iframe if present
|
||||
const oldRootId = this.activeIframeRoots.get(msg.frameID)
|
||||
oldRootId != null && this.vRoots.delete(oldRootId)
|
||||
|
||||
const vDoc = new VDocument(doc)
|
||||
this.activeIframeRoots.set(msg.frameID, msg.id)
|
||||
this.vRoots.set(msg.id, vDoc)
|
||||
return;
|
||||
} else if (host instanceof Element) { // shadow DOM
|
||||
try {
|
||||
|
|
@ -394,10 +400,12 @@ export default class DOMManager extends ListWalker<Message> {
|
|||
this.nodeScrollManagers.forEach(manager => {
|
||||
const msg = manager.moveGetLast(t)
|
||||
if (msg) {
|
||||
const vElm = this.vElements.get(msg.id)
|
||||
if (vElm) {
|
||||
vElm.node.scrollLeft = msg.x
|
||||
vElm.node.scrollTop = msg.y
|
||||
let vNode: VNode
|
||||
if (vNode = this.vElements.get(msg.id)) {
|
||||
vNode.node.scrollLeft = msg.x
|
||||
vNode.node.scrollTop = msg.y
|
||||
} else if ((vNode = this.vRoots.get(msg.id)) && vNode instanceof VDocument){
|
||||
vNode.node.defaultView?.scrollTo(msg.x, msg.y)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -54,10 +54,7 @@ abstract class VParent {
|
|||
}
|
||||
|
||||
export class VDocument extends VParent {
|
||||
constructor(public node: Document | null = null) { super() }
|
||||
setDocument(doc: Document) {
|
||||
this.node = doc
|
||||
}
|
||||
constructor(public readonly node: Document) { super() }
|
||||
applyChanges() {
|
||||
if (this.children.length > 1) {
|
||||
// log err
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
scrollbar-width: thin;
|
||||
&::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.grecaptcha-badge{
|
||||
|
|
@ -190,7 +190,7 @@
|
|||
/* font-family: 'FontAwesome'; */
|
||||
top: 10px;
|
||||
left: 0;
|
||||
|
||||
|
||||
content: "\201C";
|
||||
font-size: 140px;
|
||||
color: rgba(0,0,0,0.1);
|
||||
|
|
@ -201,7 +201,7 @@
|
|||
/* font-family: 'FontAwesome'; */
|
||||
bottom: 10px;
|
||||
right: 0;
|
||||
|
||||
|
||||
content: "\201E";
|
||||
font-size: 140px;
|
||||
color: rgba(0,0,0,0.1);
|
||||
|
|
@ -226,7 +226,7 @@
|
|||
.blink-border {
|
||||
/* border: 1px #ff0000 solid; */
|
||||
border-color: #CC0000;
|
||||
|
||||
|
||||
animation: blink 1s;
|
||||
animation-iteration-count: 3;
|
||||
}
|
||||
|
|
@ -282,8 +282,18 @@ p {
|
|||
padding: 0!important;
|
||||
transition: none!important;
|
||||
}
|
||||
.tippy-notransition {
|
||||
|
||||
.tippy-tooltip[data-theme~='nopadding'] > .enter {
|
||||
background-color: transparent!important;
|
||||
}
|
||||
|
||||
.tippy-notransition, .tippy-notransition > * {
|
||||
transition: none!important;
|
||||
background-color: transparent!important;
|
||||
will-change: unset!important;
|
||||
}
|
||||
.tippy-notransition > *[x-circle] {
|
||||
display: none
|
||||
}
|
||||
|
||||
@media print {
|
||||
|
|
|
|||
206
peers/package-lock.json
generated
206
peers/package-lock.json
generated
|
|
@ -47,9 +47,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@types/express-serve-static-core": {
|
||||
"version": "4.17.28",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz",
|
||||
"integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==",
|
||||
"version": "4.17.30",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.30.tgz",
|
||||
"integrity": "sha512-gstzbTWro2/nFed1WXtf+TtrpwxH7Ggs4RLYTLbeVgIkUQOI3WG/JKjgeOU1zXDvezllupjrf8OPIdvTbIaVOQ==",
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"@types/qs": "*",
|
||||
|
|
@ -57,14 +57,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@types/mime": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
|
||||
"integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw=="
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz",
|
||||
"integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA=="
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "17.0.21",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz",
|
||||
"integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ=="
|
||||
"version": "18.7.16",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.16.tgz",
|
||||
"integrity": "sha512-EQHhixfu+mkqHMZl1R2Ovuvn47PUw18azMJOTwSZr9/fhzHNGXAJ0ma0dayRVchprpCj0Kc1K1xKoWaATWF1qg=="
|
||||
},
|
||||
"node_modules/@types/qs": {
|
||||
"version": "6.9.7",
|
||||
|
|
@ -77,11 +77,11 @@
|
|||
"integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw=="
|
||||
},
|
||||
"node_modules/@types/serve-static": {
|
||||
"version": "1.13.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz",
|
||||
"integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==",
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz",
|
||||
"integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==",
|
||||
"dependencies": {
|
||||
"@types/mime": "^1",
|
||||
"@types/mime": "*",
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
|
|
@ -130,7 +130,7 @@
|
|||
"node_modules/array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
|
||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.0",
|
||||
|
|
@ -175,6 +175,14 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/camelcase": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
||||
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
|
||||
|
|
@ -231,7 +239,7 @@
|
|||
"node_modules/cookie-signature": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
|
||||
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
|
||||
},
|
||||
"node_modules/cors": {
|
||||
"version": "2.8.5",
|
||||
|
|
@ -256,7 +264,7 @@
|
|||
"node_modules/decamelize": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
||||
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
|
||||
"integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
|
@ -504,7 +512,7 @@
|
|||
"node_modules/media-typer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
|
||||
"integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
|
|
@ -512,12 +520,12 @@
|
|||
"node_modules/merge-descriptors": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
|
||||
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
|
||||
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
|
||||
},
|
||||
"node_modules/methods": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
|
||||
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
|
||||
"integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
|
|
@ -534,19 +542,19 @@
|
|||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.51.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz",
|
||||
"integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==",
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-types": {
|
||||
"version": "2.1.34",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz",
|
||||
"integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==",
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"dependencies": {
|
||||
"mime-db": "1.51.0"
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
|
|
@ -555,7 +563,7 @@
|
|||
"node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"node_modules/negotiator": {
|
||||
"version": "0.6.3",
|
||||
|
|
@ -568,7 +576,7 @@
|
|||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
|
@ -644,7 +652,7 @@
|
|||
"node_modules/path-to-regexp": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
||||
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
|
||||
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
|
||||
},
|
||||
"node_modules/peer": {
|
||||
"version": "0.6.1",
|
||||
|
|
@ -668,15 +676,6 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/peer/node_modules/uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
|
||||
"bin": {
|
||||
"uuid": "bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
|
|
@ -728,7 +727,7 @@
|
|||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
|
||||
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
|
@ -807,7 +806,7 @@
|
|||
"node_modules/set-blocking": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
|
||||
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
|
||||
},
|
||||
"node_modules/setprototypeof": {
|
||||
"version": "1.2.0",
|
||||
|
|
@ -890,15 +889,24 @@
|
|||
"node_modules/utils-merge": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
|
||||
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
|
||||
"engines": {
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
|
||||
"bin": {
|
||||
"uuid": "bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
|
||||
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
|
|
@ -906,7 +914,7 @@
|
|||
"node_modules/which-module": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
|
||||
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
|
||||
"integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q=="
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "6.2.0",
|
||||
|
|
@ -922,9 +930,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "7.5.7",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz",
|
||||
"integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==",
|
||||
"version": "7.5.9",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
|
||||
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
|
||||
"engines": {
|
||||
"node": ">=8.3.0"
|
||||
},
|
||||
|
|
@ -978,14 +986,6 @@
|
|||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs-parser/node_modules/camelcase": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
||||
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
@ -1023,9 +1023,9 @@
|
|||
}
|
||||
},
|
||||
"@types/express-serve-static-core": {
|
||||
"version": "4.17.28",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz",
|
||||
"integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==",
|
||||
"version": "4.17.30",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.30.tgz",
|
||||
"integrity": "sha512-gstzbTWro2/nFed1WXtf+TtrpwxH7Ggs4RLYTLbeVgIkUQOI3WG/JKjgeOU1zXDvezllupjrf8OPIdvTbIaVOQ==",
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"@types/qs": "*",
|
||||
|
|
@ -1033,14 +1033,14 @@
|
|||
}
|
||||
},
|
||||
"@types/mime": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
|
||||
"integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw=="
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz",
|
||||
"integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA=="
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "17.0.21",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz",
|
||||
"integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ=="
|
||||
"version": "18.7.16",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.16.tgz",
|
||||
"integrity": "sha512-EQHhixfu+mkqHMZl1R2Ovuvn47PUw18azMJOTwSZr9/fhzHNGXAJ0ma0dayRVchprpCj0Kc1K1xKoWaATWF1qg=="
|
||||
},
|
||||
"@types/qs": {
|
||||
"version": "6.9.7",
|
||||
|
|
@ -1053,11 +1053,11 @@
|
|||
"integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw=="
|
||||
},
|
||||
"@types/serve-static": {
|
||||
"version": "1.13.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz",
|
||||
"integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==",
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz",
|
||||
"integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==",
|
||||
"requires": {
|
||||
"@types/mime": "^1",
|
||||
"@types/mime": "*",
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
|
|
@ -1094,7 +1094,7 @@
|
|||
"array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
|
||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
|
||||
},
|
||||
"body-parser": {
|
||||
"version": "1.20.0",
|
||||
|
|
@ -1129,6 +1129,11 @@
|
|||
"get-intrinsic": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"camelcase": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
||||
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
|
||||
},
|
||||
"cliui": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
|
||||
|
|
@ -1173,7 +1178,7 @@
|
|||
"cookie-signature": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
|
||||
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
|
||||
},
|
||||
"cors": {
|
||||
"version": "2.8.5",
|
||||
|
|
@ -1195,7 +1200,7 @@
|
|||
"decamelize": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
||||
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
|
||||
"integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA=="
|
||||
},
|
||||
"depd": {
|
||||
"version": "2.0.0",
|
||||
|
|
@ -1382,17 +1387,17 @@
|
|||
"media-typer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
|
||||
"integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="
|
||||
},
|
||||
"merge-descriptors": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
|
||||
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
|
||||
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
|
||||
},
|
||||
"methods": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
|
||||
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
|
||||
"integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="
|
||||
},
|
||||
"mime": {
|
||||
"version": "1.6.0",
|
||||
|
|
@ -1400,22 +1405,22 @@
|
|||
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.51.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz",
|
||||
"integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g=="
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.34",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz",
|
||||
"integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==",
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"requires": {
|
||||
"mime-db": "1.51.0"
|
||||
"mime-db": "1.52.0"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"negotiator": {
|
||||
"version": "0.6.3",
|
||||
|
|
@ -1425,7 +1430,7 @@
|
|||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
|
||||
},
|
||||
"object-inspect": {
|
||||
"version": "1.12.2",
|
||||
|
|
@ -1474,7 +1479,7 @@
|
|||
"path-to-regexp": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
||||
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
|
||||
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
|
||||
},
|
||||
"peer": {
|
||||
"version": "0.6.1",
|
||||
|
|
@ -1490,13 +1495,6 @@
|
|||
"uuid": "^3.4.0",
|
||||
"ws": "^7.2.3",
|
||||
"yargs": "^15.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"proxy-addr": {
|
||||
|
|
@ -1535,7 +1533,7 @@
|
|||
"require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
|
||||
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="
|
||||
},
|
||||
"require-main-filename": {
|
||||
"version": "2.0.0",
|
||||
|
|
@ -1593,7 +1591,7 @@
|
|||
"set-blocking": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
|
||||
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
|
||||
},
|
||||
"setprototypeof": {
|
||||
"version": "1.2.0",
|
||||
|
|
@ -1655,17 +1653,22 @@
|
|||
"utils-merge": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
|
||||
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="
|
||||
},
|
||||
"uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
|
||||
},
|
||||
"vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
|
||||
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
|
||||
},
|
||||
"which-module": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
|
||||
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
|
||||
"integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q=="
|
||||
},
|
||||
"wrap-ansi": {
|
||||
"version": "6.2.0",
|
||||
|
|
@ -1678,9 +1681,9 @@
|
|||
}
|
||||
},
|
||||
"ws": {
|
||||
"version": "7.5.7",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz",
|
||||
"integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==",
|
||||
"version": "7.5.9",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
|
||||
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
|
||||
"requires": {}
|
||||
},
|
||||
"y18n": {
|
||||
|
|
@ -1713,13 +1716,6 @@
|
|||
"requires": {
|
||||
"camelcase": "^5.0.0",
|
||||
"decamelize": "^1.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"camelcase": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
||||
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@ const {peerRouter, peerConnection, peerDisconnect, peerError} = require('./serve
|
|||
const express = require('express');
|
||||
const {ExpressPeerServer} = require('peer');
|
||||
|
||||
const HOST = '0.0.0.0';
|
||||
const PORT = 9000;
|
||||
const debug = process.env.debug === "1" || false;
|
||||
const HOST = process.env.LISTEN_HOST || '0.0.0.0';
|
||||
const PORT = process.env.LISTEN_PORT || 9000;
|
||||
|
||||
const app = express();
|
||||
|
||||
|
|
@ -30,4 +31,10 @@ peerServer.on('disconnect', peerDisconnect);
|
|||
peerServer.on('error', peerError);
|
||||
app.use('/', peerServer);
|
||||
app.enable('trust proxy');
|
||||
module.exports = {server};
|
||||
module.exports = {server};
|
||||
|
||||
process.on('uncaughtException', err => {
|
||||
console.log(`Uncaught Exception: ${err.message}`);
|
||||
debug && console.log(err.stack);
|
||||
// process.exit(1);
|
||||
});
|
||||
|
|
@ -37,7 +37,11 @@ const peerDisconnect = (client) => {
|
|||
}
|
||||
|
||||
const peerError = (error) => {
|
||||
console.error('error fired');
|
||||
//https://peerjs.com/docs/#peeron-error
|
||||
console.error('Error detected in Peers');
|
||||
console.error('Error type:');
|
||||
console.error(error.type);
|
||||
console.error('Error message:');
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,17 +3,17 @@ const sourcemapsReaderServer = require('./servers/sourcemaps-server');
|
|||
const express = require('express');
|
||||
const {request_logger} = require("./utils/helper");
|
||||
|
||||
const HOST = '0.0.0.0';
|
||||
const PORT = 9000;
|
||||
const HOST = process.env.SR_HOST || '127.0.0.1';
|
||||
const PORT = process.env.SR_PORT || 9000;
|
||||
|
||||
const app = express();
|
||||
app.use(request_logger("[wsapp]"));
|
||||
app.use(request_logger("[SR]"));
|
||||
|
||||
app.use('/sourcemaps', sourcemapsReaderServer);
|
||||
app.use('/heapdump', dumps.router);
|
||||
|
||||
const server = app.listen(PORT, HOST, () => {
|
||||
console.log(`WS App listening on http://${HOST}:${PORT}`);
|
||||
console.log(`SR App listening on http://${HOST}:${PORT}`);
|
||||
console.log('Press Ctrl+C to quit.');
|
||||
});
|
||||
module.exports = {server};
|
||||
|
|
@ -42,8 +42,8 @@ module.exports.sourcemapReader = async event => {
|
|||
return new Promise(function (resolve, reject) {
|
||||
s3.getObject(options, (err, data) => {
|
||||
if (err) {
|
||||
console.log("Get S3 object failed");
|
||||
console.log(err);
|
||||
console.error("[SR] Get S3 object failed");
|
||||
console.error(err);
|
||||
return reject(err);
|
||||
}
|
||||
let sourcemap = data.Body.toString();
|
||||
|
|
@ -68,13 +68,13 @@ module.exports.sourcemapReader = async event => {
|
|||
preview = preview.slice(start, original.line + event.padding);
|
||||
}
|
||||
} else {
|
||||
console.log("source not found, null preview for:");
|
||||
console.log("[SR] source not found, null preview for:");
|
||||
console.log(original.source);
|
||||
preview = []
|
||||
}
|
||||
url = URL.parse(original.source);
|
||||
} else {
|
||||
console.log("couldn't find original position of:");
|
||||
console.log("[SR] couldn't find original position of:");
|
||||
console.log({
|
||||
line: event.positions[i].line,
|
||||
column: event.positions[i].column
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ router.post('/', (req, res) => {
|
|||
});
|
||||
req.on('end', function () {
|
||||
data = JSON.parse(data);
|
||||
console.log("Starting parser for: " + data.key);
|
||||
console.log("[SR] Starting parser for: " + data.key);
|
||||
// process.env = {...process.env, ...data.bucket_config};
|
||||
handler.sourcemapReader(data)
|
||||
.then((results) => {
|
||||
|
|
@ -18,7 +18,7 @@ router.post('/', (req, res) => {
|
|||
res.end(JSON.stringify(results));
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error("Something went wrong");
|
||||
console.error("[SR] Something went wrong");
|
||||
console.error(e);
|
||||
res.statusCode(500);
|
||||
res.end(e);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@openreplay/tracker-assist",
|
||||
"description": "Tracker plugin for screen assistance through the WebRTC",
|
||||
"version": "4.0.0",
|
||||
"version": "4.0.1",
|
||||
"keywords": [
|
||||
"WebRTC",
|
||||
"assistance",
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
"socket.io-client": "^4.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@openreplay/tracker": "^3.6.0"
|
||||
"@openreplay/tracker": ">=3.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@openreplay/tracker": "file:../tracker",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@openreplay/tracker-axios",
|
||||
"description": "Tracker plugin for axios requests recording",
|
||||
"version": "3.6.0",
|
||||
"version": "3.6.1",
|
||||
"keywords": [
|
||||
"axios",
|
||||
"logging",
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
},
|
||||
"dependencies": {},
|
||||
"peerDependencies": {
|
||||
"@openreplay/tracker": "^3.6.0",
|
||||
"@openreplay/tracker": ">=3.6.0",
|
||||
"axios": "0.x"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@openreplay/tracker-fetch",
|
||||
"description": "Tracker plugin for fetch requests recording ",
|
||||
"version": "3.6.0",
|
||||
"version": "3.6.1",
|
||||
"keywords": [
|
||||
"fetch",
|
||||
"logging",
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
},
|
||||
"dependencies": {},
|
||||
"peerDependencies": {
|
||||
"@openreplay/tracker": "^3.6.0"
|
||||
"@openreplay/tracker": ">=3.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@openreplay/tracker": "file:../tracker",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@openreplay/tracker-graphql",
|
||||
"description": "Tracker plugin for GraphQL requests recording",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.1",
|
||||
"keywords": [
|
||||
"graphql",
|
||||
"logging",
|
||||
|
|
@ -22,10 +22,10 @@
|
|||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@openreplay/tracker": "^3.0.0"
|
||||
"@openreplay/tracker": ">=3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@openreplay/tracker": "^3.0.0",
|
||||
"@openreplay/tracker": "file:../tracker",
|
||||
"prettier": "^1.18.2",
|
||||
"replace-in-files-cli": "^1.0.0",
|
||||
"typescript": "^3.6.4"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@openreplay/tracker-mobx",
|
||||
"description": "Tracker plugin for MobX events recording",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.1",
|
||||
"keywords": [
|
||||
"mobx",
|
||||
"logging",
|
||||
|
|
@ -23,11 +23,11 @@
|
|||
},
|
||||
"dependencies": {},
|
||||
"peerDependencies": {
|
||||
"@openreplay/tracker": "^3.0.0",
|
||||
"@openreplay/tracker": ">=3.0.0",
|
||||
"mobx": "^4.15.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@openreplay/tracker": "^3.0.3",
|
||||
"@openreplay/tracker": "file:../tracker",
|
||||
"mobx": "^4.15.7",
|
||||
"prettier": "^1.18.2",
|
||||
"replace-in-files-cli": "^1.0.0",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@openreplay/tracker-ngrx",
|
||||
"description": "Tracker plugin for NgRx state recording",
|
||||
"version": "3.4.8",
|
||||
"version": "3.4.9",
|
||||
"keywords": [
|
||||
"ngrx",
|
||||
"logging",
|
||||
|
|
@ -23,11 +23,11 @@
|
|||
},
|
||||
"dependencies": {},
|
||||
"peerDependencies": {
|
||||
"@openreplay/tracker": "^3.4.8",
|
||||
"@openreplay/tracker": ">=3.4.8",
|
||||
"@ngrx/store": ">=4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@openreplay/tracker": "^3.4.8",
|
||||
"@openreplay/tracker": "file:../tracker",
|
||||
"prettier": "^1.18.2",
|
||||
"replace-in-files-cli": "^1.0.0",
|
||||
"typescript": "^4.6.0-dev.20211126"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@openreplay/tracker-profiler",
|
||||
"description": "Tracker plugin for profiling JS function calls",
|
||||
"version": "3.0.0",
|
||||
"version": "3.0.1",
|
||||
"keywords": [
|
||||
"debugging",
|
||||
"logging",
|
||||
|
|
@ -22,10 +22,10 @@
|
|||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@openreplay/tracker": "^3.0.0"
|
||||
"@openreplay/tracker": ">=3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@openreplay/tracker": "^3.0.0",
|
||||
"@openreplay/tracker": "file:../tracker",
|
||||
"prettier": "^1.18.2",
|
||||
"replace-in-files-cli": "^1.0.0",
|
||||
"typescript": "^3.6.4"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@openreplay/tracker-redux",
|
||||
"description": "Tracker plugin for Redux state recording",
|
||||
"version": "3.5.0",
|
||||
"version": "3.5.1",
|
||||
"keywords": [
|
||||
"redux",
|
||||
"logging",
|
||||
|
|
@ -23,11 +23,11 @@
|
|||
},
|
||||
"dependencies": {},
|
||||
"peerDependencies": {
|
||||
"@openreplay/tracker": "^3.5.0",
|
||||
"@openreplay/tracker": ">=3.5.0",
|
||||
"redux": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@openreplay/tracker": "^3.5.0",
|
||||
"@openreplay/tracker": "file:../tracker",
|
||||
"prettier": "^1.18.2",
|
||||
"replace-in-files-cli": "^1.0.0",
|
||||
"typescript": "^4.6.0-dev.20211126"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@openreplay/tracker-vuex",
|
||||
"description": "Tracker plugin for Vuex state recording",
|
||||
"version": "4.0.1",
|
||||
"version": "4.0.2",
|
||||
"keywords": [
|
||||
"vuex",
|
||||
"logging",
|
||||
|
|
@ -23,10 +23,10 @@
|
|||
},
|
||||
"dependencies": {},
|
||||
"peerDependencies": {
|
||||
"@openreplay/tracker": "^3.4.8"
|
||||
"@openreplay/tracker": ">=3.4.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@openreplay/tracker": "^3.4.8",
|
||||
"@openreplay/tracker": "file:../tracker",
|
||||
"prettier": "^1.18.2",
|
||||
"replace-in-files-cli": "^1.0.0",
|
||||
"typescript": "^4.6.0-dev.20211126"
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ const tracker = new Tracker({
|
|||
});
|
||||
|
||||
const zustandPlugin = tracker.use(trackerZustand())
|
||||
// store name, optional
|
||||
// randomly generated if undefined
|
||||
const bearStoreLogger = zustandPlugin('bear_store')
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@openreplay/tracker-zustand",
|
||||
"description": "Tracker plugin for Zustand state recording",
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.2",
|
||||
"keywords": [
|
||||
"zustand",
|
||||
"state",
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
//@ts-ignore
|
||||
export function isNode(sth: any): sth is Node {
|
||||
return !!sth && sth.nodeType != null
|
||||
}
|
||||
|
||||
export function isSVGElement(node: Element): node is SVGElement {
|
||||
return node.namespaceURI === 'http://www.w3.org/2000/svg'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -213,9 +213,9 @@ export default class App {
|
|||
}
|
||||
}
|
||||
|
||||
safe<T extends (...args: any[]) => void>(fn: T): T {
|
||||
safe<T extends (this: any, ...args: any[]) => void>(fn: T): T {
|
||||
const app = this
|
||||
return function (this: any, ...args: any) {
|
||||
return function (this: any, ...args: any[]) {
|
||||
try {
|
||||
fn.apply(this, args)
|
||||
} catch (e) {
|
||||
|
|
@ -225,12 +225,10 @@ export default class App {
|
|||
// message: e.message,
|
||||
// stack: e.stack
|
||||
}
|
||||
} as any // TODO: correct typing
|
||||
} as T // TODO: correct typing
|
||||
}
|
||||
|
||||
attachCommitCallback(cb: CommitCallback): void {
|
||||
// TODO!: what if start callback added when activityState === Active ?
|
||||
// For example - attachEventListener() called during dynamic <iframe> appearance
|
||||
this.commitCallbacks.push(cb)
|
||||
}
|
||||
attachStartCallback(cb: StartCallback, useSafe = false): void {
|
||||
|
|
@ -245,6 +243,7 @@ export default class App {
|
|||
}
|
||||
this.stopCallbacks.push(cb)
|
||||
}
|
||||
// Use app.nodes.attachNodeListener for registered nodes instead
|
||||
attachEventListener(
|
||||
target: EventTarget,
|
||||
type: string,
|
||||
|
|
@ -390,6 +389,7 @@ export default class App {
|
|||
|
||||
const sReset = this.sessionStorage.getItem(this.options.session_reset_key)
|
||||
this.sessionStorage.removeItem(this.options.session_reset_key)
|
||||
const shouldReset = startOpts.forceNew || sReset !== null
|
||||
|
||||
return window
|
||||
.fetch(this.options.ingestPoint + '/v1/web/start', {
|
||||
|
|
@ -401,10 +401,9 @@ export default class App {
|
|||
...this.getTrackerInfo(),
|
||||
timestamp,
|
||||
userID: this.session.getInfo().userID,
|
||||
token: this.session.getSessionToken(),
|
||||
token: shouldReset ? undefined : this.session.getSessionToken(),
|
||||
deviceMemory,
|
||||
jsHeapSizeLimit,
|
||||
reset: startOpts.forceNew || sReset !== null,
|
||||
}),
|
||||
})
|
||||
.then((r) => {
|
||||
|
|
@ -424,6 +423,9 @@ export default class App {
|
|||
if (!this.worker) {
|
||||
return Promise.reject('no worker found after start request (this might not happen)')
|
||||
}
|
||||
if (this.activityState === ActivityState.NotActive) {
|
||||
return Promise.reject('Tracker stopped during authorisation')
|
||||
}
|
||||
const {
|
||||
token,
|
||||
userUUID,
|
||||
|
|
@ -441,9 +443,12 @@ export default class App {
|
|||
) {
|
||||
return Promise.reject(`Incorrect server response: ${JSON.stringify(r)}`)
|
||||
}
|
||||
if (sessionID !== this.session.getInfo().sessionID) {
|
||||
this.session.reset()
|
||||
}
|
||||
this.session.setSessionToken(token)
|
||||
this.localStorage.setItem(this.options.local_uuid_key, userUUID)
|
||||
this.session.update({ sessionID, timestamp: startTimestamp || timestamp, projectID }) // TODO: no no-explicit 'any'
|
||||
this.localStorage.setItem(this.options.local_uuid_key, userUUID)
|
||||
|
||||
const startWorkerMsg: WorkerMessageData = {
|
||||
type: 'auth',
|
||||
|
|
|
|||
|
|
@ -12,20 +12,18 @@ export default class Nodes {
|
|||
attachNodeCallback(nodeCallback: NodeCallback): void {
|
||||
this.nodeCallbacks.push(nodeCallback)
|
||||
}
|
||||
// TODO: what is the difference with app.attachEventListener. can we use only one of those?
|
||||
attachElementListener(type: string, node: Element, elementListener: EventListener): void {
|
||||
attachNodeListener(node: Node, type: string, listener: EventListener): void {
|
||||
const id = this.getID(node)
|
||||
if (id === undefined) {
|
||||
return
|
||||
}
|
||||
node.addEventListener(type, elementListener)
|
||||
node.addEventListener(type, listener)
|
||||
let listeners = this.elementListeners.get(id)
|
||||
if (listeners === undefined) {
|
||||
listeners = []
|
||||
this.elementListeners.set(id, listeners)
|
||||
return
|
||||
}
|
||||
listeners.push([type, elementListener])
|
||||
listeners.push([type, listener])
|
||||
}
|
||||
|
||||
registerNode(node: Node): [/*id:*/ number, /*isNew:*/ boolean] {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ export default class IFrameObserver extends Observer {
|
|||
} //log TODO common app.logger
|
||||
// Have to observe document, because the inner <html> might be changed
|
||||
this.observeRoot(doc, (docID) => {
|
||||
//MBTODO: do not send if empty (send on load? it might be in-place iframe, like our replayer, which does not get loaded)
|
||||
if (docID === undefined) {
|
||||
console.log('OpenReplay: Iframe document not bound')
|
||||
return
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ export default abstract class Observer {
|
|||
return false
|
||||
}
|
||||
this.app.sanitizer.handleNode(id, parentID, node)
|
||||
if (this.app.sanitizer.isMaskedContainer(parentID)) {
|
||||
if (this.app.sanitizer.isHidden(parentID)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
@ -287,13 +287,13 @@ export default abstract class Observer {
|
|||
if (isElementNode(node)) {
|
||||
let el: Element = node
|
||||
if (parentID !== undefined) {
|
||||
if (this.app.sanitizer.isMaskedContainer(id)) {
|
||||
if (this.app.sanitizer.isHidden(id)) {
|
||||
const width = el.clientWidth
|
||||
const height = el.clientHeight
|
||||
el = node.cloneNode() as Element
|
||||
// TODO: use ResizeObserver
|
||||
;(el as HTMLElement | SVGElement).style.width = width + 'px'
|
||||
;(el as HTMLElement | SVGElement).style.height = height + 'px'
|
||||
;(el as HTMLElement | SVGElement).style.width = `${width}px`
|
||||
;(el as HTMLElement | SVGElement).style.height = `${height}px`
|
||||
}
|
||||
|
||||
this.app.send(CreateElementNode(id, parentID, index, el.tagName, isSVGElement(node)))
|
||||
|
|
|
|||
|
|
@ -78,41 +78,45 @@ export default class TopObserver extends Observer {
|
|||
private handleIframe(iframe: HTMLIFrameElement): void {
|
||||
let doc: Document | null = null
|
||||
let win: Window | null = null
|
||||
const handle = this.app.safe(() => {
|
||||
const id = this.app.nodes.getID(iframe)
|
||||
if (id === undefined) {
|
||||
//log
|
||||
return
|
||||
}
|
||||
const currentWin = iframe.contentWindow
|
||||
const currentDoc = iframe.contentDocument
|
||||
if (currentDoc && currentDoc !== doc) {
|
||||
const observer = new IFrameObserver(this.app)
|
||||
this.iframeObservers.push(observer)
|
||||
observer.observe(iframe)
|
||||
doc = currentDoc
|
||||
// setTimeout is required. Otherwise some event listeners (scroll, mousemove) applied in modules
|
||||
// do not work on the iframe document when it 've been loaded dynamically ((why?))
|
||||
const handle = this.app.safe(() =>
|
||||
setTimeout(() => {
|
||||
const id = this.app.nodes.getID(iframe)
|
||||
if (id === undefined) {
|
||||
//log
|
||||
return
|
||||
}
|
||||
const currentWin = iframe.contentWindow
|
||||
const currentDoc = iframe.contentDocument
|
||||
if (currentDoc && currentDoc !== doc) {
|
||||
const observer = new IFrameObserver(this.app)
|
||||
this.iframeObservers.push(observer)
|
||||
observer.observe(iframe) // TODO: call unregisterNode for the previous doc if present (incapsulate: one iframe - one observer)
|
||||
doc = currentDoc
|
||||
|
||||
// Le truc
|
||||
;(doc as PatchedDocument).__openreplay__getOffset = () => {
|
||||
const { top, left } = this.getDocumentOffset(iframe.ownerDocument)
|
||||
return {
|
||||
top: iframe.offsetTop + top,
|
||||
left: iframe.offsetLeft + left,
|
||||
// Le truc
|
||||
;(doc as PatchedDocument).__openreplay__getOffset = () => {
|
||||
const { top, left } = this.getDocumentOffset(iframe.ownerDocument)
|
||||
return {
|
||||
top: iframe.offsetTop + top,
|
||||
left: iframe.offsetLeft + left,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
currentWin &&
|
||||
// Sometimes currentWin.window is null (not in specification). Such window object is not functional
|
||||
currentWin === currentWin.window &&
|
||||
!this.contextsSet.has(currentWin) // for each context callbacks called once per Tracker (TopObserver) instance
|
||||
) {
|
||||
this.contextsSet.add(currentWin)
|
||||
//@ts-ignore https://github.com/microsoft/TypeScript/issues/41684
|
||||
this.contextCallbacks.forEach((cb) => cb(currentWin))
|
||||
win = currentWin
|
||||
}
|
||||
})
|
||||
if (
|
||||
currentWin &&
|
||||
// Sometimes currentWin.window is null (not in specification). Such window object is not functional
|
||||
currentWin === currentWin.window &&
|
||||
!this.contextsSet.has(currentWin) // for each context callbacks called once per Tracker (TopObserver) instance
|
||||
) {
|
||||
this.contextsSet.add(currentWin)
|
||||
//@ts-ignore https://github.com/microsoft/TypeScript/issues/41684
|
||||
this.contextCallbacks.forEach((cb) => cb(currentWin))
|
||||
win = currentWin
|
||||
}
|
||||
}, 0),
|
||||
)
|
||||
iframe.addEventListener('load', handle) // why app.attachEventListener not working?
|
||||
handle()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,21 @@ import type App from './index.js'
|
|||
import { stars, hasOpenreplayAttribute } from '../utils.js'
|
||||
import { isElementNode } from './guards.js'
|
||||
|
||||
export enum SanitizeLevel {
|
||||
Plain,
|
||||
Obscured,
|
||||
Hidden,
|
||||
}
|
||||
|
||||
export interface Options {
|
||||
obscureTextEmails: boolean
|
||||
obscureTextNumbers: boolean
|
||||
domSanitizer?: (node: Element) => SanitizeLevel
|
||||
}
|
||||
|
||||
export default class Sanitizer {
|
||||
private readonly masked: Set<number> = new Set()
|
||||
private readonly maskedContainers: Set<number> = new Set()
|
||||
private readonly obscured: Set<number> = new Set()
|
||||
private readonly hidden: Set<number> = new Set()
|
||||
private readonly options: Options
|
||||
|
||||
constructor(private readonly app: App, options: Partial<Options>) {
|
||||
|
|
@ -24,21 +31,33 @@ export default class Sanitizer {
|
|||
|
||||
handleNode(id: number, parentID: number, node: Node) {
|
||||
if (
|
||||
this.masked.has(parentID) ||
|
||||
(isElementNode(node) && hasOpenreplayAttribute(node, 'masked'))
|
||||
this.obscured.has(parentID) ||
|
||||
(isElementNode(node) &&
|
||||
(hasOpenreplayAttribute(node, 'masked') || hasOpenreplayAttribute(node, 'obscured')))
|
||||
) {
|
||||
this.masked.add(id)
|
||||
this.obscured.add(id)
|
||||
}
|
||||
if (
|
||||
this.maskedContainers.has(parentID) ||
|
||||
(isElementNode(node) && hasOpenreplayAttribute(node, 'htmlmasked'))
|
||||
this.hidden.has(parentID) ||
|
||||
(isElementNode(node) &&
|
||||
(hasOpenreplayAttribute(node, 'htmlmasked') || hasOpenreplayAttribute(node, 'hidden')))
|
||||
) {
|
||||
this.maskedContainers.add(id)
|
||||
this.hidden.add(id)
|
||||
}
|
||||
|
||||
if (this.options.domSanitizer !== undefined && isElementNode(node)) {
|
||||
const sanitizeLevel = this.options.domSanitizer(node)
|
||||
if (sanitizeLevel === SanitizeLevel.Obscured) {
|
||||
this.obscured.add(id)
|
||||
}
|
||||
if (sanitizeLevel === SanitizeLevel.Hidden) {
|
||||
this.hidden.add(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sanitize(id: number, data: string): string {
|
||||
if (this.masked.has(id)) {
|
||||
if (this.obscured.has(id)) {
|
||||
// TODO: is it the best place to put trim() ? Might trimmed spaces be considered in layout in certain cases?
|
||||
return data
|
||||
.trim()
|
||||
|
|
@ -56,11 +75,12 @@ export default class Sanitizer {
|
|||
return data
|
||||
}
|
||||
|
||||
isMasked(id: number): boolean {
|
||||
return this.masked.has(id)
|
||||
isObscured(id: number): boolean {
|
||||
return this.obscured.has(id)
|
||||
}
|
||||
isMaskedContainer(id: number) {
|
||||
return this.maskedContainers.has(id)
|
||||
|
||||
isHidden(id: number) {
|
||||
return this.hidden.has(id)
|
||||
}
|
||||
|
||||
getInnerTextSecure(el: HTMLElement): string {
|
||||
|
|
@ -72,7 +92,7 @@ export default class Sanitizer {
|
|||
}
|
||||
|
||||
clear(): void {
|
||||
this.masked.clear()
|
||||
this.maskedContainers.clear()
|
||||
this.obscured.clear()
|
||||
this.hidden.clear()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ export default class Session {
|
|||
let token = hash
|
||||
let pageNoStr = '100500' // back-compat for sessionToken
|
||||
if (hashParts.length == 2) {
|
||||
;[token, pageNoStr] = hashParts
|
||||
;[pageNoStr, token] = hashParts
|
||||
}
|
||||
if (!pageNoStr || !token) {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import App, { DEFAULT_INGEST_POINT } from './app/index.js'
|
||||
export { default as App } from './app/index.js'
|
||||
|
||||
import { UserID, UserAnonymousID, RawCustomEvent, CustomIssue } from './app/messages.gen.js'
|
||||
import { UserAnonymousID, RawCustomEvent, CustomIssue } from './app/messages.gen.js'
|
||||
import * as _Messages from './app/messages.gen.js'
|
||||
export const Messages = _Messages
|
||||
export { SanitizeLevel } from './app/sanitizer.js'
|
||||
|
||||
import Connection from './modules/connection.js'
|
||||
import Console from './modules/console.js'
|
||||
|
|
@ -187,9 +188,7 @@ export default class API {
|
|||
return
|
||||
}
|
||||
this.app.stop()
|
||||
const sessionHash = this.app.session.getSessionHash()
|
||||
this.app.session.reset()
|
||||
return sessionHash
|
||||
return this.app.session.getSessionHash()
|
||||
}
|
||||
|
||||
getSessionToken(): string | null | undefined {
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ export default function (app: App): void {
|
|||
if (id === undefined) {
|
||||
return
|
||||
}
|
||||
const { src, complete, naturalWidth, naturalHeight, srcset } = this
|
||||
const { src, complete, naturalWidth, naturalHeight } = this
|
||||
if (!complete) {
|
||||
return
|
||||
}
|
||||
|
|
@ -63,7 +63,11 @@ export default function (app: App): void {
|
|||
if (isURL(resolvedSrc)) {
|
||||
app.send(ResourceTiming(timestamp(), 0, 0, 0, 0, 0, resolvedSrc, 'img'))
|
||||
}
|
||||
} else if (resolvedSrc.length >= 1e5 || app.sanitizer.isMasked(id)) {
|
||||
} else if (
|
||||
resolvedSrc.length >= 1e5 ||
|
||||
app.sanitizer.isHidden(id) ||
|
||||
app.sanitizer.isObscured(id)
|
||||
) {
|
||||
sendPlaceholder(id, this)
|
||||
} else {
|
||||
sendSrc(id, this)
|
||||
|
|
@ -97,8 +101,8 @@ export default function (app: App): void {
|
|||
if (!hasTag(node, 'IMG')) {
|
||||
return
|
||||
}
|
||||
app.nodes.attachElementListener('error', node, sendImgAttrs.bind(node))
|
||||
app.nodes.attachElementListener('load', node, sendImgAttrs.bind(node))
|
||||
app.nodes.attachNodeListener(node, 'error', sendImgAttrs.bind(node))
|
||||
app.nodes.attachNodeListener(node, 'load', sendImgAttrs.bind(node))
|
||||
sendImgAttrs.call(node)
|
||||
observer.observe(node, { attributes: true, attributeFilter: ['src', 'srcset'] })
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type App from '../app/index.js'
|
||||
import { normSpaces, IN_BROWSER, getLabelAttribute, hasOpenreplayAttribute } from '../utils.js'
|
||||
import { normSpaces, IN_BROWSER, getLabelAttribute } from '../utils.js'
|
||||
import { hasTag } from '../app/guards.js'
|
||||
import { SetInputTarget, SetInputValue, SetInputChecked } from '../app/messages.gen.js'
|
||||
|
||||
|
|
@ -103,10 +103,11 @@ export default function (app: App, opts: Partial<Options>): void {
|
|||
function sendInputValue(id: number, node: TextEditableElement | HTMLSelectElement): void {
|
||||
let value = node.value
|
||||
let inputMode: InputMode = options.defaultInputMode
|
||||
if (node.type === 'password' || hasOpenreplayAttribute(node, 'hidden')) {
|
||||
|
||||
if (node.type === 'password' || app.sanitizer.isHidden(id)) {
|
||||
inputMode = InputMode.Hidden
|
||||
} else if (
|
||||
hasOpenreplayAttribute(node, 'obscured') ||
|
||||
app.sanitizer.isObscured(id) ||
|
||||
(inputMode === InputMode.Plain &&
|
||||
((options.obscureInputNumbers && node.type !== 'date' && /\d\d\d\d/.test(value)) ||
|
||||
(options.obscureInputDates && node.type === 'date') ||
|
||||
|
|
|
|||
|
|
@ -1,30 +1,39 @@
|
|||
import type App from '../app/index.js'
|
||||
import { SetViewportScroll, SetNodeScroll } from '../app/messages.gen.js'
|
||||
import { isElementNode, isRootNode } from '../app/guards.js'
|
||||
import { isNode, isElementNode, isRootNode, isDocument } from '../app/guards.js'
|
||||
|
||||
function getDocumentScroll(doc: Document): [number, number] {
|
||||
const win = doc.defaultView
|
||||
return [
|
||||
(win && win.pageXOffset) ||
|
||||
(doc.documentElement && doc.documentElement.scrollLeft) ||
|
||||
(doc.body && doc.body.scrollLeft) ||
|
||||
0,
|
||||
(win && win.pageYOffset) ||
|
||||
(doc.documentElement && doc.documentElement.scrollTop) ||
|
||||
(doc.body && doc.body.scrollTop) ||
|
||||
0,
|
||||
]
|
||||
}
|
||||
|
||||
export default function (app: App): void {
|
||||
let documentScroll = false
|
||||
const nodeScroll: Map<Node, [number, number]> = new Map()
|
||||
|
||||
function setNodeScroll(target: EventTarget | null) {
|
||||
if (target instanceof Element) {
|
||||
if (!isNode(target)) {
|
||||
return
|
||||
}
|
||||
if (isElementNode(target)) {
|
||||
nodeScroll.set(target, [target.scrollLeft, target.scrollTop])
|
||||
}
|
||||
if (isDocument(target)) {
|
||||
nodeScroll.set(target, getDocumentScroll(target))
|
||||
}
|
||||
}
|
||||
|
||||
const sendSetViewportScroll = app.safe((): void =>
|
||||
app.send(
|
||||
SetViewportScroll(
|
||||
window.pageXOffset ||
|
||||
(document.documentElement && document.documentElement.scrollLeft) ||
|
||||
(document.body && document.body.scrollLeft) ||
|
||||
0,
|
||||
window.pageYOffset ||
|
||||
(document.documentElement && document.documentElement.scrollTop) ||
|
||||
(document.body && document.body.scrollTop) ||
|
||||
0,
|
||||
),
|
||||
),
|
||||
app.send(SetViewportScroll(...getDocumentScroll(document))),
|
||||
)
|
||||
|
||||
const sendSetNodeScroll = app.safe((s: [number, number], node: Node): void => {
|
||||
|
|
@ -42,11 +51,12 @@ export default function (app: App): void {
|
|||
})
|
||||
|
||||
app.nodes.attachNodeCallback((node, isStart) => {
|
||||
// MBTODO: iterate over all the nodes on start instead of using isStart hack
|
||||
if (isStart && isElementNode(node) && node.scrollLeft + node.scrollTop > 0) {
|
||||
nodeScroll.set(node, [node.scrollLeft, node.scrollTop])
|
||||
} else if (isRootNode(node)) {
|
||||
// scroll is not-composed event (https://javascript.info/shadow-dom-events)
|
||||
app.attachEventListener(node, 'scroll', (e: Event): void => {
|
||||
app.nodes.attachNodeListener(node, 'scroll', (e: Event): void => {
|
||||
setNodeScroll(e.target)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,14 @@
|
|||
export function timestamp(): number {
|
||||
return Math.round(performance.now()) + performance.timing.navigationStart
|
||||
}
|
||||
const DEPRECATED_ATTRS = { htmlmasked: 'hidden', masked: 'obscured' }
|
||||
|
||||
export const IN_BROWSER = !(typeof window === 'undefined')
|
||||
|
||||
const navigationStart: number | false =
|
||||
(IN_BROWSER && performance.timing.navigationStart) || performance.timeOrigin
|
||||
// performance.now() is buggy in some browsers
|
||||
export const timestamp: () => number =
|
||||
IN_BROWSER && performance.now() && navigationStart
|
||||
? () => Math.round(performance.now() + navigationStart)
|
||||
: () => Date.now()
|
||||
|
||||
export const stars: (str: string) => string =
|
||||
'repeat' in String.prototype
|
||||
|
|
@ -16,8 +24,6 @@ export function isURL(s: string): boolean {
|
|||
return s.startsWith('https://') || s.startsWith('http://')
|
||||
}
|
||||
|
||||
export const IN_BROWSER = !(typeof window === 'undefined')
|
||||
|
||||
// TODO: JOIN IT WITH LOGGER somehow (use logging decorators?); Don't forget about index.js loggin when there is no logger instance.
|
||||
|
||||
export const DOCS_HOST = 'https://docs.openreplay.com'
|
||||
|
|
@ -47,19 +53,20 @@ export function getLabelAttribute(e: Element): string | null {
|
|||
return value
|
||||
}
|
||||
|
||||
export function hasOpenreplayAttribute(e: Element, name: string): boolean {
|
||||
const newName = `data-openreplay-${name}`
|
||||
export function hasOpenreplayAttribute(e: Element, attr: string): boolean {
|
||||
const newName = `data-openreplay-${attr}`
|
||||
if (e.hasAttribute(newName)) {
|
||||
// @ts-ignore
|
||||
if (DEPRECATED_ATTRS[attr]) {
|
||||
deprecationWarn(
|
||||
`"${newName}" attribute`,
|
||||
// @ts-ignore
|
||||
`"${DEPRECATED_ATTRS[attr] as string}" attribute`,
|
||||
'/installation/sanitize-data',
|
||||
)
|
||||
}
|
||||
return true
|
||||
}
|
||||
const oldName = `data-asayer-${name}`
|
||||
if (e.hasAttribute(oldName)) {
|
||||
deprecationWarn(
|
||||
`"${oldName}" attribute`,
|
||||
`"${newName}" attribute`,
|
||||
'/installation/sanitize-data',
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ export default class BatchWriter {
|
|||
return
|
||||
}
|
||||
|
||||
// MBTODO: move service-messages creation to webworker
|
||||
// MBTODO: move service-messages creation methods to webworker
|
||||
const batchMetadata: Messages.BatchMetadata = [
|
||||
Messages.Type.BatchMetadata,
|
||||
1,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ const express = require('express');
|
|||
const socket = require("./servers/websocket");
|
||||
const {request_logger} = require("./utils/helper");
|
||||
|
||||
const HOST = '0.0.0.0';
|
||||
const debug = process.env.debug === "1" || false;
|
||||
const HOST = process.env.LISTEN_HOST || '0.0.0.0';
|
||||
const PORT = process.env.LISTEN_PORT || 9001;
|
||||
|
||||
const wsapp = express();
|
||||
|
|
|
|||
|
|
@ -242,6 +242,7 @@ module.exports = {
|
|||
start: (server, prefix) => {
|
||||
createSocketIOServer(server, prefix);
|
||||
io.on('connection', async (socket) => {
|
||||
socket.on(EVENTS_DEFINITION.listen.ERROR, err => errorHandler(EVENTS_DEFINITION.listen.ERROR, err));
|
||||
debug && console.log(`WS started:${socket.id}, Query:${JSON.stringify(socket.handshake.query)}`);
|
||||
socket._connectedAt = new Date();
|
||||
socket.peerId = socket.handshake.query.peerId;
|
||||
|
|
@ -308,7 +309,6 @@ module.exports = {
|
|||
|
||||
socket.on(EVENTS_DEFINITION.listen.CONNECT_ERROR, err => errorHandler(EVENTS_DEFINITION.listen.CONNECT_ERROR, err));
|
||||
socket.on(EVENTS_DEFINITION.listen.CONNECT_FAILED, err => errorHandler(EVENTS_DEFINITION.listen.CONNECT_FAILED, err));
|
||||
socket.on(EVENTS_DEFINITION.listen.ERROR, err => errorHandler(EVENTS_DEFINITION.listen.ERROR, err));
|
||||
|
||||
socket.onAny(async (eventName, ...args) => {
|
||||
if (Object.values(EVENTS_DEFINITION.listen).indexOf(eventName) >= 0) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue