@lib-acr/browser 0.0.0-stage → 0.0.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.
Files changed (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +113 -2
  3. package/dist/cjs/browser-acr.js +600 -0
  4. package/dist/cjs/browser-acr.js.map +1 -0
  5. package/dist/cjs/captured.js +19 -0
  6. package/dist/cjs/captured.js.map +1 -0
  7. package/dist/cjs/control/command-runner.js +289 -0
  8. package/dist/cjs/control/command-runner.js.map +1 -0
  9. package/dist/cjs/control/ui.js +277 -0
  10. package/dist/cjs/control/ui.js.map +1 -0
  11. package/dist/cjs/device.js +54 -0
  12. package/dist/cjs/device.js.map +1 -0
  13. package/dist/cjs/fetch-tracker.js +63 -0
  14. package/dist/cjs/fetch-tracker.js.map +1 -0
  15. package/dist/cjs/identity.js +120 -0
  16. package/dist/cjs/identity.js.map +1 -0
  17. package/dist/cjs/index.js +73 -0
  18. package/dist/cjs/index.js.map +1 -0
  19. package/dist/cjs/sdk-info.js +6 -0
  20. package/dist/cjs/sdk-info.js.map +1 -0
  21. package/dist/cjs/url.js +31 -0
  22. package/dist/cjs/url.js.map +1 -0
  23. package/dist/cjs/web-vitals.js +160 -0
  24. package/dist/cjs/web-vitals.js.map +1 -0
  25. package/dist/esm/browser-acr.js +595 -0
  26. package/dist/esm/browser-acr.js.map +1 -0
  27. package/dist/esm/captured.js +15 -0
  28. package/dist/esm/captured.js.map +1 -0
  29. package/dist/esm/control/command-runner.js +284 -0
  30. package/dist/esm/control/command-runner.js.map +1 -0
  31. package/dist/esm/control/ui.js +272 -0
  32. package/dist/esm/control/ui.js.map +1 -0
  33. package/dist/esm/device.js +50 -0
  34. package/dist/esm/device.js.map +1 -0
  35. package/dist/esm/fetch-tracker.js +60 -0
  36. package/dist/esm/fetch-tracker.js.map +1 -0
  37. package/dist/esm/identity.js +112 -0
  38. package/dist/esm/identity.js.map +1 -0
  39. package/dist/esm/index.js +13 -0
  40. package/dist/esm/index.js.map +1 -0
  41. package/dist/esm/package.json +3 -0
  42. package/dist/esm/sdk-info.js +3 -0
  43. package/dist/esm/sdk-info.js.map +1 -0
  44. package/dist/esm/url.js +27 -0
  45. package/dist/esm/url.js.map +1 -0
  46. package/dist/esm/web-vitals.js +156 -0
  47. package/dist/esm/web-vitals.js.map +1 -0
  48. package/dist/types/browser-acr.d.ts +142 -0
  49. package/dist/types/captured.d.ts +4 -0
  50. package/dist/types/control/command-runner.d.ts +57 -0
  51. package/dist/types/control/ui.d.ts +50 -0
  52. package/dist/types/device.d.ts +24 -0
  53. package/dist/types/fetch-tracker.d.ts +15 -0
  54. package/dist/types/identity.d.ts +48 -0
  55. package/dist/types/index.d.ts +17 -0
  56. package/dist/types/sdk-info.d.ts +4 -0
  57. package/dist/types/url.d.ts +10 -0
  58. package/dist/types/web-vitals.d.ts +50 -0
  59. package/package.json +40 -4
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Application Control Room
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,114 @@
1
- # Temporary Holding Version
1
+ # @lib-acr/browser
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Browser SDK: uncaught errors and unhandled rejections, page views (including client-side route changes), fetch timing, Core Web Vitals, sessions and anonymous visitor ids. It accepts publishable keys only and refuses a secret key.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @lib-acr/browser
9
+ ```
10
+
11
+ ## Quick start
12
+
13
+ ```ts
14
+ import { BrowserACR } from '@lib-acr/browser';
15
+
16
+ const acr = new BrowserACR({
17
+ apiKey: 'acr_live_…', // publishable key, restricted to your origins
18
+ endpoint: 'https://acr.example.com/v1',
19
+ appVersion: '2.3.0',
20
+ });
21
+ acr.start(); // installs listeners; call once
22
+ acr.identify('user_42'); // user id only; do not pass personal data
23
+ acr.trackEvent('product_added_to_cart', { productId: '123', price: 500 });
24
+
25
+ if (userSaysNo) acr.optOut(); // remembered on this browser; unsent telemetry is discarded
26
+ onLogout(() => acr.reset()); // new anonymous id and session, no user id
27
+ ```
28
+
29
+ ## Options
30
+
31
+ | Option | Default | Notes |
32
+ |---|---|---|
33
+ | `minLogLevel` | `warn` | Logs below this level are dropped in the page |
34
+ | `activePingMinutes` | `5` | Sends `acr.active` at this interval while the tab is visible, so ACR can count live visitors. `0` turns it off |
35
+ | `persistQueue` | `true` | Keeps unsent telemetry (at most 200 items / 50 kB) in `localStorage['acr.queue']` when the page is hidden and sends it on the next `start()` |
36
+ | `sessionTimeoutMinutes` | `30` | Any tracked event, log or error counts as activity; after the timeout a new session starts with its own `session_start` |
37
+ | `trackErrors`, `trackPageViews`, `trackFetch`, `trackWebVitals` | `true` | Automatic collection |
38
+ | `respectDoNotTrack` | `true` | |
39
+ | `ui` | `true` | Built-in maintenance screen, announcement banner and update prompt. `false`, or `{ maintenance?, announcement?, release? }` to turn parts off |
40
+ | `remoteControl` | `true` | Poll the control snapshot (kill switch, maintenance, flags, commands) |
41
+ | `configPollIntervalMs` | `60000` | Control snapshot poll interval, at least 15 000 |
42
+
43
+ `sampleRate` is applied per session, so a sampled-in visitor is recorded completely.
44
+
45
+ ## Page hide and offline
46
+
47
+ On `pagehide` and when the tab becomes hidden, every kind is sent at once with `fetch(…, { keepalive: true })`, each
48
+ request at most 60 kB. `navigator.sendBeacon` is not used because it cannot send the API key header. A bounded copy of
49
+ anything still undelivered is kept in `localStorage` and replayed on the next visit; items keep their ids, so the API
50
+ drops duplicates.
51
+
52
+ ## Entry point
53
+
54
+ This package re-exports the shared types and helpers of `@lib-acr/core` (for example `Attributes`, `LogLevel`,
55
+ `redactAttributes`), but not `AcrClient`, `HttpTransport` or `resolveConfig`: those accept a secret key and do not
56
+ belong in browser code.
57
+
58
+ ## Notes
59
+
60
+ Query strings and fragments are never recorded, and numeric or UUID path segments become `:id`. Do Not Track is respected by default. A failed `fetch` that the app does not catch is reported once (as a network error), not again as an unhandled rejection. INP is reported as the maximum interaction duration, which is an approximation of the official metric. Request and response bodies and headers are never read.
61
+
62
+ ## Remote control
63
+
64
+ After `start()` the SDK polls the control snapshot (see `@lib-acr/core`) and polls again whenever the tab becomes
65
+ visible or the device comes back online. It acts on the snapshot as follows:
66
+
67
+ - **Kill switch** (`sdk.enabled: false`) stops collection and flushing until it is lifted.
68
+ - **Maintenance:** shows a full-page maintenance screen (focus-trapped dialog with a "Check again" button). Users or
69
+ anonymous ids in `allowUserIds` are exempt.
70
+ - **Announcement:** a banner at the top while inside its `startsAt` – `endsAt` window. Dismissals are remembered per
71
+ id in `localStorage['acr.dismissed']`. Call `acr.dismissAnnouncement(id)` from your own UI.
72
+ - **Release:** when `appVersion` is below `latestVersion` or `minimumVersion`, a "new version available" prompt with a
73
+ Reload button appears. With `mode: "force"` and a version below `minimumVersion`, the page reloads once per tab and
74
+ minimum version (guarded in `sessionStorage['acr.forceReload']`), then falls back to the prompt.
75
+ - **Commands** run at most once per browser. Applied ids are kept in `localStorage['acr.cmds']` (the last 50). Commands
76
+ issued before `localStorage['acr.firstSeen']` are skipped, and so are expired ones. The id is recorded before the
77
+ SDK acts, then it sends `acr.command_applied` (`commandId`, `type`, `result`, `cleared`) and flushes before any reload.
78
+ - `clear_cache` clears the selected categories: Cache Storage, service workers, `localStorage` and `sessionStorage`
79
+ (every key except the SDK's own `acr.*` keys), IndexedDB (where `indexedDB.databases()` exists, otherwise the
80
+ result is `partial`) and cookies readable by script. HttpOnly cookies cannot be cleared by any script.
81
+ - `reload` with `mode: "immediate"` reloads the page; `mode: "prompt"` shows the reload prompt. A second
82
+ SDK-triggered reload within 30 s turns into a prompt, so reloads cannot loop.
83
+
84
+ The built-in UI is rendered inside the shadow root of one `<acr-ui>` element, so page styles do not affect it. It
85
+ follows `prefers-color-scheme` and inserts server text as text, never as HTML. To render your own UI:
86
+
87
+ ```ts
88
+ const acr = new BrowserACR({ apiKey, endpoint, appVersion: '2.3.0', ui: { announcement: false } }); // or ui: false
89
+ acr.onControlChange(({ maintenance, announcement, release, reloadRequested }) => { /* render */ });
90
+ ```
91
+
92
+ `remoteControl: false` turns all of this off; `configPollIntervalMs` changes the poll interval.
93
+
94
+ ## Feature flags
95
+
96
+ ```ts
97
+ if (acr.flag('new-checkout', false)) showNewCheckout();
98
+ ```
99
+
100
+ Flags are evaluated locally for the identified user, or for the anonymous id before `identify()`, so the same browser
101
+ keeps the same variant. They return the fallback until the first snapshot arrives.
102
+
103
+ ## Wire protocol
104
+
105
+ Every SDK sends the same protocol: `POST {endpoint}/ingest/{events|logs|errors|heartbeat}` with the `X-ACR-Api-Key`
106
+ header (and `X-ACR-Secret-Key` for server keys). The credential determines the app and environment. The body is
107
+ `{ schemaVersion: 1, sdk, items[1..500] }`.
108
+ Each item has a client `id`, which lets the server drop duplicates when a batch is retried.
109
+
110
+ Retries use exponential backoff with jitter for network errors, 429 and 5xx responses. Other 4xx responses are not retried.
111
+ Telemetry is buffered in a bounded in-memory queue. When it is full, the oldest items are dropped and counted in `stats()`.
112
+ SDK code never throws into the host application.
113
+
114
+ Metrics (`increment`, `gauge`, `histogram`) and traces are not yet available.