@yuanze_dev/tracker 0.3.1 → 0.4.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.
@@ -1,3 +1,4 @@
1
+ import { redactUrl } from "./redact.js";
1
2
  const DEFAULT_ALLOW = 'a,button,[role="button"],[role="link"],[role="tab"],input[type="submit"],input[type="button"],summary';
2
3
  const DEFAULT_DENY = '[data-no-track],input[type="password"],[type="password"],.yz-no-track';
3
4
  const SENSITIVE_TEXT = /(\d[\d\s-]{9,}\d)|([\w.+-]+@[\w-]+\.[\w.]+)|(\d{15,19})/g;
@@ -38,9 +39,9 @@ export function setupAutocapture(tracker, options = {}) {
38
39
  return;
39
40
  const { captureClicks = true, allow = DEFAULT_ALLOW, deny = DEFAULT_DENY, sampleRate = 1, maxTextLength = 64, } = options;
40
41
  const sendPageview = () => tracker.track("$pageview", {
41
- url: location.pathname + location.search,
42
+ url: redactUrl(location.pathname + location.search),
42
43
  title: document.title,
43
- referrer: document.referrer,
44
+ referrer: redactUrl(document.referrer),
44
45
  });
45
46
  sendPageview();
46
47
  const patch = (key) => {
@@ -90,7 +91,7 @@ export function setupAutocapture(tracker, options = {}) {
90
91
  props.text = text;
91
92
  const href = el.getAttribute("href");
92
93
  if (href && !href.startsWith("javascript:"))
93
- props.href = href;
94
+ props.href = redactUrl(href);
94
95
  tracker.trackUnsafe("$autocapture", props);
95
96
  }, true);
96
97
  }
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@ export type { TrackerOptions, Sender } from "./tracker.js";
6
6
  export { setupAutocapture, sanitizeText, elementSelector } from "./autocapture.js";
7
7
  export type { AutocaptureOptions } from "./autocapture.js";
8
8
  export { collectEnvContext } from "./context.js";
9
+ export { redactUrl, CREDENTIAL_PARAMS } from "./redact.js";
9
10
  export type { EnvContext } from "./context.js";
10
11
  export { SYSTEM_EVENTS, isSystemEvent } from "./events.js";
11
12
  export type { EventName, EventProps, SystemEvents, ProjectEvents } from "./events.js";
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ import { collectEnvContext } from "./context.js";
4
4
  export { Tracker, defaultFetchSender } from "./tracker.js";
5
5
  export { setupAutocapture, sanitizeText, elementSelector } from "./autocapture.js";
6
6
  export { collectEnvContext } from "./context.js";
7
+ export { redactUrl, CREDENTIAL_PARAMS } from "./redact.js";
7
8
  export { SYSTEM_EVENTS, isSystemEvent } from "./events.js";
8
9
  let instance = null;
9
10
  export function init(opts) {
@@ -0,0 +1,2 @@
1
+ export declare const CREDENTIAL_PARAMS: readonly ["token", "access_token", "id_token", "refresh_token", "code"];
2
+ export declare function redactUrl(input: string, params?: readonly string[]): string;
package/dist/redact.js ADDED
@@ -0,0 +1,51 @@
1
+ export const CREDENTIAL_PARAMS = [
2
+ "token",
3
+ "access_token",
4
+ "id_token",
5
+ "refresh_token",
6
+ "code",
7
+ ];
8
+ const isCredential = (key, params) => params.includes(key.toLowerCase());
9
+ function redactQuery(query, params) {
10
+ if (!query)
11
+ return query;
12
+ let touched = false;
13
+ const kept = [];
14
+ for (const pair of query.split("&")) {
15
+ if (!pair)
16
+ continue;
17
+ const key = pair.split("=")[0];
18
+ let name = key;
19
+ try {
20
+ name = decodeURIComponent(key);
21
+ }
22
+ catch {
23
+ }
24
+ if (isCredential(name, params)) {
25
+ touched = true;
26
+ continue;
27
+ }
28
+ kept.push(pair);
29
+ }
30
+ return touched ? kept.join("&") : query;
31
+ }
32
+ export function redactUrl(input, params = CREDENTIAL_PARAMS) {
33
+ if (!input)
34
+ return input;
35
+ const cut = (s, sep) => {
36
+ const i = s.indexOf(sep);
37
+ return i === -1 ? [s, ""] : [s.slice(0, i), s.slice(i + 1)];
38
+ };
39
+ const [beforeHash, hash] = cut(input, "#");
40
+ const [base, query] = cut(beforeHash, "?");
41
+ if (/^[a-z][a-z0-9+.-]*:/i.test(base) && !/^https?:/i.test(base))
42
+ return input;
43
+ const nextQuery = redactQuery(query, params);
44
+ const nextHash = hash.includes("=") ? redactQuery(hash, params) : hash;
45
+ let out = base;
46
+ if (query)
47
+ out += nextQuery ? `?${nextQuery}` : "";
48
+ if (hash)
49
+ out += nextHash ? `#${nextHash}` : "";
50
+ return out;
51
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuanze_dev/tracker",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "原则数据埋点 SDK",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",