@noirtrack/sdk 0.2.0 → 0.2.1
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/CHANGELOG.md +7 -1
- package/README.md +2 -2
- package/dist/web.d.ts +2 -2
- package/dist/web.js +21 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@noirtrack/sdk` are documented here. This project follows semantic versioning (while pre-1.0, a minor bump may include breaking changes).
|
|
4
4
|
|
|
5
|
+
## 0.2.1
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **Scroll goals on tall sections.** `data-noir-scroll-threshold` is the fraction of the *element* visible at once, so a section taller than the viewport could never reach it and the goal never fired. The effective threshold is now capped to what's reachable for the element's height, so a tall section fires once it has essentially filled the screen. Short elements are unaffected. The same fix ships in the hosted snippet.
|
|
10
|
+
|
|
5
11
|
## 0.2.0
|
|
6
12
|
|
|
7
13
|
### Changed
|
|
8
14
|
|
|
9
|
-
- **Breaking (web client):** `block` is now a boolean. Turn on the
|
|
15
|
+
- **Breaking (web client):** `block` is now a boolean. Turn on the firewall with `createClient({ block: true })` instead of `block: 'redirect' | 'overlay'`. Whether it monitors or blocks, and how a block looks (redirect or overlay), are now set per site in Firewall settings, with no code change. If you passed `block: 'redirect'` or `block: 'overlay'`, change it to `block: true`.
|
|
10
16
|
|
|
11
17
|
### Added
|
|
12
18
|
|
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ noir.identify('user_123', { email });
|
|
|
26
26
|
noir.revenue({ checkoutId: 'cs_test_123' });
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
Pageviews and route changes are automatic. Events are batched and sent with `sendBeacon`. Set `cookieless: true` for a no-cookie mode, or `block: true` to turn on the
|
|
29
|
+
Pageviews and route changes are automatic. Events are batched and sent with `sendBeacon`. Set `cookieless: true` for a no-cookie mode, or `block: true` to turn on the firewall. Whether it monitors or blocks, and how a block looks (redirect or overlay), are set in your Firewall settings, with no code change. Safe to import in SSR (it does nothing without a window). Also: `view(path?)`, `reset()`, `flush()`, `links.decorate(url)`.
|
|
30
30
|
|
|
31
31
|
## React Native
|
|
32
32
|
|
|
@@ -95,7 +95,7 @@ The guards resolve the visitor IP from `CF-Connecting-IP`, `True-Client-IP`, the
|
|
|
95
95
|
| `timeoutMs` | `800` | all | Abort a call after this, then fail open. |
|
|
96
96
|
| `autoPageviews` | `true` | web | Capture initial + SPA pageviews. |
|
|
97
97
|
| `cookieless` | `false` | web | No cookies; ids in sessionStorage. |
|
|
98
|
-
| `block` | `false` | web | Turn on the
|
|
98
|
+
| `block` | `false` | web | Turn on the firewall (Monitor/Block set in dashboard). |
|
|
99
99
|
| `flushIntervalMs` / `maxQueueSize` | `5000` / `10` | web, RN | Batch flush tuning. |
|
|
100
100
|
| `storage` | in-memory | RN | Async store (pass AsyncStorage). |
|
|
101
101
|
| `onBlock` / `blockStatus` / `blockedPage` | `block` / `403` / none | adapters | Block handling. |
|
package/dist/web.d.ts
CHANGED
|
@@ -11,8 +11,8 @@ export interface WebClientOptions {
|
|
|
11
11
|
cookieless?: boolean;
|
|
12
12
|
/** Track on localhost too (off by default, like the hosted script). */
|
|
13
13
|
allowLocalhost?: boolean;
|
|
14
|
-
/** Turn on the
|
|
15
|
-
*
|
|
14
|
+
/** Turn on the firewall on the first view. Whether it monitors or blocks, and how a block looks
|
|
15
|
+
* (redirect or overlay), are set per site in Firewall settings. Off by default. */
|
|
16
16
|
block?: boolean;
|
|
17
17
|
/** Optional redirect target if none is set in Firewall settings. */
|
|
18
18
|
blockedPage?: string;
|
package/dist/web.js
CHANGED
|
@@ -70,6 +70,11 @@ function initDeclarativeGoals(fire) {
|
|
|
70
70
|
}, true);
|
|
71
71
|
if (!('IntersectionObserver' in window))
|
|
72
72
|
return;
|
|
73
|
+
// Granular thresholds so the callback runs across the whole scroll range; the actual trigger is
|
|
74
|
+
// computed live per element (see below), so we can't rely on a single fixed threshold.
|
|
75
|
+
const STEPS = [];
|
|
76
|
+
for (let s = 0; s <= 1.0001; s += 0.05)
|
|
77
|
+
STEPS.push(Math.round(s * 100) / 100);
|
|
73
78
|
const observed = new WeakSet();
|
|
74
79
|
const observeScroll = (el) => {
|
|
75
80
|
if (observed.has(el))
|
|
@@ -78,15 +83,25 @@ function initDeclarativeGoals(fire) {
|
|
|
78
83
|
const name = el.getAttribute('data-noir-scroll');
|
|
79
84
|
if (!name)
|
|
80
85
|
return;
|
|
81
|
-
let
|
|
82
|
-
if (!(
|
|
83
|
-
|
|
86
|
+
let requested = parseFloat(el.getAttribute('data-noir-scroll-threshold') ?? '');
|
|
87
|
+
if (!(requested > 0 && requested <= 1))
|
|
88
|
+
requested = 0.5;
|
|
84
89
|
const delay = parseInt(el.getAttribute('data-noir-scroll-delay') ?? '', 10) || 0;
|
|
85
90
|
const obs = new IntersectionObserver((entries) => {
|
|
86
91
|
for (const entry of entries) {
|
|
87
|
-
if (entry.isIntersecting
|
|
92
|
+
if (!entry.isIntersecting)
|
|
93
|
+
continue;
|
|
94
|
+
// A section taller than the viewport can never expose `requested` of itself at once —
|
|
95
|
+
// the most ever visible is viewportHeight/elementHeight. Compare against that reachable
|
|
96
|
+
// max (×0.9) so a tall element still fires once it has essentially filled the screen,
|
|
97
|
+
// instead of never firing. Short elements keep their requested threshold. // why
|
|
98
|
+
const elHeight = entry.boundingClientRect.height;
|
|
99
|
+
const viewport = entry.rootBounds?.height || window.innerHeight || 0;
|
|
100
|
+
const reachable = elHeight > 0 && viewport > 0 ? (viewport / elHeight) * 0.9 : 1;
|
|
101
|
+
const effective = Math.min(requested, reachable);
|
|
102
|
+
if (entry.intersectionRatio >= effective) {
|
|
88
103
|
obs.disconnect(); // once per element per page
|
|
89
|
-
const meta = { scroll_percentage: scrollPercent(), threshold };
|
|
104
|
+
const meta = { scroll_percentage: scrollPercent(), threshold: requested };
|
|
90
105
|
if (delay > 0)
|
|
91
106
|
setTimeout(() => fire(name, meta), delay);
|
|
92
107
|
else
|
|
@@ -94,7 +109,7 @@ function initDeclarativeGoals(fire) {
|
|
|
94
109
|
return;
|
|
95
110
|
}
|
|
96
111
|
}
|
|
97
|
-
}, { threshold });
|
|
112
|
+
}, { threshold: STEPS });
|
|
98
113
|
obs.observe(el);
|
|
99
114
|
};
|
|
100
115
|
const scan = () => document.querySelectorAll('[data-noir-scroll]').forEach(observeScroll);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noirtrack/sdk",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "NoirTrack server SDK. Block bots and bad traffic before your app renders, and record goals, revenue, and identify from your backend with one secret key. Framework-agnostic core plus Next.js, Express, and fetch/edge adapters.",
|
|
5
5
|
"homepage": "https://noirtrack.com/docs",
|
|
6
6
|
"bugs": {
|