@statsig/cli-session-replay-node 3.20.0
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/LICENSE +14 -0
- package/README.md +49 -0
- package/package.json +22 -0
- package/src/AsciicastTypes.d.ts +39 -0
- package/src/AsciicastTypes.js +14 -0
- package/src/CliRecording.d.ts +60 -0
- package/src/CliRecording.js +159 -0
- package/src/CliRecordingNodeAdapter.d.ts +14 -0
- package/src/CliRecordingNodeAdapter.js +35 -0
- package/src/CliSessionReplayPlugin.d.ts +8 -0
- package/src/CliSessionReplayPlugin.js +15 -0
- package/src/index.d.ts +4 -0
- package/src/index.js +32 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
ISC License (ISC)
|
|
2
|
+
Copyright (c) 2021, Statsig, Inc.
|
|
3
|
+
|
|
4
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose
|
|
5
|
+
with or without fee is hereby granted, provided that the above copyright notice
|
|
6
|
+
and this permission notice appear in all copies.
|
|
7
|
+
|
|
8
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
9
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
10
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
11
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
12
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
13
|
+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
14
|
+
THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
Statsig helps you move faster with feature gates (feature flags), and/or dynamic configs. It also allows you to run A/B/n tests to validate your new features and understand their impact on your KPIs. If you're new to Statsig, check out our product and create an account at [statsig.com](https://www.statsig.com/?ref=gh_jsm).
|
|
2
|
+
|
|
3
|
+
<h1 align="center">
|
|
4
|
+
<a href="https://statsig.com/?ref=gh_jsm">
|
|
5
|
+
<img src="https://github.com/statsig-io/js-client-monorepo/assets/95646168/ae5499ed-20ff-4584-bf21-8857f800d485" />
|
|
6
|
+
</a>
|
|
7
|
+
<div />
|
|
8
|
+
<a href="https://statsig.com/?ref=gh_jsm">Statsig</a>
|
|
9
|
+
</h1>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://github.com/statsig-io/js-client-monorepo/blob/main/LICENSE">
|
|
13
|
+
<img src="https://img.shields.io/badge/license-ISC-blue.svg?colorA=1b2528&colorB=ccfbc7&style=for-the-badge">
|
|
14
|
+
</a>
|
|
15
|
+
<a href="https://www.npmjs.com/package/@statsig/js-client">
|
|
16
|
+
<img src="https://img.shields.io/npm/v/@statsig/js-client.svg?colorA=1b2528&colorB=b2d3ff&style=for-the-badge">
|
|
17
|
+
</a>
|
|
18
|
+
<a href="https://statsig.com/community?ref=gh_jsm">
|
|
19
|
+
<img src="https://img.shields.io/badge/slack-statsig-brightgreen.svg?logo=slack&colorA=1b2528&colorB=FFF8BA&style=for-the-badge">
|
|
20
|
+
</a>
|
|
21
|
+
</p>
|
|
22
|
+
|
|
23
|
+
## Getting Started
|
|
24
|
+
|
|
25
|
+
Read through the [Documentation](https://docs.statsig.com/client/javascript-sdk?ref=gh_jsm) or check out the [Samples](samples/).
|
|
26
|
+
|
|
27
|
+
## Packages
|
|
28
|
+
|
|
29
|
+
Clients
|
|
30
|
+
|
|
31
|
+
- Precomputed Evaluations (Recommended) [[npm](https://www.npmjs.com/package/@statsig/js-client)] [[source](https://github.com/statsig-io/js-client-monorepo/tree/main/packages/js-client)]
|
|
32
|
+
- On Device Evaluations [[npm](https://www.npmjs.com/package/@statsig/js-on-device-eval-client)] [[source](https://github.com/statsig-io/js-client-monorepo/tree/main/packages/js-on-device-eval-client)]
|
|
33
|
+
|
|
34
|
+
Product Bundles
|
|
35
|
+
|
|
36
|
+
- Session Replay [[npm](https://www.npmjs.com/package/@statsig/session-replay)] [[source](https://github.com/statsig-io/js-client-monorepo/tree/main/packages/session-replay)]
|
|
37
|
+
- Web Analytics [[npm](https://www.npmjs.com/package/@statsig/web-analytics)] [[source](https://github.com/statsig-io/js-client-monorepo/tree/main/packages/web-analytics)]
|
|
38
|
+
|
|
39
|
+
Framework Specific Bindings
|
|
40
|
+
|
|
41
|
+
- React [[npm](https://www.npmjs.com/package/@statsig/react-bindings)] [[source](https://github.com/statsig-io/js-client-monorepo/tree/main/packages/react-bindings)]
|
|
42
|
+
|
|
43
|
+
- React Native [[npm](https://www.npmjs.com/package/@statsig/react-native-bindings)] [[source](https://github.com/statsig-io/js-client-monorepo/tree/main/packages/react-native-bindings)]
|
|
44
|
+
|
|
45
|
+
- React Native (Expo) [[npm](https://www.npmjs.com/package/@statsig/expo-bindings)] [[source](https://github.com/statsig-io/js-client-monorepo/tree/main/packages/expo-bindings)]
|
|
46
|
+
|
|
47
|
+
## Community
|
|
48
|
+
|
|
49
|
+
If you need any assistance or just have a question, feel free to reach out to us on [Slack](https://statsig.com/community?ref=gh_jsm).
|
package/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@statsig/cli-session-replay-node",
|
|
3
|
+
"version": "3.20.0",
|
|
4
|
+
"license": "ISC",
|
|
5
|
+
"homepage": "https://github.com/statsig-io/js-client-monorepo",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "github:statsig-io/js-client-monorepo",
|
|
9
|
+
"directory": "packages/cli-session-replay-node"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@statsig/client-core": "3.20.0",
|
|
13
|
+
"intercept-stdout": "^0.1.2"
|
|
14
|
+
},
|
|
15
|
+
"type": "commonjs",
|
|
16
|
+
"main": "./src/index.js",
|
|
17
|
+
"typings": "./src/index.d.ts",
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@types/intercept-stdout": "^0.1.3",
|
|
20
|
+
"@types/node": "18.19.18"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export interface AsciicastHeader {
|
|
2
|
+
version: 2;
|
|
3
|
+
width: number;
|
|
4
|
+
height: number;
|
|
5
|
+
timestamp?: number;
|
|
6
|
+
duration?: number;
|
|
7
|
+
idle_time_limit?: number;
|
|
8
|
+
command?: string;
|
|
9
|
+
title?: string;
|
|
10
|
+
env?: Record<string, string | undefined>;
|
|
11
|
+
theme?: {
|
|
12
|
+
fg?: string;
|
|
13
|
+
bg?: string;
|
|
14
|
+
palette?: string;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Event codes:
|
|
19
|
+
* - o: Output
|
|
20
|
+
* - i: Input
|
|
21
|
+
* - m: Marker
|
|
22
|
+
* - r: Resize
|
|
23
|
+
* - x: Exit (Only defined by asciicast v3, but v2 supports custom events)
|
|
24
|
+
*/
|
|
25
|
+
export type AsciicastEventCode = 'o' | 'i' | 'm' | 'r' | 'x' | (string & {});
|
|
26
|
+
export declare const AsciicastEventCode: {
|
|
27
|
+
Output: "o";
|
|
28
|
+
Input: "i";
|
|
29
|
+
Marker: "m";
|
|
30
|
+
Resize: "r";
|
|
31
|
+
/**
|
|
32
|
+
* Exit code
|
|
33
|
+
* Note: Only defined by asciicast v3, but v2 supports custom events
|
|
34
|
+
*/
|
|
35
|
+
Exit: "x";
|
|
36
|
+
};
|
|
37
|
+
export type AsciicastEventData = unknown;
|
|
38
|
+
export type AsciicastEvent = [number, AsciicastEventCode, AsciicastEventData];
|
|
39
|
+
export type AsciicastArray = [AsciicastHeader, ...AsciicastEvent[]];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AsciicastEventCode = void 0;
|
|
4
|
+
exports.AsciicastEventCode = {
|
|
5
|
+
Output: 'o',
|
|
6
|
+
Input: 'i',
|
|
7
|
+
Marker: 'm',
|
|
8
|
+
Resize: 'r',
|
|
9
|
+
/**
|
|
10
|
+
* Exit code
|
|
11
|
+
* Note: Only defined by asciicast v3, but v2 supports custom events
|
|
12
|
+
*/
|
|
13
|
+
Exit: 'x',
|
|
14
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { PrecomputedEvaluationsInterface } from '@statsig/client-core';
|
|
2
|
+
import { AsciicastEventCode, AsciicastEventData, AsciicastHeader } from './AsciicastTypes';
|
|
3
|
+
export type StatsigAsciicastHeader = Omit<AsciicastHeader, 'version' | 'width' | 'height' | 'timestamp'>;
|
|
4
|
+
export interface CliRecordingPrivateHooks {
|
|
5
|
+
onResize(width: number, height: number): void;
|
|
6
|
+
onOutput(contents: string): void;
|
|
7
|
+
addCustomEvent(code: AsciicastEventCode, contents: AsciicastEventData): void;
|
|
8
|
+
}
|
|
9
|
+
export interface CliRecordingAdapter {
|
|
10
|
+
getSize(): {
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
};
|
|
14
|
+
start(): void;
|
|
15
|
+
stop(): void;
|
|
16
|
+
}
|
|
17
|
+
export type CliAdapterFactory = (hooks: CliRecordingPrivateHooks) => CliRecordingAdapter;
|
|
18
|
+
export interface CliRecordingOptions {
|
|
19
|
+
/**
|
|
20
|
+
* Override the start timestamp. Defined in milliseconds.
|
|
21
|
+
* @default Date.now()
|
|
22
|
+
*/
|
|
23
|
+
startTimestamp?: number;
|
|
24
|
+
asciicastHeader?: StatsigAsciicastHeader;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* CliRecording represents a recording. This is a singleton to ensure there's only one active recording at a time.
|
|
28
|
+
*/
|
|
29
|
+
export declare class CliRecording {
|
|
30
|
+
private static _currentRecording;
|
|
31
|
+
static get currentRecording(): CliRecording | undefined;
|
|
32
|
+
static record(client: PrecomputedEvaluationsInterface, adapterFactory: CliAdapterFactory, options?: CliRecordingOptions): CliRecording;
|
|
33
|
+
static finish(): void;
|
|
34
|
+
static isRecording(): boolean;
|
|
35
|
+
startTimestamp: number;
|
|
36
|
+
endTimestamp?: number;
|
|
37
|
+
recording: boolean;
|
|
38
|
+
private _client;
|
|
39
|
+
private _sessionID;
|
|
40
|
+
private _adapter;
|
|
41
|
+
private _asciicastLines;
|
|
42
|
+
private _payloadSize;
|
|
43
|
+
private _unsubscribe?;
|
|
44
|
+
private constructor();
|
|
45
|
+
finish(endReason?: string): void;
|
|
46
|
+
/**
|
|
47
|
+
* Start recording
|
|
48
|
+
*/
|
|
49
|
+
private _startRecording;
|
|
50
|
+
private _buildController;
|
|
51
|
+
private _appendEvent;
|
|
52
|
+
/**
|
|
53
|
+
* Create logging event and send it to Statsig
|
|
54
|
+
* @param endReason
|
|
55
|
+
*/
|
|
56
|
+
private _logRecording;
|
|
57
|
+
private _getSessionIdFromClient;
|
|
58
|
+
private _recTime;
|
|
59
|
+
private _shutdown;
|
|
60
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CliRecording = void 0;
|
|
4
|
+
const client_core_1 = require("@statsig/client-core");
|
|
5
|
+
const TIMEOUT_MS = 1000 * 60 * 60 * 4; // 4 hours
|
|
6
|
+
const MAX_RECORDING_STRLEN = 1024 * 1024; // 1 MB
|
|
7
|
+
/**
|
|
8
|
+
* CliRecording represents a recording. This is a singleton to ensure there's only one active recording at a time.
|
|
9
|
+
*/
|
|
10
|
+
class CliRecording {
|
|
11
|
+
static get currentRecording() {
|
|
12
|
+
return this._currentRecording;
|
|
13
|
+
}
|
|
14
|
+
static record(client, adapterFactory, options) {
|
|
15
|
+
if (!this._currentRecording) {
|
|
16
|
+
this._currentRecording = new CliRecording(client, adapterFactory, options);
|
|
17
|
+
}
|
|
18
|
+
return this._currentRecording;
|
|
19
|
+
}
|
|
20
|
+
static finish() {
|
|
21
|
+
var _a;
|
|
22
|
+
(_a = this._currentRecording) === null || _a === void 0 ? void 0 : _a.finish();
|
|
23
|
+
}
|
|
24
|
+
static isRecording() {
|
|
25
|
+
return this._currentRecording !== undefined;
|
|
26
|
+
}
|
|
27
|
+
constructor(client, adapterFactory, options) {
|
|
28
|
+
var _a;
|
|
29
|
+
this.recording = true;
|
|
30
|
+
this._asciicastLines = [];
|
|
31
|
+
this._payloadSize = 0;
|
|
32
|
+
this._client = client;
|
|
33
|
+
this._adapter = adapterFactory(this._buildController());
|
|
34
|
+
// Read data from client
|
|
35
|
+
const clientContext = this._client.getContext();
|
|
36
|
+
this._sessionID = this._getSessionIdFromClient(clientContext);
|
|
37
|
+
// Subscribe to events
|
|
38
|
+
const timeout = setTimeout(() => {
|
|
39
|
+
this.finish('timeout');
|
|
40
|
+
}, TIMEOUT_MS);
|
|
41
|
+
const shutdownHandler = () => this.finish();
|
|
42
|
+
const sessionExpiredHandler = () => this.finish();
|
|
43
|
+
this._client.$on('pre_shutdown', shutdownHandler);
|
|
44
|
+
this._client.$on('session_expired', sessionExpiredHandler);
|
|
45
|
+
this._unsubscribe = () => {
|
|
46
|
+
clearTimeout(timeout);
|
|
47
|
+
this._client.off('pre_shutdown', shutdownHandler);
|
|
48
|
+
this._client.off('session_expired', sessionExpiredHandler);
|
|
49
|
+
};
|
|
50
|
+
// Create recording header
|
|
51
|
+
const { width, height } = this._adapter.getSize();
|
|
52
|
+
this.startTimestamp = (_a = options === null || options === void 0 ? void 0 : options.startTimestamp) !== null && _a !== void 0 ? _a : Date.now();
|
|
53
|
+
const header = Object.assign(Object.assign({}, options === null || options === void 0 ? void 0 : options.asciicastHeader), { version: 2, width,
|
|
54
|
+
height, timestamp: Math.floor(this.startTimestamp / 1000) });
|
|
55
|
+
this._asciicastLines.push(JSON.stringify(header));
|
|
56
|
+
// Start recording
|
|
57
|
+
this._startRecording();
|
|
58
|
+
}
|
|
59
|
+
finish(endReason) {
|
|
60
|
+
this.endTimestamp = Date.now();
|
|
61
|
+
this._shutdown();
|
|
62
|
+
this._logRecording(endReason);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Start recording
|
|
66
|
+
*/
|
|
67
|
+
_startRecording() {
|
|
68
|
+
client_core_1.StatsigMetadataProvider.add({ isRecordingSession: 'true' });
|
|
69
|
+
this._adapter.start();
|
|
70
|
+
}
|
|
71
|
+
_buildController() {
|
|
72
|
+
return {
|
|
73
|
+
onResize: (width, height) => {
|
|
74
|
+
this._appendEvent('r', `${width}x${height}`);
|
|
75
|
+
},
|
|
76
|
+
onOutput: (contents) => {
|
|
77
|
+
this._appendEvent('o', contents);
|
|
78
|
+
},
|
|
79
|
+
addCustomEvent: (type, contents) => {
|
|
80
|
+
this._appendEvent(type, contents);
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
_appendEvent(type, content) {
|
|
85
|
+
if (!this.recording) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
if (this._sessionID !== this._getSessionIdFromClient()) {
|
|
90
|
+
this.finish('session_expired');
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const now = Date.now();
|
|
94
|
+
// Always keep a running end timestamp
|
|
95
|
+
this.endTimestamp = now;
|
|
96
|
+
const asciicastEvent = [
|
|
97
|
+
this._recTime(now),
|
|
98
|
+
type,
|
|
99
|
+
content,
|
|
100
|
+
];
|
|
101
|
+
const asciicastEventLength = (0, client_core_1._fastApproxSizeOf)(asciicastEvent, MAX_RECORDING_STRLEN);
|
|
102
|
+
if (this._payloadSize + asciicastEventLength >= MAX_RECORDING_STRLEN) {
|
|
103
|
+
this.finish('max_size_exceeded');
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
this._asciicastLines.push(JSON.stringify(asciicastEvent));
|
|
107
|
+
this._payloadSize += asciicastEventLength;
|
|
108
|
+
}
|
|
109
|
+
catch (e) {
|
|
110
|
+
// If we get an error here, we need to stop recording to avoid an infinite loop
|
|
111
|
+
this._asciicastLines.push(JSON.stringify([
|
|
112
|
+
this._recTime(),
|
|
113
|
+
'e',
|
|
114
|
+
e instanceof Error ? e.message : `${e}`,
|
|
115
|
+
]));
|
|
116
|
+
this.finish('error');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Create logging event and send it to Statsig
|
|
121
|
+
* @param endReason
|
|
122
|
+
*/
|
|
123
|
+
_logRecording(endReason) {
|
|
124
|
+
const file = this._asciicastLines.join('\n');
|
|
125
|
+
const metadata = {
|
|
126
|
+
session_start_ts: String(this.startTimestamp),
|
|
127
|
+
session_end_ts: String(this.endTimestamp),
|
|
128
|
+
asciinema_events: file,
|
|
129
|
+
asciinema_payload_size: String(file.length),
|
|
130
|
+
session_replay_sdk_version: client_core_1.SDK_VERSION,
|
|
131
|
+
platform: 'cli',
|
|
132
|
+
sdk_instance_id: this._client.getContext().sdkInstanceID,
|
|
133
|
+
};
|
|
134
|
+
if (endReason) {
|
|
135
|
+
metadata[endReason] = 'true';
|
|
136
|
+
}
|
|
137
|
+
this._client.logEvent({
|
|
138
|
+
eventName: 'statsig::session_recording',
|
|
139
|
+
value: this._sessionID,
|
|
140
|
+
metadata,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
_getSessionIdFromClient(context = this._client.getContext()) {
|
|
144
|
+
return context.session.data.sessionID;
|
|
145
|
+
}
|
|
146
|
+
_recTime(now = Date.now()) {
|
|
147
|
+
return (now - this.startTimestamp) / 1000;
|
|
148
|
+
}
|
|
149
|
+
_shutdown() {
|
|
150
|
+
var _a;
|
|
151
|
+
this.recording = false;
|
|
152
|
+
this._adapter.stop();
|
|
153
|
+
(_a = this._unsubscribe) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
154
|
+
this._unsubscribe = undefined;
|
|
155
|
+
client_core_1.StatsigMetadataProvider.add({ isRecordingSession: 'false' });
|
|
156
|
+
CliRecording._currentRecording = undefined;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
exports.CliRecording = CliRecording;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { CliAdapterFactory, CliRecordingAdapter, CliRecordingPrivateHooks } from './CliRecording';
|
|
2
|
+
export declare class CliRecordingNodeAdapter implements CliRecordingAdapter {
|
|
3
|
+
private _hooks;
|
|
4
|
+
private _stopIntercept;
|
|
5
|
+
constructor(_hooks: CliRecordingPrivateHooks);
|
|
6
|
+
start(): void;
|
|
7
|
+
getSize(): {
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
};
|
|
11
|
+
stop(): void;
|
|
12
|
+
private _resizeHandler;
|
|
13
|
+
}
|
|
14
|
+
export declare const CliRecordingNodeAdapterFactory: CliAdapterFactory;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CliRecordingNodeAdapterFactory = exports.CliRecordingNodeAdapter = void 0;
|
|
4
|
+
const process = require("process");
|
|
5
|
+
const intercept = require("intercept-stdout");
|
|
6
|
+
class CliRecordingNodeAdapter {
|
|
7
|
+
constructor(_hooks) {
|
|
8
|
+
this._hooks = _hooks;
|
|
9
|
+
this._resizeHandler = () => {
|
|
10
|
+
this._hooks.onResize(process.stdout.columns, process.stdout.rows);
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
start() {
|
|
14
|
+
this._stopIntercept = intercept((str) => {
|
|
15
|
+
this._hooks.onOutput(str.replaceAll('\n', '\r\n'));
|
|
16
|
+
});
|
|
17
|
+
process.stdout.on('resize', this._resizeHandler);
|
|
18
|
+
}
|
|
19
|
+
getSize() {
|
|
20
|
+
return {
|
|
21
|
+
width: process.stdout.columns,
|
|
22
|
+
height: process.stdout.rows,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
stop() {
|
|
26
|
+
if (this._stopIntercept) {
|
|
27
|
+
this._stopIntercept();
|
|
28
|
+
this._stopIntercept = undefined;
|
|
29
|
+
}
|
|
30
|
+
process.stdout.off('resize', this._resizeHandler);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.CliRecordingNodeAdapter = CliRecordingNodeAdapter;
|
|
34
|
+
const CliRecordingNodeAdapterFactory = (hooks) => new CliRecordingNodeAdapter(hooks);
|
|
35
|
+
exports.CliRecordingNodeAdapterFactory = CliRecordingNodeAdapterFactory;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { PrecomputedEvaluationsInterface, StatsigPlugin } from '@statsig/client-core';
|
|
2
|
+
import { CliRecordingOptions } from './CliRecording';
|
|
3
|
+
export declare class StatsigCliSessionReplayPlugin implements StatsigPlugin<PrecomputedEvaluationsInterface> {
|
|
4
|
+
private readonly options?;
|
|
5
|
+
readonly __plugin = "cli-session-replay-node";
|
|
6
|
+
constructor(options?: CliRecordingOptions | undefined);
|
|
7
|
+
bind(client: PrecomputedEvaluationsInterface): void;
|
|
8
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StatsigCliSessionReplayPlugin = void 0;
|
|
4
|
+
const CliRecording_1 = require("./CliRecording");
|
|
5
|
+
const CliRecordingNodeAdapter_1 = require("./CliRecordingNodeAdapter");
|
|
6
|
+
class StatsigCliSessionReplayPlugin {
|
|
7
|
+
constructor(options) {
|
|
8
|
+
this.options = options;
|
|
9
|
+
this.__plugin = 'cli-session-replay-node';
|
|
10
|
+
}
|
|
11
|
+
bind(client) {
|
|
12
|
+
CliRecording_1.CliRecording.record(client, CliRecordingNodeAdapter_1.CliRecordingNodeAdapterFactory, this.options);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.StatsigCliSessionReplayPlugin = StatsigCliSessionReplayPlugin;
|
package/src/index.d.ts
ADDED
package/src/index.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
const client_core_1 = require("@statsig/client-core");
|
|
18
|
+
const AsciicastTypes_1 = require("./AsciicastTypes");
|
|
19
|
+
const CliRecording_1 = require("./CliRecording");
|
|
20
|
+
const CliRecordingNodeAdapter_1 = require("./CliRecordingNodeAdapter");
|
|
21
|
+
const CliSessionReplayPlugin_1 = require("./CliSessionReplayPlugin");
|
|
22
|
+
__exportStar(require("./AsciicastTypes"), exports);
|
|
23
|
+
__exportStar(require("./CliRecordingNodeAdapter"), exports);
|
|
24
|
+
__exportStar(require("./CliSessionReplayPlugin"), exports);
|
|
25
|
+
__exportStar(require("./CliRecording"), exports);
|
|
26
|
+
Object.assign((0, client_core_1._getStatsigGlobal)(), {
|
|
27
|
+
AsciicastEventCode: AsciicastTypes_1.AsciicastEventCode,
|
|
28
|
+
CliRecording: CliRecording_1.CliRecording,
|
|
29
|
+
CliRecordingNodeAdapter: CliRecordingNodeAdapter_1.CliRecordingNodeAdapter,
|
|
30
|
+
CliRecordingNodeAdapterFactory: CliRecordingNodeAdapter_1.CliRecordingNodeAdapterFactory,
|
|
31
|
+
StatsigCliSessionReplayPlugin: CliSessionReplayPlugin_1.StatsigCliSessionReplayPlugin,
|
|
32
|
+
});
|