@valbuild/react 0.148.2 → 0.148.4
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 +24 -0
- package/analytics/dist/valbuild-react-analytics.browser.esm.js +950 -0
- package/analytics/dist/valbuild-react-analytics.cjs.d.ts +2 -0
- package/analytics/dist/valbuild-react-analytics.cjs.dev.js +962 -0
- package/analytics/dist/valbuild-react-analytics.cjs.js +7 -0
- package/analytics/dist/valbuild-react-analytics.cjs.prod.js +962 -0
- package/analytics/dist/valbuild-react-analytics.esm.js +953 -0
- package/analytics/dist/valbuild-react-analytics.worker.esm.js +232 -0
- package/analytics/package.json +7 -0
- package/dist/createForOfIteratorHelper-69c4a419.esm.js +52 -0
- package/dist/createForOfIteratorHelper-6f9dc6fa.cjs.prod.js +54 -0
- package/dist/createForOfIteratorHelper-73fe9a1a.worker.esm.js +52 -0
- package/dist/createForOfIteratorHelper-8a871dc3.cjs.dev.js +54 -0
- package/dist/createForOfIteratorHelper-c0be3691.browser.esm.js +52 -0
- package/dist/declarations/src/analytics/beacon.d.ts +80 -0
- package/dist/declarations/src/analytics/index.d.ts +3 -0
- package/dist/declarations/src/analytics/splitValPaths.d.ts +12 -0
- package/dist/declarations/src/analytics/tracker.d.ts +64 -0
- package/dist/{raw-eda286dd.cjs.dev.js → raw-c2b82a01.cjs.dev.js} +23 -71
- package/dist/{raw-7aae8bf6.esm.js → raw-cd78aea7.browser.esm.js} +4 -51
- package/dist/{raw-00151a05.worker.esm.js → raw-d156d004.worker.esm.js} +4 -51
- package/dist/{raw-9bb55a5f.browser.esm.js → raw-d43ba7b8.esm.js} +4 -51
- package/dist/{raw-f3f7e399.cjs.prod.js → raw-de29c973.cjs.prod.js} +23 -71
- package/dist/{slicedToArray-e9e8e991.cjs.dev.js → slicedToArray-387314c6.cjs.dev.js} +0 -11
- package/dist/{slicedToArray-0c0a3b4a.esm.js → slicedToArray-3d4c6640.esm.js} +1 -11
- package/dist/{slicedToArray-86004d59.cjs.prod.js → slicedToArray-64c83d56.cjs.prod.js} +0 -11
- package/dist/{slicedToArray-7d0170b6.worker.esm.js → slicedToArray-8b1a55e5.worker.esm.js} +1 -11
- package/dist/{slicedToArray-9cce0d9f.browser.esm.js → slicedToArray-8f9b0d84.browser.esm.js} +1 -11
- package/dist/toConsumableArray-203e636a.cjs.prod.js +21 -0
- package/dist/toConsumableArray-5335b4b0.worker.esm.js +19 -0
- package/dist/toConsumableArray-991f680f.browser.esm.js +19 -0
- package/dist/toConsumableArray-c950e394.esm.js +19 -0
- package/dist/toConsumableArray-d7cf1601.cjs.dev.js +21 -0
- package/dist/typeof-16428c61.cjs.prod.js +13 -0
- package/dist/typeof-9915e135.browser.esm.js +11 -0
- package/dist/typeof-a1531d8f.esm.js +11 -0
- package/dist/typeof-b568f48f.cjs.dev.js +13 -0
- package/dist/typeof-e0c837cc.worker.esm.js +11 -0
- package/internal/dist/valbuild-react-internal.browser.esm.js +5 -18
- package/internal/dist/valbuild-react-internal.cjs.dev.js +6 -19
- package/internal/dist/valbuild-react-internal.cjs.prod.js +6 -19
- package/internal/dist/valbuild-react-internal.esm.js +5 -18
- package/internal/dist/valbuild-react-internal.worker.esm.js +5 -18
- package/jsx-dev-runtime/dist/valbuild-react-jsx-dev-runtime.browser.esm.js +2 -1
- package/jsx-dev-runtime/dist/valbuild-react-jsx-dev-runtime.cjs.dev.js +3 -2
- package/jsx-dev-runtime/dist/valbuild-react-jsx-dev-runtime.cjs.prod.js +3 -2
- package/jsx-dev-runtime/dist/valbuild-react-jsx-dev-runtime.esm.js +2 -1
- package/jsx-dev-runtime/dist/valbuild-react-jsx-dev-runtime.worker.esm.js +2 -1
- package/jsx-runtime/dist/valbuild-react-jsx-runtime.browser.esm.js +2 -1
- package/jsx-runtime/dist/valbuild-react-jsx-runtime.cjs.dev.js +3 -2
- package/jsx-runtime/dist/valbuild-react-jsx-runtime.cjs.prod.js +3 -2
- package/jsx-runtime/dist/valbuild-react-jsx-runtime.esm.js +2 -1
- package/jsx-runtime/dist/valbuild-react-jsx-runtime.worker.esm.js +2 -1
- package/package.json +16 -6
- package/stega/dist/valbuild-react-stega.browser.esm.js +5 -3
- package/stega/dist/valbuild-react-stega.cjs.dev.js +8 -6
- package/stega/dist/valbuild-react-stega.cjs.prod.js +8 -6
- package/stega/dist/valbuild-react-stega.esm.js +5 -3
- package/stega/dist/valbuild-react-stega.worker.esm.js +5 -3
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { _ as _toConsumableArray } from '../../dist/toConsumableArray-5335b4b0.worker.esm.js';
|
|
2
|
+
import { _ as _slicedToArray } from '../../dist/slicedToArray-8b1a55e5.worker.esm.js';
|
|
3
|
+
import { _ as _createForOfIteratorHelper } from '../../dist/createForOfIteratorHelper-73fe9a1a.worker.esm.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The analytics wire format, version 1: what the browser sends to
|
|
7
|
+
* `POST /api/val/analytics`. See `docs/plans/analytics.md`, "Wire format".
|
|
8
|
+
*
|
|
9
|
+
* Nothing in this directory may import `@valbuild/core`, `@valbuild/shared`
|
|
10
|
+
* or zod: this is code every visitor of a site downloads, and those three are
|
|
11
|
+
* most of the weight Val already puts on a page (`client-bundle-weight.md`).
|
|
12
|
+
* `imports.test.ts` keeps it so. The zod schema the server parses this with
|
|
13
|
+
* is `AnalyticsBeacon` in `@valbuild/shared/internal`, and `beacon.test.ts`
|
|
14
|
+
* checks the two agree.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** What only the first beacon of a page view carries. Its presence IS the page view. */
|
|
18
|
+
|
|
19
|
+
/** Module file path → module paths (the part of a source path after `?p=`). */
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The receiver rejects a beacon above these (`AnalyticsBeacon` in
|
|
23
|
+
* `@valbuild/shared/internal` repeats them), so the sender never sends more:
|
|
24
|
+
* it cuts or drops what is longer, and splits what is larger.
|
|
25
|
+
*/
|
|
26
|
+
var MAX_PATHS_PER_BEACON = 200;
|
|
27
|
+
var MAX_ROUTE_LENGTH = 512;
|
|
28
|
+
var MAX_UTM_LENGTH = 100;
|
|
29
|
+
var MAX_CV_LENGTH = 128;
|
|
30
|
+
var MAX_MODULE_FILE_PATH_LENGTH = 512;
|
|
31
|
+
var MAX_MODULE_PATH_LENGTH = 1024;
|
|
32
|
+
/**
|
|
33
|
+
* A beacon's size in bytes of JSON, below the 16 KB Val's hosting accepts --
|
|
34
|
+
* 200 long router keys are about 18 KB. `sendBeacon` itself takes 64 KB.
|
|
35
|
+
*/
|
|
36
|
+
var MAX_BEACON_BYTES = 12000;
|
|
37
|
+
var MODULE_FILE_PATH_SEP = "?p=";
|
|
38
|
+
|
|
39
|
+
/** Splits a source path into its module file path and its module path. */
|
|
40
|
+
function splitSourcePath(sourcePath) {
|
|
41
|
+
var at = sourcePath.indexOf(MODULE_FILE_PATH_SEP);
|
|
42
|
+
if (at === -1) {
|
|
43
|
+
return [sourcePath, ""];
|
|
44
|
+
}
|
|
45
|
+
return [sourcePath.slice(0, at), sourcePath.slice(at + MODULE_FILE_PATH_SEP.length)];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The beacons that carry `rendered` and `viewed`: at most
|
|
50
|
+
* `MAX_PATHS_PER_BEACON` paths and about `MAX_BEACON_BYTES` each. `view`, when
|
|
51
|
+
* given, goes in the first. Returns none when there is nothing to say.
|
|
52
|
+
*
|
|
53
|
+
* A path longer than the receiver takes is dropped rather than cut: half a
|
|
54
|
+
* path names some other content, or none.
|
|
55
|
+
*/
|
|
56
|
+
function buildBeacons(args) {
|
|
57
|
+
var _args$cv;
|
|
58
|
+
var counted = function counted(kind, sourcePath) {
|
|
59
|
+
var _splitSourcePath = splitSourcePath(sourcePath),
|
|
60
|
+
_splitSourcePath2 = _slicedToArray(_splitSourcePath, 2),
|
|
61
|
+
moduleFilePath = _splitSourcePath2[0],
|
|
62
|
+
modulePath = _splitSourcePath2[1];
|
|
63
|
+
if (moduleFilePath.length > MAX_MODULE_FILE_PATH_LENGTH || modulePath.length > MAX_MODULE_PATH_LENGTH) {
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
return [{
|
|
67
|
+
kind: kind,
|
|
68
|
+
moduleFilePath: moduleFilePath,
|
|
69
|
+
modulePath: modulePath
|
|
70
|
+
}];
|
|
71
|
+
};
|
|
72
|
+
var all = [].concat(_toConsumableArray(args.rendered.flatMap(function (path) {
|
|
73
|
+
return counted("rendered", path);
|
|
74
|
+
})), _toConsumableArray(args.viewed.flatMap(function (path) {
|
|
75
|
+
return counted("viewed", path);
|
|
76
|
+
})));
|
|
77
|
+
if (all.length === 0 && !args.view) {
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
var cv = (_args$cv = args.cv) === null || _args$cv === void 0 ? void 0 : _args$cv.slice(0, MAX_CV_LENGTH);
|
|
81
|
+
var empty = function empty(withView) {
|
|
82
|
+
var beacon = {
|
|
83
|
+
v: 1,
|
|
84
|
+
route: args.route,
|
|
85
|
+
rendered: {},
|
|
86
|
+
viewed: {}
|
|
87
|
+
};
|
|
88
|
+
if (cv) {
|
|
89
|
+
beacon.cv = cv;
|
|
90
|
+
}
|
|
91
|
+
if (withView && args.view) {
|
|
92
|
+
beacon.view = args.view;
|
|
93
|
+
}
|
|
94
|
+
return beacon;
|
|
95
|
+
};
|
|
96
|
+
var beacons = [];
|
|
97
|
+
var beacon = empty(true);
|
|
98
|
+
var paths = 0;
|
|
99
|
+
var bytes = byteLength(JSON.stringify(beacon));
|
|
100
|
+
// What adding a path costs: the path and a comma, and a new key when its
|
|
101
|
+
// module is not in this beacon yet. An estimate in UTF-8 bytes, close
|
|
102
|
+
// enough to keep well under the limit.
|
|
103
|
+
var costOf = function costOf(path) {
|
|
104
|
+
return byteLength(JSON.stringify(path.modulePath)) + 1 + (beacon[path.kind][path.moduleFilePath] ? 0 : byteLength(JSON.stringify(path.moduleFilePath)) + 4);
|
|
105
|
+
};
|
|
106
|
+
var _iterator2 = _createForOfIteratorHelper(all),
|
|
107
|
+
_step2;
|
|
108
|
+
try {
|
|
109
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
110
|
+
var _beacon$path$kind, _path$moduleFilePath, _beacon$path$kind$_pa;
|
|
111
|
+
var path = _step2.value;
|
|
112
|
+
var cost = costOf(path);
|
|
113
|
+
if (paths > 0 && (paths === MAX_PATHS_PER_BEACON || bytes + cost > MAX_BEACON_BYTES)) {
|
|
114
|
+
beacons.push(beacon);
|
|
115
|
+
beacon = empty(false);
|
|
116
|
+
paths = 0;
|
|
117
|
+
bytes = byteLength(JSON.stringify(beacon));
|
|
118
|
+
cost = costOf(path);
|
|
119
|
+
}
|
|
120
|
+
((_beacon$path$kind$_pa = (_beacon$path$kind = beacon[path.kind])[_path$moduleFilePath = path.moduleFilePath]) !== null && _beacon$path$kind$_pa !== void 0 ? _beacon$path$kind$_pa : _beacon$path$kind[_path$moduleFilePath] = []).push(path.modulePath);
|
|
121
|
+
paths += 1;
|
|
122
|
+
bytes += cost;
|
|
123
|
+
}
|
|
124
|
+
} catch (err) {
|
|
125
|
+
_iterator2.e(err);
|
|
126
|
+
} finally {
|
|
127
|
+
_iterator2.f();
|
|
128
|
+
}
|
|
129
|
+
beacons.push(beacon);
|
|
130
|
+
return beacons;
|
|
131
|
+
}
|
|
132
|
+
function byteLength(text) {
|
|
133
|
+
return new TextEncoder().encode(text).length;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* The source paths in a `data-val-path` attribute.
|
|
138
|
+
*
|
|
139
|
+
* One element can show several pieces of content, and `attrs()` and
|
|
140
|
+
* `autoTagJSX` join their paths with commas. Core's `splitJoinedSourcePaths`
|
|
141
|
+
* splits on every comma, which cuts a path whose record key holds one
|
|
142
|
+
* (`"/blog/a,b"`). This splits only on commas outside the JSON strings a
|
|
143
|
+
* module path is made of, so it agrees with core wherever core is right and
|
|
144
|
+
* keeps such a path whole. It is here rather than imported because nothing in
|
|
145
|
+
* this directory may import core -- see `beacon.ts`.
|
|
146
|
+
*/
|
|
147
|
+
function splitValPaths(attribute) {
|
|
148
|
+
if (!attribute) {
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
151
|
+
var paths = [];
|
|
152
|
+
var current = "";
|
|
153
|
+
var inString = false;
|
|
154
|
+
var escaped = false;
|
|
155
|
+
var _iterator = _createForOfIteratorHelper(attribute),
|
|
156
|
+
_step;
|
|
157
|
+
try {
|
|
158
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
159
|
+
var _char = _step.value;
|
|
160
|
+
if (inString) {
|
|
161
|
+
current += _char;
|
|
162
|
+
if (escaped) {
|
|
163
|
+
escaped = false;
|
|
164
|
+
} else if (_char === "\\") {
|
|
165
|
+
escaped = true;
|
|
166
|
+
} else if (_char === '"') {
|
|
167
|
+
inString = false;
|
|
168
|
+
}
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
if (_char === '"') {
|
|
172
|
+
inString = true;
|
|
173
|
+
current += _char;
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (_char === ",") {
|
|
177
|
+
if (current) {
|
|
178
|
+
paths.push(current);
|
|
179
|
+
}
|
|
180
|
+
current = "";
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
current += _char;
|
|
184
|
+
}
|
|
185
|
+
} catch (err) {
|
|
186
|
+
_iterator.e(err);
|
|
187
|
+
} finally {
|
|
188
|
+
_iterator.f();
|
|
189
|
+
}
|
|
190
|
+
if (current) {
|
|
191
|
+
paths.push(current);
|
|
192
|
+
}
|
|
193
|
+
return paths;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** Every 5%, so an element far taller than the screen still crosses one. */
|
|
197
|
+
Array.from({
|
|
198
|
+
length: 21
|
|
199
|
+
}, function (_, i) {
|
|
200
|
+
return i / 20;
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Counts which content a visitor's page shows, and sends it.
|
|
205
|
+
*
|
|
206
|
+
* - **Rendered**: an element with a `data-val-path` is in the document.
|
|
207
|
+
* - **Viewed**: one is at least half visible -- or covers at least half the
|
|
208
|
+
* viewport, for an element taller than it -- for `viewedAfterMs` without a
|
|
209
|
+
* break, while the page is visible.
|
|
210
|
+
*
|
|
211
|
+
* Each path counts at most once of each per page view. A page view starts with
|
|
212
|
+
* the page and with every client-side navigation to another pathname; content
|
|
213
|
+
* still on screen after one (a header, a footer) counts again for the new one,
|
|
214
|
+
* because it was rendered on it.
|
|
215
|
+
*
|
|
216
|
+
* Returns null where it does nothing: on the server, and for an automated
|
|
217
|
+
* browser (`navigator.webdriver`). The caller decides the rest -- draft mode,
|
|
218
|
+
* the Studio's canvas and an editor browsing with Val enabled all count
|
|
219
|
+
* nothing, and the provider does not start it for them.
|
|
220
|
+
*
|
|
221
|
+
* A page the browser PRERENDERS (speculation rules, the address bar's guess
|
|
222
|
+
* at where the visitor is going) is hydrated with nobody looking, and may
|
|
223
|
+
* never be looked at: nothing starts until it is shown, and nothing at all
|
|
224
|
+
* if it never is.
|
|
225
|
+
*/
|
|
226
|
+
function startValAnalytics() {
|
|
227
|
+
{
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export { MAX_PATHS_PER_BEACON, MAX_ROUTE_LENGTH, MAX_UTM_LENGTH, buildBeacons, splitValPaths, startValAnalytics };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { a as _unsupportedIterableToArray } from './slicedToArray-3d4c6640.esm.js';
|
|
2
|
+
|
|
3
|
+
function _createForOfIteratorHelper(r, e) {
|
|
4
|
+
var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
|
|
5
|
+
if (!t) {
|
|
6
|
+
if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
|
|
7
|
+
t && (r = t);
|
|
8
|
+
var n = 0,
|
|
9
|
+
F = function () {};
|
|
10
|
+
return {
|
|
11
|
+
s: F,
|
|
12
|
+
n: function () {
|
|
13
|
+
return n >= r.length ? {
|
|
14
|
+
done: !0
|
|
15
|
+
} : {
|
|
16
|
+
done: !1,
|
|
17
|
+
value: r[n++]
|
|
18
|
+
};
|
|
19
|
+
},
|
|
20
|
+
e: function (r) {
|
|
21
|
+
throw r;
|
|
22
|
+
},
|
|
23
|
+
f: F
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
27
|
+
}
|
|
28
|
+
var o,
|
|
29
|
+
a = !0,
|
|
30
|
+
u = !1;
|
|
31
|
+
return {
|
|
32
|
+
s: function () {
|
|
33
|
+
t = t.call(r);
|
|
34
|
+
},
|
|
35
|
+
n: function () {
|
|
36
|
+
var r = t.next();
|
|
37
|
+
return a = r.done, r;
|
|
38
|
+
},
|
|
39
|
+
e: function (r) {
|
|
40
|
+
u = !0, o = r;
|
|
41
|
+
},
|
|
42
|
+
f: function () {
|
|
43
|
+
try {
|
|
44
|
+
a || null == t.return || t.return();
|
|
45
|
+
} finally {
|
|
46
|
+
if (u) throw o;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export { _createForOfIteratorHelper as _ };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var slicedToArray = require('./slicedToArray-64c83d56.cjs.prod.js');
|
|
4
|
+
|
|
5
|
+
function _createForOfIteratorHelper(r, e) {
|
|
6
|
+
var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
|
|
7
|
+
if (!t) {
|
|
8
|
+
if (Array.isArray(r) || (t = slicedToArray._unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
|
|
9
|
+
t && (r = t);
|
|
10
|
+
var n = 0,
|
|
11
|
+
F = function () {};
|
|
12
|
+
return {
|
|
13
|
+
s: F,
|
|
14
|
+
n: function () {
|
|
15
|
+
return n >= r.length ? {
|
|
16
|
+
done: !0
|
|
17
|
+
} : {
|
|
18
|
+
done: !1,
|
|
19
|
+
value: r[n++]
|
|
20
|
+
};
|
|
21
|
+
},
|
|
22
|
+
e: function (r) {
|
|
23
|
+
throw r;
|
|
24
|
+
},
|
|
25
|
+
f: F
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
29
|
+
}
|
|
30
|
+
var o,
|
|
31
|
+
a = !0,
|
|
32
|
+
u = !1;
|
|
33
|
+
return {
|
|
34
|
+
s: function () {
|
|
35
|
+
t = t.call(r);
|
|
36
|
+
},
|
|
37
|
+
n: function () {
|
|
38
|
+
var r = t.next();
|
|
39
|
+
return a = r.done, r;
|
|
40
|
+
},
|
|
41
|
+
e: function (r) {
|
|
42
|
+
u = !0, o = r;
|
|
43
|
+
},
|
|
44
|
+
f: function () {
|
|
45
|
+
try {
|
|
46
|
+
a || null == t.return || t.return();
|
|
47
|
+
} finally {
|
|
48
|
+
if (u) throw o;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
exports._createForOfIteratorHelper = _createForOfIteratorHelper;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { a as _unsupportedIterableToArray } from './slicedToArray-8b1a55e5.worker.esm.js';
|
|
2
|
+
|
|
3
|
+
function _createForOfIteratorHelper(r, e) {
|
|
4
|
+
var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
|
|
5
|
+
if (!t) {
|
|
6
|
+
if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
|
|
7
|
+
t && (r = t);
|
|
8
|
+
var n = 0,
|
|
9
|
+
F = function () {};
|
|
10
|
+
return {
|
|
11
|
+
s: F,
|
|
12
|
+
n: function () {
|
|
13
|
+
return n >= r.length ? {
|
|
14
|
+
done: !0
|
|
15
|
+
} : {
|
|
16
|
+
done: !1,
|
|
17
|
+
value: r[n++]
|
|
18
|
+
};
|
|
19
|
+
},
|
|
20
|
+
e: function (r) {
|
|
21
|
+
throw r;
|
|
22
|
+
},
|
|
23
|
+
f: F
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
27
|
+
}
|
|
28
|
+
var o,
|
|
29
|
+
a = !0,
|
|
30
|
+
u = !1;
|
|
31
|
+
return {
|
|
32
|
+
s: function () {
|
|
33
|
+
t = t.call(r);
|
|
34
|
+
},
|
|
35
|
+
n: function () {
|
|
36
|
+
var r = t.next();
|
|
37
|
+
return a = r.done, r;
|
|
38
|
+
},
|
|
39
|
+
e: function (r) {
|
|
40
|
+
u = !0, o = r;
|
|
41
|
+
},
|
|
42
|
+
f: function () {
|
|
43
|
+
try {
|
|
44
|
+
a || null == t.return || t.return();
|
|
45
|
+
} finally {
|
|
46
|
+
if (u) throw o;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export { _createForOfIteratorHelper as _ };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var slicedToArray = require('./slicedToArray-387314c6.cjs.dev.js');
|
|
4
|
+
|
|
5
|
+
function _createForOfIteratorHelper(r, e) {
|
|
6
|
+
var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
|
|
7
|
+
if (!t) {
|
|
8
|
+
if (Array.isArray(r) || (t = slicedToArray._unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
|
|
9
|
+
t && (r = t);
|
|
10
|
+
var n = 0,
|
|
11
|
+
F = function () {};
|
|
12
|
+
return {
|
|
13
|
+
s: F,
|
|
14
|
+
n: function () {
|
|
15
|
+
return n >= r.length ? {
|
|
16
|
+
done: !0
|
|
17
|
+
} : {
|
|
18
|
+
done: !1,
|
|
19
|
+
value: r[n++]
|
|
20
|
+
};
|
|
21
|
+
},
|
|
22
|
+
e: function (r) {
|
|
23
|
+
throw r;
|
|
24
|
+
},
|
|
25
|
+
f: F
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
29
|
+
}
|
|
30
|
+
var o,
|
|
31
|
+
a = !0,
|
|
32
|
+
u = !1;
|
|
33
|
+
return {
|
|
34
|
+
s: function () {
|
|
35
|
+
t = t.call(r);
|
|
36
|
+
},
|
|
37
|
+
n: function () {
|
|
38
|
+
var r = t.next();
|
|
39
|
+
return a = r.done, r;
|
|
40
|
+
},
|
|
41
|
+
e: function (r) {
|
|
42
|
+
u = !0, o = r;
|
|
43
|
+
},
|
|
44
|
+
f: function () {
|
|
45
|
+
try {
|
|
46
|
+
a || null == t.return || t.return();
|
|
47
|
+
} finally {
|
|
48
|
+
if (u) throw o;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
exports._createForOfIteratorHelper = _createForOfIteratorHelper;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { a as _unsupportedIterableToArray } from './slicedToArray-8f9b0d84.browser.esm.js';
|
|
2
|
+
|
|
3
|
+
function _createForOfIteratorHelper(r, e) {
|
|
4
|
+
var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
|
|
5
|
+
if (!t) {
|
|
6
|
+
if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
|
|
7
|
+
t && (r = t);
|
|
8
|
+
var n = 0,
|
|
9
|
+
F = function () {};
|
|
10
|
+
return {
|
|
11
|
+
s: F,
|
|
12
|
+
n: function () {
|
|
13
|
+
return n >= r.length ? {
|
|
14
|
+
done: !0
|
|
15
|
+
} : {
|
|
16
|
+
done: !1,
|
|
17
|
+
value: r[n++]
|
|
18
|
+
};
|
|
19
|
+
},
|
|
20
|
+
e: function (r) {
|
|
21
|
+
throw r;
|
|
22
|
+
},
|
|
23
|
+
f: F
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
27
|
+
}
|
|
28
|
+
var o,
|
|
29
|
+
a = !0,
|
|
30
|
+
u = !1;
|
|
31
|
+
return {
|
|
32
|
+
s: function () {
|
|
33
|
+
t = t.call(r);
|
|
34
|
+
},
|
|
35
|
+
n: function () {
|
|
36
|
+
var r = t.next();
|
|
37
|
+
return a = r.done, r;
|
|
38
|
+
},
|
|
39
|
+
e: function (r) {
|
|
40
|
+
u = !0, o = r;
|
|
41
|
+
},
|
|
42
|
+
f: function () {
|
|
43
|
+
try {
|
|
44
|
+
a || null == t.return || t.return();
|
|
45
|
+
} finally {
|
|
46
|
+
if (u) throw o;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export { _createForOfIteratorHelper as _ };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The analytics wire format, version 1: what the browser sends to
|
|
3
|
+
* `POST /api/val/analytics`. See `docs/plans/analytics.md`, "Wire format".
|
|
4
|
+
*
|
|
5
|
+
* Nothing in this directory may import `@valbuild/core`, `@valbuild/shared`
|
|
6
|
+
* or zod: this is code every visitor of a site downloads, and those three are
|
|
7
|
+
* most of the weight Val already puts on a page (`client-bundle-weight.md`).
|
|
8
|
+
* `imports.test.ts` keeps it so. The zod schema the server parses this with
|
|
9
|
+
* is `AnalyticsBeacon` in `@valbuild/shared/internal`, and `beacon.test.ts`
|
|
10
|
+
* checks the two agree.
|
|
11
|
+
*/
|
|
12
|
+
export type AnalyticsDevice = "phone" | "tablet" | "desktop";
|
|
13
|
+
export type AnalyticsUtm = {
|
|
14
|
+
source?: string;
|
|
15
|
+
medium?: string;
|
|
16
|
+
campaign?: string;
|
|
17
|
+
};
|
|
18
|
+
/** What only the first beacon of a page view carries. Its presence IS the page view. */
|
|
19
|
+
export type AnalyticsPageView = {
|
|
20
|
+
/** `document.referrer`'s host, only when it is another site. */
|
|
21
|
+
ref?: string;
|
|
22
|
+
utm?: AnalyticsUtm;
|
|
23
|
+
device: AnalyticsDevice;
|
|
24
|
+
};
|
|
25
|
+
/** Module file path → module paths (the part of a source path after `?p=`). */
|
|
26
|
+
export type AnalyticsPaths = Record<string, string[]>;
|
|
27
|
+
export type AnalyticsBeacon = {
|
|
28
|
+
v: 1;
|
|
29
|
+
/** `location.pathname`, never the query or the hash. */
|
|
30
|
+
route: string;
|
|
31
|
+
/** The content version the page was rendered from, when the page knows it. */
|
|
32
|
+
cv?: string;
|
|
33
|
+
view?: AnalyticsPageView;
|
|
34
|
+
rendered: AnalyticsPaths;
|
|
35
|
+
viewed: AnalyticsPaths;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* The receiver rejects a beacon above these (`AnalyticsBeacon` in
|
|
39
|
+
* `@valbuild/shared/internal` repeats them), so the sender never sends more:
|
|
40
|
+
* it cuts or drops what is longer, and splits what is larger.
|
|
41
|
+
*/
|
|
42
|
+
export declare const MAX_PATHS_PER_BEACON = 200;
|
|
43
|
+
export declare const MAX_ROUTE_LENGTH = 512;
|
|
44
|
+
export declare const MAX_UTM_LENGTH = 100;
|
|
45
|
+
/** A host name is at most 253 characters (RFC 1035). */
|
|
46
|
+
export declare const MAX_REF_LENGTH = 253;
|
|
47
|
+
export declare const MAX_CV_LENGTH = 128;
|
|
48
|
+
export declare const MAX_MODULE_FILE_PATH_LENGTH = 512;
|
|
49
|
+
export declare const MAX_MODULE_PATH_LENGTH = 1024;
|
|
50
|
+
/**
|
|
51
|
+
* A beacon's size in bytes of JSON, below the 16 KB Val's hosting accepts --
|
|
52
|
+
* 200 long router keys are about 18 KB. `sendBeacon` itself takes 64 KB.
|
|
53
|
+
*/
|
|
54
|
+
export declare const MAX_BEACON_BYTES = 12000;
|
|
55
|
+
/** Phone below 640 px of viewport width, tablet below 1024, desktop above. */
|
|
56
|
+
export declare function deviceOf(viewportWidth: number): AnalyticsDevice;
|
|
57
|
+
/**
|
|
58
|
+
* The referrer's host, when it is another site -- never its path or query,
|
|
59
|
+
* which can carry anything. A referrer from this site is navigation within it,
|
|
60
|
+
* not a source.
|
|
61
|
+
*/
|
|
62
|
+
export declare function referrerHostOf(referrer: string, ownHost: string): string | undefined;
|
|
63
|
+
/** `utm_source`, `utm_medium` and `utm_campaign`, and no other parameter. */
|
|
64
|
+
export declare function utmOf(search: string): AnalyticsUtm | undefined;
|
|
65
|
+
export declare function routeOf(pathname: string): string;
|
|
66
|
+
/**
|
|
67
|
+
* The beacons that carry `rendered` and `viewed`: at most
|
|
68
|
+
* `MAX_PATHS_PER_BEACON` paths and about `MAX_BEACON_BYTES` each. `view`, when
|
|
69
|
+
* given, goes in the first. Returns none when there is nothing to say.
|
|
70
|
+
*
|
|
71
|
+
* A path longer than the receiver takes is dropped rather than cut: half a
|
|
72
|
+
* path names some other content, or none.
|
|
73
|
+
*/
|
|
74
|
+
export declare function buildBeacons(args: {
|
|
75
|
+
route: string;
|
|
76
|
+
cv?: string;
|
|
77
|
+
view?: AnalyticsPageView;
|
|
78
|
+
rendered: readonly string[];
|
|
79
|
+
viewed: readonly string[];
|
|
80
|
+
}): AnalyticsBeacon[];
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { startValAnalytics, type ValAnalyticsTracker, type ValAnalyticsOptions, } from "./tracker.js";
|
|
2
|
+
export { buildBeacons, type AnalyticsBeacon, type AnalyticsDevice, type AnalyticsPageView, type AnalyticsPaths, type AnalyticsUtm, MAX_PATHS_PER_BEACON, MAX_ROUTE_LENGTH, MAX_UTM_LENGTH, } from "./beacon.js";
|
|
3
|
+
export { splitValPaths } from "./splitValPaths.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The source paths in a `data-val-path` attribute.
|
|
3
|
+
*
|
|
4
|
+
* One element can show several pieces of content, and `attrs()` and
|
|
5
|
+
* `autoTagJSX` join their paths with commas. Core's `splitJoinedSourcePaths`
|
|
6
|
+
* splits on every comma, which cuts a path whose record key holds one
|
|
7
|
+
* (`"/blog/a,b"`). This splits only on commas outside the JSON strings a
|
|
8
|
+
* module path is made of, so it agrees with core wherever core is right and
|
|
9
|
+
* keeps such a path whole. It is here rather than imported because nothing in
|
|
10
|
+
* this directory may import core -- see `beacon.ts`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function splitValPaths(attribute: string | null): string[];
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export type ValAnalyticsOptions = {
|
|
2
|
+
/** Where beacons go. Default `/api/val/analytics`, on the site's own origin. */
|
|
3
|
+
endpoint?: string;
|
|
4
|
+
/** The content version the page was rendered from, sent as `cv`. */
|
|
5
|
+
contentVersion?: string;
|
|
6
|
+
/** How long after a page view starts its first beacon goes. Default 3 s. */
|
|
7
|
+
firstSendAfterMs?: number;
|
|
8
|
+
/** How long an element must stay on screen to count as viewed. Default 1 s. */
|
|
9
|
+
viewedAfterMs?: number;
|
|
10
|
+
/** How many new paths make a beacon worth sending before the page is left. Default 50. */
|
|
11
|
+
sendWhenPending?: number;
|
|
12
|
+
/** The shortest time between two of those. Default 15 s. */
|
|
13
|
+
minSendIntervalMs?: number;
|
|
14
|
+
/**
|
|
15
|
+
* The pathname the page was rendered and hydrated at. When the visitor is
|
|
16
|
+
* somewhere else by the time this starts, they navigated in between, and
|
|
17
|
+
* that page is sent as a page view of its own. Without it, the URL the
|
|
18
|
+
* document was loaded at stands in -- which also differs after a redirect
|
|
19
|
+
* or a trailing slash the router normalised, so a caller that knows should
|
|
20
|
+
* say.
|
|
21
|
+
*/
|
|
22
|
+
landingPath?: string;
|
|
23
|
+
/**
|
|
24
|
+
* The route a pathname is a page of, as the app names it: `/blogs/$slug`
|
|
25
|
+
* for `/blogs/a-post`. What is sent, so a path that holds something about
|
|
26
|
+
* one visitor -- an order number, a token, an email address -- is never
|
|
27
|
+
* stored as if it were a page of the site. Without it the pathname is sent
|
|
28
|
+
* as it is, so a caller that knows its routes should say.
|
|
29
|
+
*
|
|
30
|
+
* A page view is still a change of PATHNAME: `/blogs/a` to `/blogs/b` is a
|
|
31
|
+
* new one, of the same route.
|
|
32
|
+
*/
|
|
33
|
+
routeFor?: (pathname: string) => string;
|
|
34
|
+
};
|
|
35
|
+
export type ValAnalyticsTracker = {
|
|
36
|
+
/** Sends what is waiting now. */
|
|
37
|
+
flush(): void;
|
|
38
|
+
/** Sends what is waiting, then stops counting and restores everything it patched. */
|
|
39
|
+
stop(): void;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Counts which content a visitor's page shows, and sends it.
|
|
43
|
+
*
|
|
44
|
+
* - **Rendered**: an element with a `data-val-path` is in the document.
|
|
45
|
+
* - **Viewed**: one is at least half visible -- or covers at least half the
|
|
46
|
+
* viewport, for an element taller than it -- for `viewedAfterMs` without a
|
|
47
|
+
* break, while the page is visible.
|
|
48
|
+
*
|
|
49
|
+
* Each path counts at most once of each per page view. A page view starts with
|
|
50
|
+
* the page and with every client-side navigation to another pathname; content
|
|
51
|
+
* still on screen after one (a header, a footer) counts again for the new one,
|
|
52
|
+
* because it was rendered on it.
|
|
53
|
+
*
|
|
54
|
+
* Returns null where it does nothing: on the server, and for an automated
|
|
55
|
+
* browser (`navigator.webdriver`). The caller decides the rest -- draft mode,
|
|
56
|
+
* the Studio's canvas and an editor browsing with Val enabled all count
|
|
57
|
+
* nothing, and the provider does not start it for them.
|
|
58
|
+
*
|
|
59
|
+
* A page the browser PRERENDERS (speculation rules, the address bar's guess
|
|
60
|
+
* at where the visitor is going) is hydrated with nobody looking, and may
|
|
61
|
+
* never be looked at: nothing starts until it is shown, and nothing at all
|
|
62
|
+
* if it never is.
|
|
63
|
+
*/
|
|
64
|
+
export declare function startValAnalytics(options?: ValAnalyticsOptions): ValAnalyticsTracker | null;
|