@thred-apps/thred-track 1.2.1 → 1.2.3
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/README.md +19 -230
- package/dist/core/tracker.d.ts +14 -0
- package/dist/core/tracker.d.ts.map +1 -1
- package/dist/index.esm.js +64 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +64 -1
- package/dist/index.js.map +1 -1
- package/dist/thred.umd.js +1 -1
- package/dist/thred.umd.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,106 +1,43 @@
|
|
|
1
1
|
# Thred SDK
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- **ChatGPT Detection** - Automatic detection of visitors from ChatGPT
|
|
8
|
-
- **Browser Fingerprinting** - Privacy-friendly visitor identification
|
|
9
|
-
- **Page View Tracking** - Automatic page view analytics
|
|
10
|
-
- **Form Tracking** - Automatic form submission tracking
|
|
11
|
-
- **Lead Enrichment** - Capture and enrich lead data
|
|
12
|
-
- **Zero Dependencies** - Lightweight with no external dependencies
|
|
13
|
-
- **Multiple Formats** - UMD, CommonJS, and ES modules
|
|
14
|
-
- **TypeScript Support** - Full TypeScript definitions included
|
|
3
|
+
Automatic browser tracking and lead enrichment for ChatGPT referrals.
|
|
15
4
|
|
|
16
5
|
## Installation
|
|
17
6
|
|
|
18
|
-
###
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
npm install thred-track
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### Yarn
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
yarn add thred-track
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
### CDN (Script Tag)
|
|
7
|
+
### Script Tag
|
|
31
8
|
|
|
32
9
|
```html
|
|
33
10
|
<script src="https://cdn.thred.dev/thred-track.js?browserKey=YOUR_KEY"></script>
|
|
34
11
|
```
|
|
35
12
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
### Script Tag
|
|
39
|
-
|
|
40
|
-
Drop the script onto your page with your browser key. That's it — everything is automatic:
|
|
13
|
+
### NPM
|
|
41
14
|
|
|
42
|
-
```
|
|
43
|
-
|
|
15
|
+
```bash
|
|
16
|
+
npm install @thred-apps/thred-track
|
|
44
17
|
```
|
|
45
18
|
|
|
46
|
-
### Module Import
|
|
47
|
-
|
|
48
19
|
```typescript
|
|
49
|
-
import { ThredSDK } from 'thred-track';
|
|
20
|
+
import { ThredSDK } from '@thred-apps/thred-track';
|
|
50
21
|
|
|
51
22
|
new ThredSDK({ browserKey: 'YOUR_KEY' });
|
|
52
23
|
```
|
|
53
24
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
1. Detects ChatGPT referrals via UTM parameters
|
|
57
|
-
2. Generates a browser fingerprint
|
|
58
|
-
3. Tracks page views for ChatGPT visitors
|
|
59
|
-
4. Monitors and captures form submissions based on your API config
|
|
60
|
-
|
|
61
|
-
## What Happens on Initialization
|
|
62
|
-
|
|
63
|
-
When the SDK initializes, it follows the same flow as the original script:
|
|
64
|
-
|
|
65
|
-
1. **Fetches config** from the Thred API using your `browserKey`
|
|
66
|
-
2. **Checks eligibility** — tracking only runs if the config says `enabled: true` and the visitor has a ChatGPT session or arrived via ChatGPT UTM
|
|
67
|
-
3. **Tracks the page view** automatically for ChatGPT visitors
|
|
68
|
-
4. **Sets up form tracking** — either injecting fingerprints into hosted form links, or attaching submit listeners to your form (based on config `type`)
|
|
69
|
-
|
|
70
|
-
All of this happens without any manual method calls.
|
|
71
|
-
|
|
72
|
-
## Constructor Options
|
|
73
|
-
|
|
74
|
-
```typescript
|
|
75
|
-
interface ThredOptions {
|
|
76
|
-
browserKey: string; // Required: Your Thred browser key
|
|
77
|
-
debug?: boolean; // Optional: Enable debug logging (default: false)
|
|
78
|
-
autoInit?: boolean; // Optional: Auto-initialize on construction (default: true)
|
|
79
|
-
}
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
## Usage Examples
|
|
83
|
-
|
|
84
|
-
### Basic HTML Page
|
|
25
|
+
That's it. The SDK automatically:
|
|
85
26
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
<input type="text" name="company">
|
|
91
|
-
<button type="submit">Submit</button>
|
|
92
|
-
</form>
|
|
27
|
+
- Detects ChatGPT referrals
|
|
28
|
+
- Fingerprints the visitor
|
|
29
|
+
- Tracks page views
|
|
30
|
+
- Captures form submissions
|
|
93
31
|
|
|
94
|
-
|
|
95
|
-
```
|
|
32
|
+
No manual method calls needed.
|
|
96
33
|
|
|
97
|
-
|
|
34
|
+
## Framework Examples
|
|
98
35
|
|
|
99
36
|
### React
|
|
100
37
|
|
|
101
38
|
```typescript
|
|
102
39
|
import { useEffect, useRef } from 'react';
|
|
103
|
-
import { ThredSDK } from 'thred-track';
|
|
40
|
+
import { ThredSDK } from '@thred-apps/thred-track';
|
|
104
41
|
|
|
105
42
|
function App() {
|
|
106
43
|
const thredRef = useRef<ThredSDK | null>(null);
|
|
@@ -108,9 +45,7 @@ function App() {
|
|
|
108
45
|
useEffect(() => {
|
|
109
46
|
thredRef.current = new ThredSDK({
|
|
110
47
|
browserKey: process.env.REACT_APP_THRED_KEY!,
|
|
111
|
-
debug: process.env.NODE_ENV === 'development',
|
|
112
48
|
});
|
|
113
|
-
|
|
114
49
|
return () => thredRef.current?.destroy();
|
|
115
50
|
}, []);
|
|
116
51
|
|
|
@@ -124,7 +59,7 @@ function App() {
|
|
|
124
59
|
'use client';
|
|
125
60
|
|
|
126
61
|
import { useEffect, useRef } from 'react';
|
|
127
|
-
import { ThredSDK } from 'thred-track';
|
|
62
|
+
import { ThredSDK } from '@thred-apps/thred-track';
|
|
128
63
|
|
|
129
64
|
export function ThredProvider({ children }: { children: React.ReactNode }) {
|
|
130
65
|
const thredRef = useRef<ThredSDK | null>(null);
|
|
@@ -133,7 +68,6 @@ export function ThredProvider({ children }: { children: React.ReactNode }) {
|
|
|
133
68
|
thredRef.current = new ThredSDK({
|
|
134
69
|
browserKey: process.env.NEXT_PUBLIC_THRED_KEY!,
|
|
135
70
|
});
|
|
136
|
-
|
|
137
71
|
return () => thredRef.current?.destroy();
|
|
138
72
|
}, []);
|
|
139
73
|
|
|
@@ -141,162 +75,17 @@ export function ThredProvider({ children }: { children: React.ReactNode }) {
|
|
|
141
75
|
}
|
|
142
76
|
```
|
|
143
77
|
|
|
144
|
-
### Delayed Initialization
|
|
145
|
-
|
|
146
|
-
If you need to control when tracking starts (e.g., after user consent):
|
|
147
|
-
|
|
148
|
-
```typescript
|
|
149
|
-
import { ThredSDK } from 'thred-track';
|
|
150
|
-
|
|
151
|
-
const thred = new ThredSDK({
|
|
152
|
-
browserKey: 'YOUR_KEY',
|
|
153
|
-
autoInit: false,
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
// Later, when ready:
|
|
157
|
-
await thred.init();
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
## Advanced API
|
|
161
|
-
|
|
162
|
-
These methods are available for advanced use cases but are **not required** for typical usage — the SDK handles everything automatically.
|
|
163
|
-
|
|
164
|
-
#### `identify(leadData: LeadData): Promise<void>`
|
|
165
|
-
|
|
166
|
-
Manually identify a user outside of automatic form tracking (e.g., after OAuth or a custom flow):
|
|
167
|
-
|
|
168
|
-
```typescript
|
|
169
|
-
await thred.identify({
|
|
170
|
-
name: 'John Doe',
|
|
171
|
-
email: 'john@example.com',
|
|
172
|
-
company: 'Acme Inc',
|
|
173
|
-
});
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
#### `destroy(): void`
|
|
177
|
-
|
|
178
|
-
Clean up the SDK instance and remove event listeners. Use this when unmounting in SPAs:
|
|
179
|
-
|
|
180
|
-
```typescript
|
|
181
|
-
thred.destroy();
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
## Development
|
|
185
|
-
|
|
186
|
-
### Setup
|
|
187
|
-
|
|
188
|
-
```bash
|
|
189
|
-
npm install
|
|
190
|
-
npm run build
|
|
191
|
-
npm run dev # Watch mode
|
|
192
|
-
npm test
|
|
193
|
-
npm run lint
|
|
194
|
-
npm run format
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
### Project Structure
|
|
198
|
-
|
|
199
|
-
```
|
|
200
|
-
thred-track/
|
|
201
|
-
├── src/
|
|
202
|
-
│ ├── core/ # Core SDK functionality
|
|
203
|
-
│ │ ├── api.ts # API client
|
|
204
|
-
│ │ ├── fingerprint.ts # Fingerprint management
|
|
205
|
-
│ │ └── tracker.ts # Event tracking
|
|
206
|
-
│ ├── utils/ # Utility functions
|
|
207
|
-
│ │ ├── detector.ts # ChatGPT detection
|
|
208
|
-
│ │ └── logger.ts # Logging utility
|
|
209
|
-
│ ├── types/ # TypeScript definitions
|
|
210
|
-
│ │ └── index.ts
|
|
211
|
-
│ ├── __tests__/ # Test files
|
|
212
|
-
│ └── index.ts # Main entry point
|
|
213
|
-
├── dist/ # Build output
|
|
214
|
-
└── package.json
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
### Building
|
|
218
|
-
|
|
219
|
-
The SDK builds to multiple formats:
|
|
220
|
-
|
|
221
|
-
- **UMD** (`dist/thred-track.umd.js`) — For script tags
|
|
222
|
-
- **CommonJS** (`dist/index.js`) — For Node.js / bundlers
|
|
223
|
-
- **ES Module** (`dist/index.esm.js`) — For modern bundlers
|
|
224
|
-
- **TypeScript** (`dist/index.d.ts`) — Type definitions
|
|
225
|
-
|
|
226
|
-
### Testing
|
|
227
|
-
|
|
228
|
-
```bash
|
|
229
|
-
npm test
|
|
230
|
-
npm run test:watch
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
### Local Testing
|
|
234
|
-
|
|
235
|
-
```bash
|
|
236
|
-
npm run serve
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
Then open http://localhost:8080/basic.html?utm_source=chatgpt
|
|
240
|
-
|
|
241
|
-
## Configuration
|
|
242
|
-
|
|
243
|
-
The SDK fetches configuration from your Thred API automatically on init:
|
|
244
|
-
|
|
245
|
-
```json
|
|
246
|
-
{
|
|
247
|
-
"enabled": true,
|
|
248
|
-
"type": "custom",
|
|
249
|
-
"formId": "form",
|
|
250
|
-
"emailId": "email",
|
|
251
|
-
"nameId": "name",
|
|
252
|
-
"companyId": "company",
|
|
253
|
-
"hasChatSession": true
|
|
254
|
-
}
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
This config controls which form to track, which fields to extract, and whether the visitor has an existing ChatGPT session.
|
|
258
|
-
|
|
259
78
|
## Privacy & Security
|
|
260
79
|
|
|
261
|
-
- Only tracks visitors from ChatGPT
|
|
262
|
-
-
|
|
263
|
-
- All tracking controlled by API configuration
|
|
80
|
+
- Only tracks visitors arriving from ChatGPT
|
|
81
|
+
- Browser fingerprinting — no cookies required
|
|
264
82
|
- No PII collected without explicit user submission
|
|
265
|
-
-
|
|
83
|
+
- GDPR and CCPA compliant
|
|
266
84
|
|
|
267
85
|
## Browser Support
|
|
268
86
|
|
|
269
|
-
|
|
270
|
-
- Firefox (latest)
|
|
271
|
-
- Safari (latest)
|
|
272
|
-
- Opera (latest)
|
|
273
|
-
|
|
274
|
-
Requires ES2015+ support.
|
|
275
|
-
|
|
276
|
-
## API Endpoints
|
|
277
|
-
|
|
278
|
-
- **Config**: `GET /v1/config?browserKey={key}`
|
|
279
|
-
- **Page View**: `POST /v1/events/page-view?browserKey={key}`
|
|
280
|
-
- **Enrich**: `POST /v1/customers/enrich?browserKey={key}`
|
|
281
|
-
|
|
282
|
-
## TypeScript
|
|
283
|
-
|
|
284
|
-
Full TypeScript support with exported types:
|
|
285
|
-
|
|
286
|
-
```typescript
|
|
287
|
-
import type {
|
|
288
|
-
ThredOptions,
|
|
289
|
-
ThredConfig,
|
|
290
|
-
LeadData,
|
|
291
|
-
PageViewPayload,
|
|
292
|
-
EnrichPayload,
|
|
293
|
-
} from 'thred-track';
|
|
294
|
-
```
|
|
87
|
+
Chrome, Firefox, Safari, Edge (latest versions). Requires ES2015+.
|
|
295
88
|
|
|
296
89
|
## License
|
|
297
90
|
|
|
298
91
|
MIT
|
|
299
|
-
|
|
300
|
-
## Support
|
|
301
|
-
|
|
302
|
-
For questions or issues, please open a GitHub issue or contact support@thred.dev.
|
package/dist/core/tracker.d.ts
CHANGED
|
@@ -8,7 +8,16 @@ export declare class Tracker {
|
|
|
8
8
|
private logger;
|
|
9
9
|
private config;
|
|
10
10
|
private formObserver;
|
|
11
|
+
private lastTrackedUrl;
|
|
12
|
+
private popstateHandler;
|
|
13
|
+
private originalPushState;
|
|
14
|
+
private originalReplaceState;
|
|
11
15
|
constructor(api: ThredAPI, fingerprint: FingerprintManager, logger: Logger);
|
|
16
|
+
/**
|
|
17
|
+
* Resolves when the DOM is interactive (document.body exists).
|
|
18
|
+
* Safe to call whether the script is in <head> or <body>.
|
|
19
|
+
*/
|
|
20
|
+
private domReady;
|
|
12
21
|
/**
|
|
13
22
|
* Initialize tracker with config
|
|
14
23
|
*/
|
|
@@ -25,6 +34,11 @@ export declare class Tracker {
|
|
|
25
34
|
* Identify user and enrich lead data
|
|
26
35
|
*/
|
|
27
36
|
identify(leadData: LeadData): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Track page views on SPA route changes by patching pushState/replaceState
|
|
39
|
+
* and listening for popstate.
|
|
40
|
+
*/
|
|
41
|
+
private setupRouteTracking;
|
|
28
42
|
/**
|
|
29
43
|
* Setup automatic form tracking
|
|
30
44
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/core/tracker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,QAAQ,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEnD,qBAAa,OAAO;IAClB,OAAO,CAAC,GAAG,CAAW;IACtB,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,YAAY,CAAiC;
|
|
1
|
+
{"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/core/tracker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,QAAQ,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEnD,qBAAa,OAAO;IAClB,OAAO,CAAC,GAAG,CAAW;IACtB,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,YAAY,CAAiC;IACrD,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,eAAe,CAA6B;IACpD,OAAO,CAAC,iBAAiB,CAAyC;IAClE,OAAO,CAAC,oBAAoB,CAA4C;gBAGtE,GAAG,EAAE,QAAQ,EACb,WAAW,EAAE,kBAAkB,EAC/B,MAAM,EAAE,MAAM;IAOhB;;;OAGG;IACH,OAAO,CAAC,QAAQ;IAUhB;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAoC3B;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBpC;;OAEG;IACG,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IA6BxD;;OAEG;IACG,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAcjD;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IA8B1B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAsGzB;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAOlC;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAuBjC;;OAEG;IACH,OAAO,IAAI,IAAI;CAqBhB"}
|
package/dist/index.esm.js
CHANGED
|
@@ -258,10 +258,28 @@ class Tracker {
|
|
|
258
258
|
constructor(api, fingerprint, logger) {
|
|
259
259
|
this.config = null;
|
|
260
260
|
this.formObserver = null;
|
|
261
|
+
this.lastTrackedUrl = null;
|
|
262
|
+
this.popstateHandler = null;
|
|
263
|
+
this.originalPushState = null;
|
|
264
|
+
this.originalReplaceState = null;
|
|
261
265
|
this.api = api;
|
|
262
266
|
this.fingerprint = fingerprint;
|
|
263
267
|
this.logger = logger;
|
|
264
268
|
}
|
|
269
|
+
/**
|
|
270
|
+
* Resolves when the DOM is interactive (document.body exists).
|
|
271
|
+
* Safe to call whether the script is in <head> or <body>.
|
|
272
|
+
*/
|
|
273
|
+
domReady() {
|
|
274
|
+
return new Promise((resolve) => {
|
|
275
|
+
if (document.readyState === 'loading') {
|
|
276
|
+
document.addEventListener('DOMContentLoaded', () => resolve(), { once: true });
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
resolve();
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
}
|
|
265
283
|
/**
|
|
266
284
|
* Initialize tracker with config
|
|
267
285
|
*/
|
|
@@ -283,13 +301,17 @@ class Tracker {
|
|
|
283
301
|
this.logger.log('No chat session for this fingerprint - exiting');
|
|
284
302
|
return;
|
|
285
303
|
}
|
|
286
|
-
//
|
|
304
|
+
// Track initial page view
|
|
287
305
|
if (isFromChatGPT()) {
|
|
288
306
|
yield this.trackPageView();
|
|
289
307
|
}
|
|
290
308
|
else {
|
|
291
309
|
this.logger.log('UTM not from ChatGPT - skipping page view');
|
|
292
310
|
}
|
|
311
|
+
// Track SPA route changes (only needs window/history — safe before DOM ready)
|
|
312
|
+
this.setupRouteTracking();
|
|
313
|
+
// Wait for document.body to exist before touching the DOM
|
|
314
|
+
yield this.domReady();
|
|
293
315
|
// Setup form tracking
|
|
294
316
|
this.setupFormTracking();
|
|
295
317
|
});
|
|
@@ -358,6 +380,35 @@ class Tracker {
|
|
|
358
380
|
});
|
|
359
381
|
});
|
|
360
382
|
}
|
|
383
|
+
/**
|
|
384
|
+
* Track page views on SPA route changes by patching pushState/replaceState
|
|
385
|
+
* and listening for popstate.
|
|
386
|
+
*/
|
|
387
|
+
setupRouteTracking() {
|
|
388
|
+
if (typeof window === 'undefined')
|
|
389
|
+
return;
|
|
390
|
+
this.lastTrackedUrl = window.location.href;
|
|
391
|
+
const onRouteChange = () => {
|
|
392
|
+
const currentUrl = window.location.href;
|
|
393
|
+
if (currentUrl === this.lastTrackedUrl)
|
|
394
|
+
return;
|
|
395
|
+
this.lastTrackedUrl = currentUrl;
|
|
396
|
+
this.logger.log('Route change detected:', currentUrl);
|
|
397
|
+
this.trackPageView();
|
|
398
|
+
};
|
|
399
|
+
this.popstateHandler = onRouteChange;
|
|
400
|
+
window.addEventListener('popstate', this.popstateHandler);
|
|
401
|
+
this.originalPushState = history.pushState.bind(history);
|
|
402
|
+
this.originalReplaceState = history.replaceState.bind(history);
|
|
403
|
+
history.pushState = (...args) => {
|
|
404
|
+
this.originalPushState(...args);
|
|
405
|
+
onRouteChange();
|
|
406
|
+
};
|
|
407
|
+
history.replaceState = (...args) => {
|
|
408
|
+
this.originalReplaceState(...args);
|
|
409
|
+
onRouteChange();
|
|
410
|
+
};
|
|
411
|
+
}
|
|
361
412
|
/**
|
|
362
413
|
* Setup automatic form tracking
|
|
363
414
|
*/
|
|
@@ -485,6 +536,18 @@ class Tracker {
|
|
|
485
536
|
this.formObserver.disconnect();
|
|
486
537
|
this.formObserver = null;
|
|
487
538
|
}
|
|
539
|
+
if (this.popstateHandler) {
|
|
540
|
+
window.removeEventListener('popstate', this.popstateHandler);
|
|
541
|
+
this.popstateHandler = null;
|
|
542
|
+
}
|
|
543
|
+
if (this.originalPushState) {
|
|
544
|
+
history.pushState = this.originalPushState;
|
|
545
|
+
this.originalPushState = null;
|
|
546
|
+
}
|
|
547
|
+
if (this.originalReplaceState) {
|
|
548
|
+
history.replaceState = this.originalReplaceState;
|
|
549
|
+
this.originalReplaceState = null;
|
|
550
|
+
}
|
|
488
551
|
}
|
|
489
552
|
}
|
|
490
553
|
|