@steve31415/baselib 3.24.0 → 3.25.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.
@@ -10,6 +10,19 @@ export interface BrowserLoggerOptions {
10
10
  /** Also mirror events to the devtools console (default false). */
11
11
  console?: boolean;
12
12
  }
13
+ /** One random id per page load, stamped on every browser event as
14
+ * `page_id`. Exported so an app can send the same id to its server (e.g. a
15
+ * socket's client id) and join the two sides in one query. */
16
+ export declare const pageId: string;
17
+ /**
18
+ * A coarse `<os>-<browser>` label from a user-agent string — enough to tell
19
+ * Steve's devices apart in a query, deliberately nothing finer (no versions,
20
+ * no model). os: android | ios | mac | windows | chromeos | linux | other;
21
+ * browser: edge | opera | firefox | chrome | safari | other. An iPad asking for
22
+ * the desktop site reports itself as a Mac; pass `touchPoints`
23
+ * (`navigator.maxTouchPoints`) to tell it apart.
24
+ */
25
+ export declare function deviceLabel(userAgent: string, touchPoints?: number): string;
13
26
  export declare function createBrowserLogger(opts?: BrowserLoggerOptions): Logger;
14
27
  /**
15
28
  * Make the shared `logger` forward to `instance`. Call once at boot, right
@@ -10,8 +10,61 @@
10
10
  //
11
11
  // The token is ingest-only and dataset-scoped by design — visible to any
12
12
  // signed-in user, able to do nothing but add log events.
13
+ //
14
+ // Every event also carries two top-level fields saying where it came from,
15
+ // because browser events have no request to join on (2026-10-03, radar: telling
16
+ // a phone put down from a sleeping Mac from a server fault took the
17
+ // load-balancer log): `page_id`, one random id per page load, and `device`, a
18
+ // coarse `<os>-<browser>` label such as `mac-chrome` or `android-chrome`.
13
19
  import { LogShipper, makeEvents } from './log-core.js';
14
20
  export { serializeError } from './log-core.js';
21
+ /** One random id per page load, stamped on every browser event as
22
+ * `page_id`. Exported so an app can send the same id to its server (e.g. a
23
+ * socket's client id) and join the two sides in one query. */
24
+ export const pageId = newPageId();
25
+ function newPageId() {
26
+ if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function')
27
+ return crypto.randomUUID();
28
+ return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`;
29
+ }
30
+ /**
31
+ * A coarse `<os>-<browser>` label from a user-agent string — enough to tell
32
+ * Steve's devices apart in a query, deliberately nothing finer (no versions,
33
+ * no model). os: android | ios | mac | windows | chromeos | linux | other;
34
+ * browser: edge | opera | firefox | chrome | safari | other. An iPad asking for
35
+ * the desktop site reports itself as a Mac; pass `touchPoints`
36
+ * (`navigator.maxTouchPoints`) to tell it apart.
37
+ */
38
+ export function deviceLabel(userAgent, touchPoints = 0) {
39
+ const ua = userAgent;
40
+ const os = /Android/.test(ua)
41
+ ? 'android'
42
+ : /iPhone|iPad|iPod/.test(ua)
43
+ ? 'ios'
44
+ : /Macintosh|Mac OS X/.test(ua)
45
+ ? touchPoints > 1
46
+ ? 'ios'
47
+ : 'mac'
48
+ : /Windows/.test(ua)
49
+ ? 'windows'
50
+ : /CrOS/.test(ua)
51
+ ? 'chromeos'
52
+ : /Linux/.test(ua)
53
+ ? 'linux'
54
+ : 'other';
55
+ const browser = /Edg(e|A|iOS)?\//.test(ua)
56
+ ? 'edge'
57
+ : /OPR\/|OPiOS\//.test(ua)
58
+ ? 'opera'
59
+ : /Firefox\/|FxiOS\//.test(ua)
60
+ ? 'firefox'
61
+ : /Chrome\/|CriOS\//.test(ua)
62
+ ? 'chrome'
63
+ : /Safari\//.test(ua)
64
+ ? 'safari'
65
+ : 'other';
66
+ return `${os}-${browser}`;
67
+ }
15
68
  function metaContent(name) {
16
69
  return document.querySelector(`meta[name="${name}"]`)?.content || undefined;
17
70
  }
@@ -68,7 +121,12 @@ export function createBrowserLogger(opts = {}) {
68
121
  flush: () => shipper?.flush() ?? Promise.resolve(),
69
122
  };
70
123
  }
71
- const logger = build({ ...(buildId ? { build_id: buildId } : {}), ...opts.context });
124
+ const logger = build({
125
+ ...(buildId ? { build_id: buildId } : {}),
126
+ page_id: pageId,
127
+ device: deviceLabel(navigator.userAgent, navigator.maxTouchPoints ?? 0),
128
+ ...opts.context,
129
+ });
72
130
  // Ship what's pending whenever the page may be going away.
73
131
  const flushNow = () => void logger.flush();
74
132
  addEventListener('pagehide', flushNow);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steve31415/baselib",
3
- "version": "3.24.0",
3
+ "version": "3.25.0",
4
4
  "description": "Plasticine new-world shared platform library: logging, auth, service-to-service auth, db, HTTP, sync, app updates",
5
5
  "type": "module",
6
6
  "license": "MIT",