@multiplayer-app/session-recorder-react-native 0.0.1-beta.7 → 0.0.1-beta.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/NATIVE_MODULE_SETUP.md +175 -0
- package/ios/SessionRecorderNative.podspec +5 -0
- package/package.json +11 -1
- package/plugin/package.json +20 -0
- package/plugin/src/index.js +42 -0
- package/android/src/main/AndroidManifest.xml +0 -2
- package/android/src/main/java/com/multiplayer/sessionrecorder/ScreenMaskingModule.kt +0 -202
- package/android/src/main/java/com/multiplayer/sessionrecorder/ScreenMaskingPackage.kt +0 -16
- package/android/src/main/java/com/multiplayer/sessionrecorder/SessionRecorderModule.kt +0 -202
- package/android/src/main/java/com/multiplayer/sessionrecorder/SessionRecorderPackage.kt +0 -16
- package/babel.config.js +0 -13
- package/docs/AUTO_METADATA_DETECTION.md +0 -108
- package/docs/TROUBLESHOOTING.md +0 -168
- package/ios/ScreenMasking.m +0 -12
- package/ios/ScreenMasking.podspec +0 -21
- package/ios/ScreenMasking.swift +0 -205
- package/ios/SessionRecorder.podspec +0 -21
- package/scripts/generate-app-metadata.js +0 -173
- package/src/components/GestureCaptureWrapper/GestureCaptureWrapper.tsx +0 -86
- package/src/components/GestureCaptureWrapper/index.ts +0 -1
- package/src/components/ScreenRecorderView/ScreenRecorderView.tsx +0 -72
- package/src/components/ScreenRecorderView/index.ts +0 -1
- package/src/components/SessionRecorderWidget/FinalPopover.tsx +0 -62
- package/src/components/SessionRecorderWidget/FloatingButton.tsx +0 -136
- package/src/components/SessionRecorderWidget/InitialPopover.tsx +0 -89
- package/src/components/SessionRecorderWidget/ModalContainer.tsx +0 -128
- package/src/components/SessionRecorderWidget/ModalHeader.tsx +0 -24
- package/src/components/SessionRecorderWidget/SessionRecorderWidget.tsx +0 -109
- package/src/components/SessionRecorderWidget/icons.tsx +0 -52
- package/src/components/SessionRecorderWidget/index.ts +0 -3
- package/src/components/SessionRecorderWidget/styles.ts +0 -150
- package/src/components/index.ts +0 -3
- package/src/config/constants.ts +0 -60
- package/src/config/defaults.ts +0 -83
- package/src/config/index.ts +0 -6
- package/src/config/masking.ts +0 -28
- package/src/config/session-recorder.ts +0 -55
- package/src/config/validators.ts +0 -31
- package/src/context/SessionRecorderContext.tsx +0 -53
- package/src/index.ts +0 -9
- package/src/native/ScreenMasking.ts +0 -34
- package/src/native/SessionRecorderNative.ts +0 -34
- package/src/otel/helpers.ts +0 -275
- package/src/otel/index.ts +0 -138
- package/src/otel/instrumentations/index.ts +0 -115
- package/src/patch/index.ts +0 -1
- package/src/patch/xhr.ts +0 -141
- package/src/recorder/eventExporter.ts +0 -141
- package/src/recorder/gestureRecorder.ts +0 -498
- package/src/recorder/index.ts +0 -179
- package/src/recorder/navigationTracker.ts +0 -449
- package/src/recorder/screenRecorder.ts +0 -527
- package/src/services/api.service.ts +0 -203
- package/src/services/screenMaskingService.ts +0 -118
- package/src/services/storage.service.ts +0 -199
- package/src/session-recorder.ts +0 -606
- package/src/types/expo.d.ts +0 -23
- package/src/types/index.ts +0 -28
- package/src/types/session-recorder.ts +0 -429
- package/src/types/session.ts +0 -65
- package/src/utils/app-metadata.ts +0 -31
- package/src/utils/index.ts +0 -8
- package/src/utils/logger.ts +0 -225
- package/src/utils/nativeModuleTest.ts +0 -60
- package/src/utils/platform.ts +0 -384
- package/src/utils/request-utils.ts +0 -61
- package/src/utils/rrweb-events.ts +0 -309
- package/src/utils/session.ts +0 -18
- package/src/utils/time.ts +0 -17
- package/src/utils/type-utils.ts +0 -75
- package/src/version.ts +0 -1
- package/tsconfig.json +0 -24
- /package/ios/{SessionRecorder.m → SessionRecorderNative.m} +0 -0
- /package/ios/{SessionRecorder.swift → SessionRecorderNative.swift} +0 -0
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Request utility functions for React Native
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Convert FormData to query string (React Native compatible)
|
|
7
|
-
* @param formData - FormData object
|
|
8
|
-
* @returns Query string
|
|
9
|
-
*/
|
|
10
|
-
export const formDataToQuery = (formData: any): string => {
|
|
11
|
-
if (!formData) return ''
|
|
12
|
-
|
|
13
|
-
// In React Native, FormData is handled differently
|
|
14
|
-
// This is a simplified implementation
|
|
15
|
-
const params = new URLSearchParams()
|
|
16
|
-
|
|
17
|
-
if (typeof formData.entries === 'function') {
|
|
18
|
-
for (const [key, value] of formData.entries()) {
|
|
19
|
-
params.append(key, value as string)
|
|
20
|
-
}
|
|
21
|
-
} else if (typeof formData === 'object') {
|
|
22
|
-
for (const [key, value] of Object.entries(formData)) {
|
|
23
|
-
params.append(key, String(value))
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return params.toString()
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Convert object to query string
|
|
32
|
-
* @param obj - Object to convert
|
|
33
|
-
* @returns Query string
|
|
34
|
-
*/
|
|
35
|
-
export const objectToQuery = (obj: Record<string, any>): string => {
|
|
36
|
-
const params = new URLSearchParams()
|
|
37
|
-
|
|
38
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
39
|
-
if (value !== null && value !== undefined) {
|
|
40
|
-
params.append(key, String(value))
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return params.toString()
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Parse query string to object
|
|
49
|
-
* @param queryString - Query string to parse
|
|
50
|
-
* @returns Object with parsed parameters
|
|
51
|
-
*/
|
|
52
|
-
export const queryToObject = (queryString: string): Record<string, string> => {
|
|
53
|
-
const params = new URLSearchParams(queryString)
|
|
54
|
-
const obj: Record<string, string> = {}
|
|
55
|
-
|
|
56
|
-
for (const [key, value] of params.entries()) {
|
|
57
|
-
obj[key] = value
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return obj
|
|
61
|
-
}
|
|
@@ -1,309 +0,0 @@
|
|
|
1
|
-
import { Dimensions } from 'react-native'
|
|
2
|
-
import { EventType, eventWithTime, NodeType, serializedNodeWithId, IncrementalSource, mutationData } from '@rrweb/types'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Creates a meta event to mark the start of recording
|
|
6
|
-
* @param sessionId - The session ID
|
|
7
|
-
* @param sessionType - The type of session (PLAIN or CONTINUOUS)
|
|
8
|
-
* @param additionalData - Additional data to include in the meta event
|
|
9
|
-
* @returns MetaEvent object
|
|
10
|
-
*/
|
|
11
|
-
export function createRecordingMetaEvent(): eventWithTime {
|
|
12
|
-
const screenDimensions = Dimensions.get('window')
|
|
13
|
-
|
|
14
|
-
return {
|
|
15
|
-
type: EventType.Meta,
|
|
16
|
-
data: {
|
|
17
|
-
href: 'https://go.multiplayer.app/session-recorder-react-native',
|
|
18
|
-
width: screenDimensions.width,
|
|
19
|
-
height: screenDimensions.height,
|
|
20
|
-
},
|
|
21
|
-
timestamp: Date.now(),
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Create a full snapshot event with the given base64 image
|
|
27
|
-
* @param base64Image - Base64 encoded image data
|
|
28
|
-
* @param width - Screen width
|
|
29
|
-
* @param height - Screen height
|
|
30
|
-
* @param captureFormat - Image format (png, jpg, etc.)
|
|
31
|
-
* @param nodeIdCounter - Starting node ID counter (will be modified)
|
|
32
|
-
* @returns Full snapshot event
|
|
33
|
-
*/
|
|
34
|
-
export function createFullSnapshotEvent(
|
|
35
|
-
base64Image: string,
|
|
36
|
-
width: number,
|
|
37
|
-
height: number,
|
|
38
|
-
captureFormat: string = 'jpg',
|
|
39
|
-
nodeIdCounter: { current: number },
|
|
40
|
-
): eventWithTime {
|
|
41
|
-
// Create a virtual DOM node representing the screen as an image
|
|
42
|
-
const imageNode: serializedNodeWithId = {
|
|
43
|
-
type: NodeType.Element,
|
|
44
|
-
id: 0,
|
|
45
|
-
tagName: 'img',
|
|
46
|
-
attributes: {
|
|
47
|
-
src: `data:image/${captureFormat};base64,${base64Image}`,
|
|
48
|
-
width: width.toString(),
|
|
49
|
-
height: height.toString(),
|
|
50
|
-
style: `width: ${width}px; height: ${height}px;`,
|
|
51
|
-
},
|
|
52
|
-
childNodes: [],
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Create the root container
|
|
56
|
-
const rootNode: serializedNodeWithId = {
|
|
57
|
-
type: NodeType.Element,
|
|
58
|
-
id: nodeIdCounter.current++,
|
|
59
|
-
tagName: 'div',
|
|
60
|
-
attributes: {
|
|
61
|
-
style: `width: ${width}px; height: ${height}px; position: relative;`,
|
|
62
|
-
},
|
|
63
|
-
childNodes: [imageNode],
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const domNode: serializedNodeWithId = {
|
|
67
|
-
type: NodeType.Document,
|
|
68
|
-
childNodes: [
|
|
69
|
-
{
|
|
70
|
-
type: NodeType.DocumentType,
|
|
71
|
-
name: 'html',
|
|
72
|
-
publicId: '',
|
|
73
|
-
systemId: '',
|
|
74
|
-
id: nodeIdCounter.current++,
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
type: NodeType.Element,
|
|
78
|
-
tagName: 'html',
|
|
79
|
-
attributes: {},
|
|
80
|
-
childNodes: [
|
|
81
|
-
{
|
|
82
|
-
type: NodeType.Element,
|
|
83
|
-
tagName: 'head',
|
|
84
|
-
attributes: {},
|
|
85
|
-
childNodes: [
|
|
86
|
-
{
|
|
87
|
-
type: NodeType.Element,
|
|
88
|
-
tagName: 'meta',
|
|
89
|
-
attributes: { charset: 'utf-8' },
|
|
90
|
-
childNodes: [],
|
|
91
|
-
id: nodeIdCounter.current++,
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
type: NodeType.Element,
|
|
95
|
-
tagName: 'meta',
|
|
96
|
-
attributes: {
|
|
97
|
-
name: 'viewport',
|
|
98
|
-
content: 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no',
|
|
99
|
-
},
|
|
100
|
-
childNodes: [],
|
|
101
|
-
id: nodeIdCounter.current++,
|
|
102
|
-
},
|
|
103
|
-
],
|
|
104
|
-
id: nodeIdCounter.current++,
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
type: NodeType.Element,
|
|
108
|
-
tagName: 'body',
|
|
109
|
-
attributes: {},
|
|
110
|
-
childNodes: [rootNode],
|
|
111
|
-
id: nodeIdCounter.current++,
|
|
112
|
-
},
|
|
113
|
-
],
|
|
114
|
-
id: nodeIdCounter.current++,
|
|
115
|
-
},
|
|
116
|
-
],
|
|
117
|
-
id: nodeIdCounter.current++,
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return {
|
|
121
|
-
type: EventType.FullSnapshot,
|
|
122
|
-
data: {
|
|
123
|
-
node: domNode,
|
|
124
|
-
initialOffset: { left: 0, top: 0 },
|
|
125
|
-
},
|
|
126
|
-
timestamp: Date.now(),
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Create an incremental snapshot event with mutation data to update image src
|
|
132
|
-
* @param base64Image - New base64 encoded image data
|
|
133
|
-
* @param imageNodeId - ID of the image node to update
|
|
134
|
-
* @param captureFormat - Image format (png, jpg, etc.)
|
|
135
|
-
* @returns Incremental snapshot event with mutation data
|
|
136
|
-
*/
|
|
137
|
-
export function createIncrementalSnapshotWithImageUpdate(
|
|
138
|
-
base64Image: string,
|
|
139
|
-
captureFormat: string = 'jpg',
|
|
140
|
-
): eventWithTime {
|
|
141
|
-
const mutationData: mutationData = {
|
|
142
|
-
source: IncrementalSource.Mutation,
|
|
143
|
-
texts: [],
|
|
144
|
-
attributes: [
|
|
145
|
-
{
|
|
146
|
-
id: 0,
|
|
147
|
-
attributes: {
|
|
148
|
-
src: `data:image/${captureFormat};base64,${base64Image}`,
|
|
149
|
-
},
|
|
150
|
-
},
|
|
151
|
-
],
|
|
152
|
-
removes: [],
|
|
153
|
-
adds: [],
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return {
|
|
157
|
-
type: EventType.IncrementalSnapshot,
|
|
158
|
-
data: mutationData,
|
|
159
|
-
timestamp: Date.now(),
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Create a simple image node for React Native screen capture
|
|
165
|
-
* @param base64Image - Base64 encoded image data
|
|
166
|
-
* @param width - Image width
|
|
167
|
-
* @param height - Image height
|
|
168
|
-
* @param captureFormat - Image format (png, jpg, etc.)
|
|
169
|
-
* @param nodeId - Node ID for the image
|
|
170
|
-
* @returns Serialized node with ID
|
|
171
|
-
*/
|
|
172
|
-
export function createImageNode(
|
|
173
|
-
base64Image: string,
|
|
174
|
-
width: number,
|
|
175
|
-
height: number,
|
|
176
|
-
captureFormat: string = 'jpg',
|
|
177
|
-
nodeId: number,
|
|
178
|
-
): serializedNodeWithId {
|
|
179
|
-
return {
|
|
180
|
-
type: NodeType.Element,
|
|
181
|
-
id: nodeId,
|
|
182
|
-
tagName: 'img',
|
|
183
|
-
attributes: {
|
|
184
|
-
src: `data:image/${captureFormat};base64,${base64Image}`,
|
|
185
|
-
width: width.toString(),
|
|
186
|
-
height: height.toString(),
|
|
187
|
-
style: `width: ${width}px; height: ${height}px;`,
|
|
188
|
-
},
|
|
189
|
-
childNodes: [],
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Create a document node for React Native screen capture
|
|
195
|
-
* @param imageNode - The image node to include
|
|
196
|
-
* @param width - Screen width
|
|
197
|
-
* @param height - Screen height
|
|
198
|
-
* @param nodeIdCounter - Node ID counter (will be modified)
|
|
199
|
-
* @returns Document node
|
|
200
|
-
*/
|
|
201
|
-
export function createDocumentNode(
|
|
202
|
-
imageNode: serializedNodeWithId,
|
|
203
|
-
width: number,
|
|
204
|
-
height: number,
|
|
205
|
-
nodeIdCounter: { current: number },
|
|
206
|
-
): serializedNodeWithId {
|
|
207
|
-
// Create the root container
|
|
208
|
-
const rootNode: serializedNodeWithId = {
|
|
209
|
-
type: NodeType.Element,
|
|
210
|
-
id: nodeIdCounter.current++,
|
|
211
|
-
tagName: 'div',
|
|
212
|
-
attributes: {
|
|
213
|
-
style: `width: ${width}px; height: ${height}px; position: relative;`,
|
|
214
|
-
},
|
|
215
|
-
childNodes: [imageNode],
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
return {
|
|
219
|
-
type: NodeType.Document,
|
|
220
|
-
childNodes: [
|
|
221
|
-
{
|
|
222
|
-
type: NodeType.DocumentType,
|
|
223
|
-
name: 'html',
|
|
224
|
-
publicId: '',
|
|
225
|
-
systemId: '',
|
|
226
|
-
id: nodeIdCounter.current++,
|
|
227
|
-
},
|
|
228
|
-
{
|
|
229
|
-
type: NodeType.Element,
|
|
230
|
-
tagName: 'html',
|
|
231
|
-
attributes: {},
|
|
232
|
-
childNodes: [
|
|
233
|
-
{
|
|
234
|
-
type: NodeType.Element,
|
|
235
|
-
tagName: 'head',
|
|
236
|
-
attributes: {},
|
|
237
|
-
childNodes: [
|
|
238
|
-
{
|
|
239
|
-
type: NodeType.Element,
|
|
240
|
-
tagName: 'meta',
|
|
241
|
-
attributes: { charset: 'utf-8' },
|
|
242
|
-
childNodes: [],
|
|
243
|
-
id: nodeIdCounter.current++,
|
|
244
|
-
},
|
|
245
|
-
{
|
|
246
|
-
type: NodeType.Element,
|
|
247
|
-
tagName: 'meta',
|
|
248
|
-
attributes: {
|
|
249
|
-
name: 'viewport',
|
|
250
|
-
content: 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no',
|
|
251
|
-
},
|
|
252
|
-
childNodes: [],
|
|
253
|
-
id: nodeIdCounter.current++,
|
|
254
|
-
},
|
|
255
|
-
],
|
|
256
|
-
id: nodeIdCounter.current++,
|
|
257
|
-
},
|
|
258
|
-
{
|
|
259
|
-
type: NodeType.Element,
|
|
260
|
-
tagName: 'body',
|
|
261
|
-
attributes: {},
|
|
262
|
-
childNodes: [rootNode],
|
|
263
|
-
id: nodeIdCounter.current++,
|
|
264
|
-
},
|
|
265
|
-
],
|
|
266
|
-
id: nodeIdCounter.current++,
|
|
267
|
-
},
|
|
268
|
-
],
|
|
269
|
-
id: nodeIdCounter.current++,
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* Generate a simple hash for screen comparison
|
|
275
|
-
* This is a lightweight hash that focuses on the beginning and end of the base64 string
|
|
276
|
-
* to detect changes without doing a full comparison
|
|
277
|
-
* @param base64Image - Base64 encoded image
|
|
278
|
-
* @param sampleSize - Number of characters to sample from each part
|
|
279
|
-
* @returns Hash string for comparison
|
|
280
|
-
*/
|
|
281
|
-
export function generateScreenHash(base64Image: string, sampleSize: number = 100): string {
|
|
282
|
-
// Use a simple hash that samples the beginning, middle, and end of the base64 string
|
|
283
|
-
// This is much faster than comparing the entire string
|
|
284
|
-
const start = base64Image.substring(0, sampleSize)
|
|
285
|
-
const middle = base64Image.substring(
|
|
286
|
-
Math.floor(base64Image.length / 2) - sampleSize / 2,
|
|
287
|
-
Math.floor(base64Image.length / 2) + sampleSize / 2,
|
|
288
|
-
)
|
|
289
|
-
const end = base64Image.substring(base64Image.length - sampleSize)
|
|
290
|
-
|
|
291
|
-
// Combine samples and create a simple hash
|
|
292
|
-
const combined = start + middle + end
|
|
293
|
-
return simpleHash(combined)
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* Simple hash function for string comparison
|
|
298
|
-
* @param str - String to hash
|
|
299
|
-
* @returns Hash value as string
|
|
300
|
-
*/
|
|
301
|
-
export function simpleHash(str: string): string {
|
|
302
|
-
let hash = 0
|
|
303
|
-
for (let i = 0; i < str.length; i++) {
|
|
304
|
-
const char = str.charCodeAt(i)
|
|
305
|
-
hash = (hash << 5) - hash + char
|
|
306
|
-
hash = hash & hash // Convert to 32-bit integer
|
|
307
|
-
}
|
|
308
|
-
return Math.abs(hash).toString(36)
|
|
309
|
-
}
|
package/src/utils/session.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { DEBUG_SESSION_MAX_DURATION_SECONDS } from '../config/constants'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Session-related utility functions for React Native
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
export const isSessionActive = (session: any, continuousRecording: boolean): boolean => {
|
|
8
|
-
if (!session) return false
|
|
9
|
-
if (continuousRecording) return true
|
|
10
|
-
const startedAt = new Date(session.startedAt || session.createdAt)
|
|
11
|
-
const now = new Date()
|
|
12
|
-
const diff = now.getTime() - startedAt.getTime()
|
|
13
|
-
return diff < DEBUG_SESSION_MAX_DURATION_SECONDS * 1000
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const isConsoleEvent = (event: any): boolean => {
|
|
17
|
-
return event.type === 'Plugin' && event.data?.plugin === 'rrweb/console@1'
|
|
18
|
-
}
|
package/src/utils/time.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Time and date utility functions for React Native
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export const getFormattedDate = (date: number | Date, options?: any): string => {
|
|
6
|
-
return new Date(date).toLocaleDateString(
|
|
7
|
-
'en-US',
|
|
8
|
-
options || {
|
|
9
|
-
month: 'short',
|
|
10
|
-
year: 'numeric',
|
|
11
|
-
day: 'numeric',
|
|
12
|
-
hour: 'numeric',
|
|
13
|
-
minute: '2-digit',
|
|
14
|
-
second: '2-digit',
|
|
15
|
-
},
|
|
16
|
-
)
|
|
17
|
-
}
|
package/src/utils/type-utils.ts
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
const nativeIsArray = Array.isArray
|
|
2
|
-
const ObjProto = Object.prototype
|
|
3
|
-
export const hasOwnProperty = ObjProto.hasOwnProperty
|
|
4
|
-
const toString = ObjProto.toString
|
|
5
|
-
|
|
6
|
-
export const isArray =
|
|
7
|
-
nativeIsArray ||
|
|
8
|
-
function (obj: any): obj is any[] {
|
|
9
|
-
return toString.call(obj) === '[object Array]'
|
|
10
|
-
}
|
|
11
|
-
export const isUint8Array = function (x: unknown): x is Uint8Array {
|
|
12
|
-
return toString.call(x) === '[object Uint8Array]'
|
|
13
|
-
}
|
|
14
|
-
// from a comment on http://dbj.org/dbj/?p=286
|
|
15
|
-
// fails on only one very rare and deliberate custom object:
|
|
16
|
-
// let bomb = { toString : undefined, valueOf: function(o) { return "function BOMBA!"; }};
|
|
17
|
-
export const isFunction = function (f: any): f is (...args: any[]) => any {
|
|
18
|
-
return typeof f === 'function'
|
|
19
|
-
}
|
|
20
|
-
// Underscore Addons
|
|
21
|
-
export const isObject = function (x: unknown): x is Record<string, any> {
|
|
22
|
-
return x === Object(x) && !isArray(x)
|
|
23
|
-
}
|
|
24
|
-
export const isEmptyObject = function (x: unknown): x is Record<string, any> {
|
|
25
|
-
if (isObject(x)) {
|
|
26
|
-
for (const key in x) {
|
|
27
|
-
if (hasOwnProperty.call(x, key)) {
|
|
28
|
-
return false
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
return true
|
|
32
|
-
}
|
|
33
|
-
return false
|
|
34
|
-
}
|
|
35
|
-
export const isUndefined = function (x: unknown): x is undefined {
|
|
36
|
-
return x === void 0
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export const isString = function (x: unknown): x is string {
|
|
40
|
-
return toString.call(x) == '[object String]'
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export const isEmptyString = function (x: unknown): boolean {
|
|
44
|
-
return isString(x) && x.trim().length === 0
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export const isNull = function (x: unknown): x is null {
|
|
48
|
-
return x === null
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/*
|
|
52
|
-
sometimes you want to check if something is null or undefined
|
|
53
|
-
that's what this is for
|
|
54
|
-
*/
|
|
55
|
-
export const isNullish = function (x: unknown): x is null | undefined {
|
|
56
|
-
return isUndefined(x) || isNull(x)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export const isDate = function (x: unknown): x is Date {
|
|
60
|
-
return toString.call(x) == '[object Date]'
|
|
61
|
-
}
|
|
62
|
-
export const isNumber = function (x: unknown): x is number {
|
|
63
|
-
return toString.call(x) == '[object Number]'
|
|
64
|
-
}
|
|
65
|
-
export const isBoolean = function (x: unknown): x is boolean {
|
|
66
|
-
return toString.call(x) === '[object Boolean]'
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export const isFormData = (x: unknown): x is FormData => {
|
|
70
|
-
return x instanceof FormData
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export const isFile = (x: unknown): x is File => {
|
|
74
|
-
return x instanceof File
|
|
75
|
-
}
|
package/src/version.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const version = "0.0.1"
|
package/tsconfig.json
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"rootDir": "./src",
|
|
4
|
-
"declaration": true,
|
|
5
|
-
"esModuleInterop": true,
|
|
6
|
-
"jsx": "react-native",
|
|
7
|
-
"incremental": false,
|
|
8
|
-
"lib": ["ESNext"],
|
|
9
|
-
"module": "ES2015",
|
|
10
|
-
"moduleResolution": "bundler",
|
|
11
|
-
"noEmitOnError": true,
|
|
12
|
-
"outDir": "./dist",
|
|
13
|
-
"skipLibCheck": true,
|
|
14
|
-
"sourceMap": true,
|
|
15
|
-
"strict": true,
|
|
16
|
-
"target": "ES2018",
|
|
17
|
-
"allowSyntheticDefaultImports": true,
|
|
18
|
-
"resolveJsonModule": true,
|
|
19
|
-
"isolatedModules": true
|
|
20
|
-
},
|
|
21
|
-
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
|
22
|
-
"exclude": ["node_modules", "dist", "examples"],
|
|
23
|
-
"files": ["src/index.ts"]
|
|
24
|
-
}
|
|
File without changes
|
|
File without changes
|