@hanzo/event 0.3.27 → 0.3.28

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/hz.js CHANGED
@@ -55,7 +55,7 @@
55
55
  }
56
56
 
57
57
  var LIB = 'hz.js'
58
- var VERSION = '0.3.27'
58
+ var VERSION = '0.3.28'
59
59
  var host = (s.getAttribute('data-host') || 'https://api.hanzo.ai').replace(/\/+$/, '')
60
60
  var product = s.getAttribute('data-product') || location.hostname
61
61
  var capture = s.getAttribute('data-capture') !== '0'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanzo/event",
3
- "version": "0.3.27",
3
+ "version": "0.3.28",
4
4
  "description": "Hanzo Event — the ONE telemetry client. Emits pageview/event/identify/group to the Hanzo Cloud event stream (POST /v1/event), AND reports errors to Sentry as real Sentry envelopes — the error plane needs a DSN, without one nothing reaches Sentry. First-touch attribution, beacon-on-unload, auto error capture, client-side secret/PII scrubbing, a shared event + goal vocabulary. Subsumes @sentry.",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/",
package/src/core.ts CHANGED
@@ -699,7 +699,14 @@ function registry(): Map<string, Analytics> {
699
699
  * This is the ONE way to get a client: `new Analytics` bypasses the registry
700
700
  * and is for tests and for a deliberately separate instance. */
701
701
  export function createAnalytics(config: AnalyticsConfig): Analytics {
702
- if (!isBrowser()) return new Analytics(config)
702
+ // A disabled client emits nothing, so it can double nothing and does not take
703
+ // the stream. Callers reach their answer at different moments — a provider
704
+ // whose ownership resolves in an effect renders once saying `false` before it
705
+ // has decided anything — and the client built in that moment must not become
706
+ // the one the page keeps. Registering it would silence the page, and adopting
707
+ // `enabled` from a later caller would let one surface overrule another's
708
+ // reading of consent. Neither: it is simply not the stream's client.
709
+ if (!isBrowser() || config.enabled === false) return new Analytics(config)
703
710
  const key = (config.host ?? DEFAULT_HOST) + '\0' + config.product
704
711
  const clients = registry()
705
712
  const existing = clients.get(key)
@@ -95,6 +95,32 @@ describe('one stream, one client', () => {
95
95
  expect(tx.sent[0].ingestKey).toBe(KEY)
96
96
  })
97
97
 
98
+ // A provider whose ownership resolves in an effect renders once saying
99
+ // `enabled: false` and then again saying true. Measured on hanzo.ai: the
100
+ // library's first render built a disabled client, and a registry that kept it
101
+ // handed that one to the app too — the page went silent, which is worse than
102
+ // the double it replaced.
103
+ it('does not let a disabled client take the stream', () => {
104
+ const off = createAnalytics({ product: 'site', host: HOST, enabled: false })
105
+ const on = createAnalytics({ product: 'site', host: HOST, transport: tx, flushIntervalMs: 999999 })
106
+ expect(on).not.toBe(off)
107
+ on.pageview('/pricing')
108
+ on.flush()
109
+ expect(tx.pageviews).toHaveLength(1)
110
+ expect(createAnalytics({ product: 'site', host: HOST, getToken: () => KEY })).toBe(on)
111
+ })
112
+
113
+ it('gives every disabled caller its own inert client', () => {
114
+ const a = createAnalytics({ product: 'site', host: HOST, enabled: false, transport: tx })
115
+ const b = createAnalytics({ product: 'site', host: HOST, enabled: false, transport: tx })
116
+ expect(a).not.toBe(b)
117
+ a.pageview('/pricing')
118
+ b.pageview('/pricing')
119
+ a.flush()
120
+ b.flush()
121
+ expect(tx.sent).toHaveLength(0)
122
+ })
123
+
98
124
  it('keeps separate streams separate', () => {
99
125
  expect(createAnalytics({ product: 'chat', host: HOST })).not.toBe(
100
126
  createAnalytics({ product: 'site', host: HOST }),
package/src/version.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  // The library version, stamped on every event (`libraryVersion`) and on the
2
2
  // Sentry `sdk` block. It lives alone so `sentry.ts` can read it without importing
3
3
  // `core.ts` — core imports sentry, so the reverse would be an import cycle.
4
- export const VERSION = '0.3.27'
4
+ export const VERSION = '0.3.28'