Compare commits

...
Sign in to create a new pull request.

4 commits

Author SHA1 Message Date
nick-delirium
aefa251329
tracker: react native "sendMessage" hook for gql integration 2024-12-27 13:55:39 +01:00
nick-delirium
a6ede1fdaf
ui: name for gql msg 2024-12-26 15:07:49 +01:00
nick-delirium
d91e98ff99
new mobile gql message 2024-12-26 15:07:48 +01:00
nick-delirium
53424b4001
graphql events support for mobile player, react-native connector 2024-12-26 15:07:48 +01:00
29 changed files with 484 additions and 158 deletions

View file

@ -6,9 +6,9 @@ func IsReplayerType(id int) bool {
}
func IsMobileType(id int) bool {
return 90 == id || 91 == id || 92 == id || 93 == id || 94 == id || 95 == id || 96 == id || 97 == id || 98 == id || 100 == id || 101 == id || 102 == id || 103 == id || 104 == id || 105 == id || 106 == id || 107 == id || 110 == id || 111 == id
return 90 == id || 91 == id || 92 == id || 93 == id || 94 == id || 95 == id || 96 == id || 97 == id || 98 == id || 100 == id || 101 == id || 102 == id || 103 == id || 104 == id || 105 == id || 106 == id || 107 == id || 110 == id || 111 == id || 89 == id
}
func IsDOMType(id int) bool {
return 0 == id || 4 == id || 5 == id || 6 == id || 7 == id || 8 == id || 9 == id || 10 == id || 11 == id || 12 == id || 13 == id || 14 == id || 15 == id || 16 == id || 18 == id || 19 == id || 20 == id || 37 == id || 38 == id || 49 == id || 50 == id || 51 == id || 43 == id || 52 == id || 54 == id || 55 == id || 57 == id || 58 == id || 59 == id || 60 == id || 61 == id || 67 == id || 68 == id || 69 == id || 70 == id || 71 == id || 72 == id || 73 == id || 74 == id || 75 == id || 76 == id || 77 == id || 113 == id || 114 == id || 117 == id || 118 == id || 119 == id || 122 == id || 93 == id || 96 == id || 100 == id || 101 == id || 102 == id || 103 == id || 104 == id || 105 == id || 106 == id || 111 == id
return 0 == id || 4 == id || 5 == id || 6 == id || 7 == id || 8 == id || 9 == id || 10 == id || 11 == id || 12 == id || 13 == id || 14 == id || 15 == id || 16 == id || 18 == id || 19 == id || 20 == id || 37 == id || 38 == id || 49 == id || 50 == id || 51 == id || 43 == id || 52 == id || 54 == id || 55 == id || 57 == id || 58 == id || 59 == id || 60 == id || 61 == id || 67 == id || 68 == id || 69 == id || 70 == id || 71 == id || 72 == id || 73 == id || 74 == id || 75 == id || 76 == id || 77 == id || 113 == id || 114 == id || 117 == id || 118 == id || 119 == id || 122 == id || 93 == id || 96 == id || 100 == id || 101 == id || 102 == id || 103 == id || 104 == id || 105 == id || 106 == id || 111 == id || 89 == id
}

View file

@ -58,6 +58,9 @@ func GetTimestamp(message Message) uint64 {
case *MobileIssueEvent:
return msg.Timestamp
case *MobileGraphQL:
return msg.Timestamp
}
return uint64(message.Meta().Timestamp)
}

View file

@ -117,6 +117,7 @@ const (
MsgMobileBatchMeta = 107
MsgMobilePerformanceAggregated = 110
MsgMobileIssueEvent = 111
MsgMobileGraphQL = 89
)
type Timestamp struct {
@ -3210,3 +3211,36 @@ func (msg *MobileIssueEvent) Decode() Message {
func (msg *MobileIssueEvent) TypeID() int {
return 111
}
type MobileGraphQL struct {
message
Timestamp uint64
Length uint64
OperationKind string
OperationName string
Variables string
Response string
Duration uint64
}
func (msg *MobileGraphQL) Encode() []byte {
buf := make([]byte, 71+len(msg.OperationKind)+len(msg.OperationName)+len(msg.Variables)+len(msg.Response))
buf[0] = 89
p := 1
p = WriteUint(msg.Timestamp, buf, p)
p = WriteUint(msg.Length, buf, p)
p = WriteString(msg.OperationKind, buf, p)
p = WriteString(msg.OperationName, buf, p)
p = WriteString(msg.Variables, buf, p)
p = WriteString(msg.Response, buf, p)
p = WriteUint(msg.Duration, buf, p)
return buf[:p]
}
func (msg *MobileGraphQL) Decode() Message {
return msg
}
func (msg *MobileGraphQL) TypeID() int {
return 89
}

View file

@ -2055,6 +2055,33 @@ func DecodeMobileIssueEvent(reader BytesReader) (Message, error) {
return msg, err
}
func DecodeMobileGraphQL(reader BytesReader) (Message, error) {
var err error = nil
msg := &MobileGraphQL{}
if msg.Timestamp, err = reader.ReadUint(); err != nil {
return nil, err
}
if msg.Length, err = reader.ReadUint(); err != nil {
return nil, err
}
if msg.OperationKind, err = reader.ReadString(); err != nil {
return nil, err
}
if msg.OperationName, err = reader.ReadString(); err != nil {
return nil, err
}
if msg.Variables, err = reader.ReadString(); err != nil {
return nil, err
}
if msg.Response, err = reader.ReadString(); err != nil {
return nil, err
}
if msg.Duration, err = reader.ReadUint(); err != nil {
return nil, err
}
return msg, err
}
func ReadMessage(t uint64, reader BytesReader) (Message, error) {
switch t {
case 0:
@ -2287,6 +2314,8 @@ func ReadMessage(t uint64, reader BytesReader) (Message, error) {
return DecodeMobilePerformanceAggregated(reader)
case 111:
return DecodeMobileIssueEvent(reader)
case 89:
return DecodeMobileGraphQL(reader)
}
return nil, fmt.Errorf("unknown message code: %v", t)
}

View file

@ -1150,3 +1150,16 @@ class MobileIssueEvent(Message):
self.payload = payload
class MobileGraphQL(Message):
__id__ = 89
def __init__(self, timestamp, length, operation_kind, operation_name, variables, response, duration):
self.timestamp = timestamp
self.length = length
self.operation_kind = operation_kind
self.operation_name = operation_name
self.variables = variables
self.response = response
self.duration = duration

View file

@ -1723,3 +1723,24 @@ cdef class MobileIssueEvent(PyMessage):
self.payload = payload
cdef class MobileGraphQL(PyMessage):
cdef public int __id__
cdef public unsigned long timestamp
cdef public unsigned long length
cdef public str operation_kind
cdef public str operation_name
cdef public str variables
cdef public str response
cdef public unsigned long duration
def __init__(self, unsigned long timestamp, unsigned long length, str operation_kind, str operation_name, str variables, str response, unsigned long duration):
self.__id__ = 89
self.timestamp = timestamp
self.length = length
self.operation_kind = operation_kind
self.operation_name = operation_name
self.variables = variables
self.response = response
self.duration = duration

View file

@ -1007,3 +1007,14 @@ class MessageCodec(Codec):
payload=self.read_string(reader)
)
if message_id == 89:
return MobileGraphQL(
timestamp=self.read_uint(reader),
length=self.read_uint(reader),
operation_kind=self.read_string(reader),
operation_name=self.read_string(reader),
variables=self.read_string(reader),
response=self.read_string(reader),
duration=self.read_uint(reader)
)

View file

@ -1105,3 +1105,14 @@ cdef class MessageCodec:
payload=self.read_string(reader)
)
if message_id == 89:
return MobileGraphQL(
timestamp=self.read_uint(reader),
length=self.read_uint(reader),
operation_kind=self.read_string(reader),
operation_name=self.read_string(reader),
variables=self.read_string(reader),
response=self.read_string(reader),
duration=self.read_uint(reader)
)

View file

@ -23,12 +23,12 @@ import {
NETWORK,
OVERVIEW,
PERFORMANCE,
STACKEVENTS
STACKEVENTS,
GRAPHQL,
} from 'App/mstore/uiPlayerStore';
import { useStore } from 'App/mstore';
import { session as sessionRoute, withSiteId } from 'App/routes';
import { SummaryButton } from 'Components/Session_/Player/Controls/Controls';
import { MobEventsList, WebEventsList } from "../../../Session_/Player/Controls/EventsList";
import useShortcuts from '../ReplayPlayer/useShortcuts';
export const SKIP_INTERVALS = {
@ -261,6 +261,12 @@ const DevtoolsButtons = observer(({
active={bottomBlock === STACKEVENTS}
label="Events"
/>
<ControlButton
disabled={messagesLoading}
onClick={() => toggleBottomTools(GRAPHQL)}
active={bottomBlock === GRAPHQL}
label="GraphQL"
/>
<ControlButton
popover={
<div className={'flex gap-2 items-center'}>

View file

@ -7,10 +7,8 @@ import { observer } from 'mobx-react-lite';
import styles from 'Components/Session_/playerBlock.module.css';
interface IProps {
fullscreen: boolean;
sessionId: string;
fullscreen?: boolean;
activeTab: string;
jiraConfig: Record<string, any>
fullView?: boolean
setActiveTab: (tab: string) => void
}
@ -42,4 +40,4 @@ function PlayerBlock(props: IProps) {
);
}
export default observer(PlayerBlock)
export default observer(PlayerBlock)

View file

@ -10,6 +10,7 @@ import {
PERFORMANCE,
EXCEPTIONS,
OVERVIEW,
GRAPHQL,
} from 'App/mstore/uiPlayerStore';
import { MobileNetworkPanel } from 'Shared/DevTools/NetworkPanel';
import { MobilePerformance } from 'Components/Session_/Performance';
@ -18,6 +19,7 @@ import MobileControls from './MobileControls';
import Overlay from './MobileOverlay'
import stl from 'Components/Session_/Player/player.module.css';
import { MobileOverviewPanel } from 'Components/Session_/OverviewPanel';
import GraphQL from 'Components/Session_/GraphQL';
import MobileConsolePanel from 'Shared/DevTools/ConsolePanel/MobileConsolePanel';
import { MobilePlayerContext } from 'App/components/Session/playerContext';
import { MobileStackEventPanel } from 'Shared/DevTools/StackEventPanel';
@ -32,7 +34,6 @@ interface IProps {
isMultiview?: boolean;
activeTab: string;
setActiveTab: (tab: string) => void;
bottomBlock: any;
fullscreen?: boolean;
}
@ -146,6 +147,7 @@ function Player(props: IProps) {
{bottomBlock === NETWORK && <MobileNetworkPanel panelHeight={panelHeight} />}
{bottomBlock === PERFORMANCE && <MobilePerformance />}
{bottomBlock === EXCEPTIONS && <MobileExceptions />}
{bottomBlock === GRAPHQL && <GraphQL isMobile panelHeight={panelHeight} />}
</div>
)}
{!fullView ? (

View file

@ -2,13 +2,14 @@ import { Duration } from 'luxon';
import { observer } from 'mobx-react-lite';
import React, { useEffect } from 'react';
import { PlayerContext } from 'App/components/Session/playerContext';
import { PlayerContext, MobilePlayerContext } from 'App/components/Session/playerContext';
import { getRE } from 'App/utils';
import TimeTable from 'Components/shared/DevTools/TimeTable';
import { CloseButton, Input, NoContent, SlideModal } from 'UI';
import BottomBlock from '../BottomBlock';
import GQLDetails from './GQLDetails';
import { IWebPlayerStore, IIOSPlayerStore } from 'App/player/create';
export function renderStart(r) {
return (
@ -28,15 +29,125 @@ export function renderStart(r) {
);
}
function renderDefaultStatus() {
return '2xx-3xx';
interface Props {
onFilterChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
filteredList: Array<any>;
current: any;
renderName: (item: any) => React.ReactNode;
panelHeight: number;
closeModal: () => void;
currentIndex: number;
setCurrent: (item: any, index: number) => void;
lastActiveItem?: any;
onJump?: ({ time }: { time: number }) => void;
}
function GraphQL({ panelHeight }: { panelHeight: number }) {
const { player, store } = React.useContext(PlayerContext);
const { time, livePlay, tabStates, currentTab } = store.get();
const { graphqlList: list = [], graphqlListNow: listNow = [] } =
tabStates[currentTab];
const GraphQLComponent = ({
onFilterChange,
filteredList,
current,
renderName,
panelHeight,
closeModal,
currentIndex,
setCurrent,
lastActiveItem,
onJump,
}: Props) => {
return (
<React.Fragment>
<SlideModal
size="middle"
right
title={
<div className="flex justify-between">
<h1>GraphQL</h1>
<div className="flex items-center">
<CloseButton onClick={closeModal} size="18" className="ml-2" />
</div>
</div>
}
isDisplayed={current != null}
content={
current && (
<GQLDetails
gql={current}
first={currentIndex === 0}
last={currentIndex === filteredList.length - 1}
/>
)
}
onClose={closeModal}
/>
<BottomBlock>
<BottomBlock.Header>
<span className="font-semibold color-gray-medium mr-4">GraphQL</span>
<div className="flex items-center">
<Input
// className="input-small"
placeholder="Filter by name or type"
icon="search"
name="filter"
onChange={onFilterChange}
/>
</div>
</BottomBlock.Header>
<BottomBlock.Content>
<NoContent
size="small"
title="No recordings found"
show={filteredList.length === 0}
>
<TimeTable
rows={filteredList}
onRowClick={setCurrent}
tableHeight={panelHeight - 102}
hoverable
activeIndex={lastActiveItem}
onJump={onJump}
>
{[
{
label: 'Start',
width: 90,
render: renderStart,
},
{
label: 'Type',
dataKey: 'operationKind',
width: 80,
},
{
label: 'Name',
width: 300,
render: renderName,
},
]}
</TimeTable>
</NoContent>
</BottomBlock.Content>
</BottomBlock>
</React.Fragment>
);
};
function GraphQL({ panelHeight, isMobile }: { panelHeight: number, isMobile?: boolean }) {
const context = isMobile ? MobilePlayerContext : PlayerContext;
// @ts-ignore
const { player, store } = React.useContext(context);
const { time, livePlay } = store.get();
let list: any[] = [];
let listNow: any[] = [];
if (isMobile) {
const { graphqlList = [], graphqlListNow = [] } = (store as unknown as IIOSPlayerStore).get();
list = graphqlList;
listNow = graphqlListNow;
} else {
const { tabStates, currentTab } = (store as unknown as IWebPlayerStore).get();
const { graphqlList = [], graphqlListNow = [] } = tabStates[currentTab];
list = graphqlList;
listNow = graphqlListNow;
}
const defaultState = {
filter: '',
@ -121,79 +232,18 @@ function GraphQL({ panelHeight }: { panelHeight: number }) {
const { current, currentIndex, filteredList, lastActiveItem } = state;
return (
<React.Fragment>
<SlideModal
size="middle"
right
title={
<div className="flex justify-between">
<h1>GraphQL</h1>
<div className="flex items-center">
<CloseButton onClick={closeModal} size="18" className="ml-2" />
</div>
</div>
}
isDisplayed={current != null}
content={
current && (
<GQLDetails
gql={current}
first={currentIndex === 0}
last={currentIndex === filteredList.length - 1}
/>
)
}
onClose={closeModal}
/>
<BottomBlock>
<BottomBlock.Header>
<span className="font-semibold color-gray-medium mr-4">GraphQL</span>
<div className="flex items-center">
<Input
// className="input-small"
placeholder="Filter by name or type"
icon="search"
name="filter"
onChange={onFilterChange}
/>
</div>
</BottomBlock.Header>
<BottomBlock.Content>
<NoContent
size="small"
title="No recordings found"
show={filteredList.length === 0}
>
<TimeTable
rows={filteredList}
onRowClick={setCurrent}
tableHeight={panelHeight - 102}
hoverable
activeIndex={lastActiveItem}
onJump={onJump}
>
{[
{
label: 'Start',
width: 90,
render: renderStart,
},
{
label: 'Type',
dataKey: 'operationKind',
width: 80,
},
{
label: 'Name',
width: 300,
render: renderName,
},
]}
</TimeTable>
</NoContent>
</BottomBlock.Content>
</BottomBlock>
</React.Fragment>
<GraphQLComponent
onFilterChange={onFilterChange}
filteredList={filteredList}
current={current}
renderName={renderName}
panelHeight={panelHeight}
closeModal={closeModal}
currentIndex={currentIndex}
setCurrent={setCurrent}
lastActiveItem={lastActiveItem}
onJump={onJump}
/>
);
}

View file

@ -8,7 +8,8 @@ const SIMPLE_LIST_NAMES = [
"exceptions",
"profiles",
"frustrations",
"performance"
"performance",
"graphql",
] as const
const MARKED_LIST_NAMES = [ "log", "resource", "fetch", "stack", "websocket" ] as const
@ -89,4 +90,4 @@ export default class Lists {
) as State
}
}
}

View file

@ -286,6 +286,9 @@ export default class IOSMessageManager implements IMessageManager {
// @ts-ignore
this.lists.lists.log.append(Log(log));
break;
case MType.MobileGraphQl:
this.lists.lists.graphql.insert(msg);
break;
default:
console.log(msg);
// stuff

View file

@ -997,6 +997,26 @@ export default class RawMessageReader extends PrimitiveReader {
};
}
case 89: {
const timestamp = this.readUint(); if (timestamp === null) { return resetPointer() }
const length = this.readUint(); if (length === null) { return resetPointer() }
const operationKind = this.readString(); if (operationKind === null) { return resetPointer() }
const operationName = this.readString(); if (operationName === null) { return resetPointer() }
const variables = this.readString(); if (variables === null) { return resetPointer() }
const response = this.readString(); if (response === null) { return resetPointer() }
const duration = this.readUint(); if (duration === null) { return resetPointer() }
return {
tp: MType.MobileGraphQl,
timestamp,
length,
operationKind,
operationName,
variables,
response,
duration,
};
}
default:
throw new Error(`Unrecognizable message type: ${ tp }; Pointer at the position ${this.p} of ${this.buf.length}`)
}

View file

@ -3,7 +3,7 @@
import { MType } from './raw.gen'
const IOS_TYPES = [90,91,92,93,94,95,96,97,98,100,101,102,103,104,105,106,107,110,111]
const IOS_TYPES = [90,91,92,93,94,95,96,97,98,100,101,102,103,104,105,106,107,110,111,89]
const DOM_TYPES = [0,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19,20,37,38,49,50,51,43,52,54,55,57,58,59,60,61,67,68,69,70,71,72,73,74,75,76,77,113,114,117,118,119,122]
export function isDOMType(t: MType) {
return DOM_TYPES.includes(t)

View file

@ -80,6 +80,7 @@ import type {
RawMobileNetworkCall,
RawMobileSwipeEvent,
RawMobileIssueEvent,
RawMobileGraphQl,
} from './raw.gen'
export type Message = RawMessage & Timed
@ -237,3 +238,5 @@ export type MobileSwipeEvent = RawMobileSwipeEvent & Timed
export type MobileIssueEvent = RawMobileIssueEvent & Timed
export type MobileGraphQl = RawMobileGraphQl & Timed

View file

@ -78,6 +78,7 @@ export const enum MType {
MobileNetworkCall = 105,
MobileSwipeEvent = 106,
MobileIssueEvent = 111,
MobileGraphQl = 89,
}
@ -646,5 +647,16 @@ export interface RawMobileIssueEvent {
payload: string,
}
export interface RawMobileGraphQl {
tp: MType.MobileGraphQl,
timestamp: number,
length: number,
operationKind: string,
operationName: string,
variables: string,
response: string,
duration: number,
}
export type RawMessage = RawTimestamp | RawSetPageLocationDeprecated | RawSetViewportSize | RawSetViewportScroll | RawCreateDocument | RawCreateElementNode | RawCreateTextNode | RawMoveNode | RawRemoveNode | RawSetNodeAttribute | RawRemoveNodeAttribute | RawSetNodeData | RawSetCssData | RawSetNodeScroll | RawSetInputValue | RawSetInputChecked | RawMouseMove | RawNetworkRequestDeprecated | RawConsoleLog | RawCssInsertRule | RawCssDeleteRule | RawFetch | RawProfiler | RawOTable | RawReduxDeprecated | RawVuex | RawMobX | RawNgRx | RawGraphQlDeprecated | RawPerformanceTrack | RawStringDictDeprecated | RawSetNodeAttributeDictDeprecated | RawStringDict | RawSetNodeAttributeDict | RawResourceTimingDeprecated | RawConnectionInformation | RawSetPageVisibility | RawLoadFontFace | RawSetNodeFocus | RawLongTask | RawSetNodeAttributeURLBased | RawSetCssDataURLBased | RawCssInsertRuleURLBased | RawMouseClick | RawMouseClickDeprecated | RawCreateIFrameDocument | RawAdoptedSsReplaceURLBased | RawAdoptedSsReplace | RawAdoptedSsInsertRuleURLBased | RawAdoptedSsInsertRule | RawAdoptedSsDeleteRule | RawAdoptedSsAddOwner | RawAdoptedSsRemoveOwner | RawZustand | RawNetworkRequest | RawWsChannel | RawSelectionChange | RawMouseThrashing | RawResourceTiming | RawTabChange | RawTabData | RawCanvasNode | RawTagTrigger | RawRedux | RawSetPageLocation | RawGraphQl | RawMobileEvent | RawMobileScreenChanges | RawMobileClickEvent | RawMobileInputEvent | RawMobilePerformanceEvent | RawMobileLog | RawMobileInternalError | RawMobileNetworkCall | RawMobileSwipeEvent | RawMobileIssueEvent;
export type RawMessage = RawTimestamp | RawSetPageLocationDeprecated | RawSetViewportSize | RawSetViewportScroll | RawCreateDocument | RawCreateElementNode | RawCreateTextNode | RawMoveNode | RawRemoveNode | RawSetNodeAttribute | RawRemoveNodeAttribute | RawSetNodeData | RawSetCssData | RawSetNodeScroll | RawSetInputValue | RawSetInputChecked | RawMouseMove | RawNetworkRequestDeprecated | RawConsoleLog | RawCssInsertRule | RawCssDeleteRule | RawFetch | RawProfiler | RawOTable | RawReduxDeprecated | RawVuex | RawMobX | RawNgRx | RawGraphQlDeprecated | RawPerformanceTrack | RawStringDictDeprecated | RawSetNodeAttributeDictDeprecated | RawStringDict | RawSetNodeAttributeDict | RawResourceTimingDeprecated | RawConnectionInformation | RawSetPageVisibility | RawLoadFontFace | RawSetNodeFocus | RawLongTask | RawSetNodeAttributeURLBased | RawSetCssDataURLBased | RawCssInsertRuleURLBased | RawMouseClick | RawMouseClickDeprecated | RawCreateIFrameDocument | RawAdoptedSsReplaceURLBased | RawAdoptedSsReplace | RawAdoptedSsInsertRuleURLBased | RawAdoptedSsInsertRule | RawAdoptedSsDeleteRule | RawAdoptedSsAddOwner | RawAdoptedSsRemoveOwner | RawZustand | RawNetworkRequest | RawWsChannel | RawSelectionChange | RawMouseThrashing | RawResourceTiming | RawTabChange | RawTabData | RawCanvasNode | RawTagTrigger | RawRedux | RawSetPageLocation | RawGraphQl | RawMobileEvent | RawMobileScreenChanges | RawMobileClickEvent | RawMobileInputEvent | RawMobilePerformanceEvent | RawMobileLog | RawMobileInternalError | RawMobileNetworkCall | RawMobileSwipeEvent | RawMobileIssueEvent | RawMobileGraphQl;

View file

@ -79,4 +79,5 @@ export const TP_MAP = {
105: MType.MobileNetworkCall,
106: MType.MobileSwipeEvent,
111: MType.MobileIssueEvent,
89: MType.MobileGraphQl,
} as const

View file

@ -611,4 +611,4 @@ message 127, 'SessionSearch', :tracker => false, :replayer => false do
uint 'Partition'
end
# FREE 2, 34, 35, 36, 65, 85, 86, 87, 88, 89
# FREE 2, 34, 35, 36, 65, 85, 86, 87, 88

View file

@ -168,3 +168,13 @@ message 111, 'MobileIssueEvent', :replayer => true do
string 'Context'
string 'Payload'
end
message 89, 'MobileGraphQL', :replayer => true do
uint 'Timestamp'
uint 'Length'
string 'OperationKind'
string 'OperationName'
string 'Variables'
string 'Response'
uint 'Duration'
end

View file

@ -9,3 +9,31 @@ npm install @openreplay/react-native
```
Please see [the documentation](https://docs.openreplay.com/en/rn-sdk/) for more information about usage.
### React Native and GraphQL
You can use [@openreplay/tracker-graphql](https://www.npmjs.com/package/@openreplay/tracker-graphql) to handle graphql events in react-native applications as well, via
```js
import { createRelayMiddleware } from '@openreplay/tracker-graphql';
const appWrapper = {
active: () => true,
send: (gqlMsg) => {
const type = 'gql';
const msg = JSON.stringify({
operationKind: gqlMsg[1],
operationName: gqlMsg[2],
variables: gqlMsg[3],
response: gqlMsg[4],
duration: gqlMsg[5],
});
Openreplay.sendCustomMessage(type, msg);
},
};
// @ts-ignore - emulating web tracker here for middleware
const middleware = createRelayMiddleware(appWrapper);
// .. connect to relay network layer
```

View file

@ -9,14 +9,14 @@ PODS:
- hermes-engine (0.74.0):
- hermes-engine/Pre-built (= 0.74.0)
- hermes-engine/Pre-built (0.74.0)
- Openreplay (1.0.15):
- Openreplay (1.0.17):
- DeviceKit
- SWCompression
- openreplay-react-native (0.6.11):
- DoubleConversion
- glog
- hermes-engine
- Openreplay (= 1.0.15)
- Openreplay (= 1.0.17)
- RCT-Folly (= 2024.01.01.00)
- RCTRequired
- RCTTypeSafety
@ -1423,8 +1423,8 @@ SPEC CHECKSUMS:
fmt: 4c2741a687cc09f0634a2e2c72a838b99f1ff120
glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2
hermes-engine: 6eae7edb2f563ee41d7c1f91f4f2e57c26d8a5c3
Openreplay: ae72a7ca1a05d7da026b7ee8f4f84dcdfaa44021
openreplay-react-native: 0cfa1842c5b2457f6e9d5fa564f746192317b20c
Openreplay: 2bffa68a1606c95cd04618f0095864649d076d40
openreplay-react-native: e77361570814a3c92483423b463011536b2346b6
RCT-Folly: 045d6ecaa59d826c5736dfba0b2f4083ff8d79df
RCTDeprecation: 3ca8b6c36bfb302e1895b72cfe7db0de0c92cd47
RCTRequired: 9fc183af555fd0c89a366c34c1ae70b7e03b1dc5

View file

@ -11,9 +11,9 @@
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
1B3DD9657AF7850CB6FA1B53 /* libPods-ReactNativeExample-ReactNativeExampleTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 68F0ED938F2BC97A9BFD4365 /* libPods-ReactNativeExample-ReactNativeExampleTests.a */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
8CFDEAD4DCE52688468D5C80 /* libPods-ReactNativeExample-ReactNativeExampleTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A889A4784F36428D3856494 /* libPods-ReactNativeExample-ReactNativeExampleTests.a */; };
C7F3F3B67AF0BA29F7DAC50F /* libPods-ReactNativeExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F4C922963FC6C79114841BE6 /* libPods-ReactNativeExample.a */; };
DA89C15737C59610E15C36FD /* libPods-ReactNativeExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 900A29F732B0D23F50779293 /* libPods-ReactNativeExample.a */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -30,6 +30,7 @@
00E356EE1AD99517003FC87E /* ReactNativeExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ReactNativeExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
00E356F21AD99517003FC87E /* ReactNativeExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ReactNativeExampleTests.m; sourceTree = "<group>"; };
01E603FB97835EE257543318 /* Pods-ReactNativeExample-ReactNativeExampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeExample-ReactNativeExampleTests.release.xcconfig"; path = "Target Support Files/Pods-ReactNativeExample-ReactNativeExampleTests/Pods-ReactNativeExample-ReactNativeExampleTests.release.xcconfig"; sourceTree = "<group>"; };
13B07F961A680F5B00A75B9A /* ReactNativeExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ReactNativeExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = ReactNativeExample/AppDelegate.h; sourceTree = "<group>"; };
13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = ReactNativeExample/AppDelegate.mm; sourceTree = "<group>"; };
@ -37,14 +38,13 @@
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = ReactNativeExample/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = ReactNativeExample/main.m; sourceTree = "<group>"; };
13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = PrivacyInfo.xcprivacy; path = ReactNativeExample/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
212B4F1F0ABCF375B1354A0B /* Pods-ReactNativeExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeExample.debug.xcconfig"; path = "Target Support Files/Pods-ReactNativeExample/Pods-ReactNativeExample.debug.xcconfig"; sourceTree = "<group>"; };
5A889A4784F36428D3856494 /* libPods-ReactNativeExample-ReactNativeExampleTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ReactNativeExample-ReactNativeExampleTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
6102A46EF47DB7D6762C9A2B /* Pods-ReactNativeExample-ReactNativeExampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeExample-ReactNativeExampleTests.release.xcconfig"; path = "Target Support Files/Pods-ReactNativeExample-ReactNativeExampleTests/Pods-ReactNativeExample-ReactNativeExampleTests.release.xcconfig"; sourceTree = "<group>"; };
4ACA5716B98C6ABE43A0766D /* Pods-ReactNativeExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeExample.debug.xcconfig"; path = "Target Support Files/Pods-ReactNativeExample/Pods-ReactNativeExample.debug.xcconfig"; sourceTree = "<group>"; };
51D080F1BD4B263A1A494122 /* Pods-ReactNativeExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeExample.release.xcconfig"; path = "Target Support Files/Pods-ReactNativeExample/Pods-ReactNativeExample.release.xcconfig"; sourceTree = "<group>"; };
68F0ED938F2BC97A9BFD4365 /* libPods-ReactNativeExample-ReactNativeExampleTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ReactNativeExample-ReactNativeExampleTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
7237FA23C741052532F892F9 /* Pods-ReactNativeExample-ReactNativeExampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeExample-ReactNativeExampleTests.debug.xcconfig"; path = "Target Support Files/Pods-ReactNativeExample-ReactNativeExampleTests/Pods-ReactNativeExample-ReactNativeExampleTests.debug.xcconfig"; sourceTree = "<group>"; };
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = ReactNativeExample/LaunchScreen.storyboard; sourceTree = "<group>"; };
837561A5C741BC8B67930889 /* Pods-ReactNativeExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeExample.release.xcconfig"; path = "Target Support Files/Pods-ReactNativeExample/Pods-ReactNativeExample.release.xcconfig"; sourceTree = "<group>"; };
EA74B193F79CA13EE3B460C6 /* Pods-ReactNativeExample-ReactNativeExampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativeExample-ReactNativeExampleTests.debug.xcconfig"; path = "Target Support Files/Pods-ReactNativeExample-ReactNativeExampleTests/Pods-ReactNativeExample-ReactNativeExampleTests.debug.xcconfig"; sourceTree = "<group>"; };
900A29F732B0D23F50779293 /* libPods-ReactNativeExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ReactNativeExample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
F4C922963FC6C79114841BE6 /* libPods-ReactNativeExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ReactNativeExample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -52,7 +52,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
8CFDEAD4DCE52688468D5C80 /* libPods-ReactNativeExample-ReactNativeExampleTests.a in Frameworks */,
1B3DD9657AF7850CB6FA1B53 /* libPods-ReactNativeExample-ReactNativeExampleTests.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -60,7 +60,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
C7F3F3B67AF0BA29F7DAC50F /* libPods-ReactNativeExample.a in Frameworks */,
DA89C15737C59610E15C36FD /* libPods-ReactNativeExample.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -102,8 +102,8 @@
isa = PBXGroup;
children = (
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
F4C922963FC6C79114841BE6 /* libPods-ReactNativeExample.a */,
5A889A4784F36428D3856494 /* libPods-ReactNativeExample-ReactNativeExampleTests.a */,
900A29F732B0D23F50779293 /* libPods-ReactNativeExample.a */,
68F0ED938F2BC97A9BFD4365 /* libPods-ReactNativeExample-ReactNativeExampleTests.a */,
);
name = Frameworks;
sourceTree = "<group>";
@ -142,10 +142,10 @@
BBD78D7AC51CEA395F1C20DB /* Pods */ = {
isa = PBXGroup;
children = (
212B4F1F0ABCF375B1354A0B /* Pods-ReactNativeExample.debug.xcconfig */,
837561A5C741BC8B67930889 /* Pods-ReactNativeExample.release.xcconfig */,
EA74B193F79CA13EE3B460C6 /* Pods-ReactNativeExample-ReactNativeExampleTests.debug.xcconfig */,
6102A46EF47DB7D6762C9A2B /* Pods-ReactNativeExample-ReactNativeExampleTests.release.xcconfig */,
4ACA5716B98C6ABE43A0766D /* Pods-ReactNativeExample.debug.xcconfig */,
51D080F1BD4B263A1A494122 /* Pods-ReactNativeExample.release.xcconfig */,
7237FA23C741052532F892F9 /* Pods-ReactNativeExample-ReactNativeExampleTests.debug.xcconfig */,
01E603FB97835EE257543318 /* Pods-ReactNativeExample-ReactNativeExampleTests.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@ -157,12 +157,12 @@
isa = PBXNativeTarget;
buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "ReactNativeExampleTests" */;
buildPhases = (
D039EC238FC4B9FDBDAFB800 /* [CP] Check Pods Manifest.lock */,
79E2EA345A351A0B80042F86 /* [CP] Check Pods Manifest.lock */,
00E356EA1AD99517003FC87E /* Sources */,
00E356EB1AD99517003FC87E /* Frameworks */,
00E356EC1AD99517003FC87E /* Resources */,
DD6933155112660ABBFB11CE /* [CP] Embed Pods Frameworks */,
1038B73ED8C88C8CDF41F1FC /* [CP] Copy Pods Resources */,
1BBDA02DD72D4004B217A05F /* [CP] Embed Pods Frameworks */,
EDC55199BC23BF9C078EF29C /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@ -178,13 +178,13 @@
isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ReactNativeExample" */;
buildPhases = (
BB963842CAFBE7B5A629B013 /* [CP] Check Pods Manifest.lock */,
1DEEBC761A9F0AD9D41C9B8F /* [CP] Check Pods Manifest.lock */,
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
35D9F844561F84987A5EA09A /* [CP] Embed Pods Frameworks */,
3862ED11E8450BD142ECCA26 /* [CP] Copy Pods Resources */,
102F54311A0D94A16229D75D /* [CP] Embed Pods Frameworks */,
9C953D85F31015264F6EA5A7 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@ -267,24 +267,7 @@
shellPath = /bin/sh;
shellScript = "set -e\n\nWITH_ENVIRONMENT=\"$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"$REACT_NATIVE_PATH/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n";
};
1038B73ED8C88C8CDF41F1FC /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ReactNativeExample-ReactNativeExampleTests/Pods-ReactNativeExample-ReactNativeExampleTests-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ReactNativeExample-ReactNativeExampleTests/Pods-ReactNativeExample-ReactNativeExampleTests-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNativeExample-ReactNativeExampleTests/Pods-ReactNativeExample-ReactNativeExampleTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
35D9F844561F84987A5EA09A /* [CP] Embed Pods Frameworks */ = {
102F54311A0D94A16229D75D /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@ -301,24 +284,24 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNativeExample/Pods-ReactNativeExample-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
3862ED11E8450BD142ECCA26 /* [CP] Copy Pods Resources */ = {
1BBDA02DD72D4004B217A05F /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ReactNativeExample/Pods-ReactNativeExample-resources-${CONFIGURATION}-input-files.xcfilelist",
"${PODS_ROOT}/Target Support Files/Pods-ReactNativeExample-ReactNativeExampleTests/Pods-ReactNativeExample-ReactNativeExampleTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ReactNativeExample/Pods-ReactNativeExample-resources-${CONFIGURATION}-output-files.xcfilelist",
"${PODS_ROOT}/Target Support Files/Pods-ReactNativeExample-ReactNativeExampleTests/Pods-ReactNativeExample-ReactNativeExampleTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNativeExample/Pods-ReactNativeExample-resources.sh\"\n";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNativeExample-ReactNativeExampleTests/Pods-ReactNativeExample-ReactNativeExampleTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
BB963842CAFBE7B5A629B013 /* [CP] Check Pods Manifest.lock */ = {
1DEEBC761A9F0AD9D41C9B8F /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@ -340,7 +323,7 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
D039EC238FC4B9FDBDAFB800 /* [CP] Check Pods Manifest.lock */ = {
79E2EA345A351A0B80042F86 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@ -362,21 +345,38 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
DD6933155112660ABBFB11CE /* [CP] Embed Pods Frameworks */ = {
9C953D85F31015264F6EA5A7 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ReactNativeExample-ReactNativeExampleTests/Pods-ReactNativeExample-ReactNativeExampleTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
"${PODS_ROOT}/Target Support Files/Pods-ReactNativeExample/Pods-ReactNativeExample-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ReactNativeExample-ReactNativeExampleTests/Pods-ReactNativeExample-ReactNativeExampleTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
"${PODS_ROOT}/Target Support Files/Pods-ReactNativeExample/Pods-ReactNativeExample-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNativeExample-ReactNativeExampleTests/Pods-ReactNativeExample-ReactNativeExampleTests-frameworks.sh\"\n";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNativeExample/Pods-ReactNativeExample-resources.sh\"\n";
showEnvVarsInLog = 0;
};
EDC55199BC23BF9C078EF29C /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ReactNativeExample-ReactNativeExampleTests/Pods-ReactNativeExample-ReactNativeExampleTests-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ReactNativeExample-ReactNativeExampleTests/Pods-ReactNativeExample-ReactNativeExampleTests-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNativeExample-ReactNativeExampleTests/Pods-ReactNativeExample-ReactNativeExampleTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
@ -412,7 +412,7 @@
/* Begin XCBuildConfiguration section */
00E356F61AD99517003FC87E /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = EA74B193F79CA13EE3B460C6 /* Pods-ReactNativeExample-ReactNativeExampleTests.debug.xcconfig */;
baseConfigurationReference = 7237FA23C741052532F892F9 /* Pods-ReactNativeExample-ReactNativeExampleTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
GCC_PREPROCESSOR_DEFINITIONS = (
@ -439,7 +439,7 @@
};
00E356F71AD99517003FC87E /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 6102A46EF47DB7D6762C9A2B /* Pods-ReactNativeExample-ReactNativeExampleTests.release.xcconfig */;
baseConfigurationReference = 01E603FB97835EE257543318 /* Pods-ReactNativeExample-ReactNativeExampleTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
COPY_PHASE_STRIP = NO;
@ -463,7 +463,7 @@
};
13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 212B4F1F0ABCF375B1354A0B /* Pods-ReactNativeExample.debug.xcconfig */;
baseConfigurationReference = 4ACA5716B98C6ABE43A0766D /* Pods-ReactNativeExample.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
@ -490,7 +490,7 @@
};
13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 837561A5C741BC8B67930889 /* Pods-ReactNativeExample.release.xcconfig */;
baseConfigurationReference = 51D080F1BD4B263A1A494122 /* Pods-ReactNativeExample.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;

View file

@ -46,6 +46,33 @@ export default function App() {
});
};
const gqlTest = () => {
const appWrapper = {
active: () => true,
send: (gqlMsg) => {
const type = 'gql';
const msg = JSON.stringify({
operationKind: gqlMsg[1],
operationName: gqlMsg[2],
variables: gqlMsg[3],
response: gqlMsg[4],
duration: gqlMsg[5],
});
Openreplay.sendCustomMessage(type, msg);
},
};
// just a mock
const mockMsg = [
'message id',
'query',
'operationName',
{ data: 'some imporatnt data' },
{ response: 'some response data' },
100,
];
appWrapper.send(mockMsg);
};
return (
<Openreplay.ORTouchTrackingView style={styles.container}>
<View style={styles.container}>
@ -69,6 +96,10 @@ export default function App() {
<Text>Request</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={gqlTest}>
<Text>GraphQL</Text>
</TouchableOpacity>
<Openreplay.ORTrackedInput
style={styles.input}
onChangeText={onChangeNumber}

View file

@ -22,6 +22,8 @@ RCT_EXTERN_METHOD(setUserID:(NSString *)userID)
RCT_EXTERN_METHOD(userAnonymousID:(NSString *)userID)
RCT_EXTERN_METHOD(sendMessage:(NSString *)msgType msg:(NSString *)msg)
RCT_EXTERN_METHOD(networkRequest:(NSString *)url
method:(NSString *)method
requestJSON:(NSString *)requestJSON

View file

@ -80,4 +80,9 @@ public class ORTrackerConnector: NSObject {
let sessionID = Openreplay.shared.getSessionID()
resolve(sessionID)
}
@objc(sendMessage:msg:)
open func sendMessage(_ msgType: String, msg: String) {
Openreplay.shared.sendMessage(msgType, msg)
}
}

View file

@ -19,11 +19,11 @@ Pod::Spec.new do |s|
# Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
# See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
if respond_to?(:install_modules_dependencies, true)
s.dependency "Openreplay", '1.0.15'
s.dependency "Openreplay", '1.0.17'
install_modules_dependencies(s)
else
s.dependency "React-Core"
s.dependency "Openreplay", '1.0.15'
s.dependency "Openreplay", '1.0.17'
# Don't install the dependencies when we run `pod install` in the old architecture.
if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
@ -38,7 +38,7 @@ Pod::Spec.new do |s|
s.dependency "RCTRequired"
s.dependency "RCTTypeSafety"
s.dependency "ReactCommon/turbomodule/core"
s.dependency "Openreplay", '1.0.15'
s.dependency "Openreplay", '1.0.17'
end
end
end

View file

@ -17,6 +17,8 @@ const LINKING_ERROR =
'- You rebuilt the app after installing the package\n' +
'- You are not using Expo Go\n';
console.log(Object.keys(ORTrackerConnector));
interface Options {
crashes?: boolean;
analytics?: boolean;
@ -32,6 +34,11 @@ interface IORTrackerConnector {
optionsDict: Options,
projectUrl?: string
) => void;
/**
* @param type - type of message (only gql at the moment)
* @param msg - JSON string containing message to be sent
* */
sendMessage: (type: string, msg: string) => void;
stop: () => void;
getSessionID: () => Promise<string>;
setMetadata: (key: string, value: string) => void;
@ -77,6 +84,30 @@ export function setUserID(userID: string) {
ORTrackerConnector.setUserID(userID);
}
/**
* Can be used with OR gql (Relay/Apollo) plugin:
* ```
* const appWrapper = {
* active: () => true,
* send: (gqlMsg) => {
* const type = 'gql';
* const msg = JSON.stringify({
* operationKind: gqlMsg[1],
* operationName: gqlMsg[2],
* variables: gqlMsg[3],
* response: gqlMsg[4],
* duration: gqlMsg[5],
* })
* sendMessage(type, msg);
* }
* }
* ```
* */
export function sendMessage(type: string, msg: string) {
ORTrackerConnector.sendMessage(type, msg);
}
let patched = false;
const patchNetwork = (
ctx = global,
@ -91,6 +122,7 @@ const patchNetwork = (
export default {
tracker: ORTrackerConnector as IORTrackerConnector,
sendCustomMessage: sendMessage,
patchNetwork: patchNetwork,
ORTouchTrackingView: RnTrackerTouchTrackingView,
ORTrackedInput: ORTrackedInput,