@posthog/browser-common 0.6.1 → 0.7.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.
package/README.md CHANGED
@@ -65,9 +65,10 @@ What an extension is given in `setup` — the adapter shared by extensions on th
65
65
 
66
66
  Identity, session, SDK metadata, capture permission, and the public project token are always-ready synchronous reads.
67
67
  `capture` and `sendRequest` are awaitable. For `sendRequest`, `sentAt` controls `sent_at` placement on POST requests; GET query mode
68
- uses the cache-busting `_` parameter instead, and GET body mode has no effect. `onRemoteConfig` immediately replays the
69
- latest known success or failure and then reports subsequent outcomes. Extensions that want a named log prefix can
70
- create a child with `client.logger.createLogger('[myExtension]')`.
68
+ uses the cache-busting `_` parameter instead, and GET body mode has no effect. `onRemoteConfig` replays the latest
69
+ available success or failure and then reports subsequent outcomes. Configuration timing is host-owned, and the
70
+ subscription remains active until disposed. Extensions that want a named log prefix can create a child with
71
+ `client.logger.createLogger('[myExtension]')`.
71
72
 
72
73
  Extensions that expose controls to other extensions should export a typed stable-name token:
73
74
 
@@ -123,7 +124,7 @@ Use `Publisher<T>` when an extension exposes an event stream. Keep the publisher
123
124
  private, expose only its listener, and dispose it with the extension:
124
125
 
125
126
  ```ts
126
- import { Publisher, type Listener } from '@posthog/browser-common'
127
+ import { Publisher, type Listener } from '@posthog/browser-common/pubsub'
127
128
 
128
129
  const changes = new Publisher<{ enabled: boolean }>()
129
130
  export const onChange: Listener<{ enabled: boolean }> = changes.listener
package/dist/client.d.ts CHANGED
@@ -65,7 +65,10 @@ export interface SendRequestInit {
65
65
  query?: Record<string, string>;
66
66
  /** Additional headers merged with the host SDK's configured request headers. */
67
67
  headers?: Record<string, string>;
68
- /** Browser transport to prefer. `sendBeacon` returns a best-effort response immediately. */
68
+ /**
69
+ * Browser transport to prefer. Fetch is the normal runtime transport. Use `sendBeacon` only for an eligible
70
+ * best-effort teardown POST. Its response confirms browser handoff, not delivery.
71
+ */
69
72
  transport?: RequestTransport;
70
73
  /** Abort the request if it does not complete within this many milliseconds. */
71
74
  timeoutMs?: number;
@@ -109,7 +112,7 @@ export interface Client {
109
112
  getExtension<T extends Extension = Extension>(name: string): T | undefined;
110
113
  /** Fires for every captured event through a deeply readonly view. */
111
114
  readonly onEvent: Listener<CapturedEventInfo>;
112
- /** Replays the latest remote-config outcome on subscription and fires for subsequent outcomes. */
115
+ /** Replays the latest available remote-config outcome and fires subsequent outcomes when the host makes them available. */
113
116
  readonly onRemoteConfig: Listener<DeepReadonly<RemoteConfigResult>>;
114
117
  /** Public project token used to authenticate endpoint-specific requests. */
115
118
  readonly projectToken: string;
package/dist/config.js CHANGED
@@ -26,7 +26,7 @@ __webpack_require__.r(__webpack_exports__);
26
26
  __webpack_require__.d(__webpack_exports__, {
27
27
  default: ()=>__WEBPACK_DEFAULT_EXPORT__
28
28
  });
29
- const packageVersion = "0.6.1";
29
+ const packageVersion = "0.7.0";
30
30
  const Config = {
31
31
  DEBUG: false,
32
32
  LIB_VERSION: packageVersion,
package/dist/config.mjs CHANGED
@@ -1,4 +1,4 @@
1
- const packageVersion = "0.6.1";
1
+ const packageVersion = "0.7.0";
2
2
  const Config = {
3
3
  DEBUG: false,
4
4
  LIB_VERSION: packageVersion,
package/dist/pubsub.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type Disposable } from './disposable';
1
+ import type { Disposable } from './disposable';
2
2
  /**
3
3
  * Call it with a handler to start listening; dispose the returned
4
4
  * {@link Disposable} to stop. There is one `Listener` per event type, so every
@@ -17,6 +17,9 @@ export type Listener<T> = (handler: (payload: T) => void) => Disposable;
17
17
  export declare class Publisher<T> implements Disposable {
18
18
  /** Subscriptions currently registered with this publisher. */
19
19
  private _subscriptions;
20
+ private _disposed;
21
+ private readonly _onError;
22
+ constructor(onError?: (error: unknown) => void);
20
23
  /**
21
24
  * Register a handler for future payloads. The returned disposable
22
25
  * subscription unregisters this handler.
package/dist/pubsub.js CHANGED
@@ -26,35 +26,48 @@ __webpack_require__.r(__webpack_exports__);
26
26
  __webpack_require__.d(__webpack_exports__, {
27
27
  Publisher: ()=>Publisher
28
28
  });
29
- const external_disposable_js_namespaceObject = require("./disposable.js");
30
29
  class Publisher {
30
+ constructor(onError){
31
+ this._subscriptions = [];
32
+ this._disposed = false;
33
+ this.listener = (handler)=>{
34
+ if (this._disposed) return {
35
+ dispose () {}
36
+ };
37
+ const subscription = [
38
+ handler,
39
+ true
40
+ ];
41
+ this._subscriptions.push(subscription);
42
+ let active = true;
43
+ return {
44
+ dispose: ()=>{
45
+ if (!active) return;
46
+ active = false;
47
+ subscription[1] = false;
48
+ const index = this._subscriptions.indexOf(subscription);
49
+ if (-1 !== index) this._subscriptions.splice(index, 1);
50
+ }
51
+ };
52
+ };
53
+ this._onError = onError;
54
+ }
31
55
  publish(payload) {
32
56
  const subscriptions = this._subscriptions.slice();
33
- subscriptions.forEach((subscription)=>{
34
- if (subscription.isActive) subscription.handler(payload);
35
- });
57
+ for (const subscription of subscriptions)if (subscription[1]) try {
58
+ subscription[0](payload);
59
+ } catch (error) {
60
+ if (!this._onError) throw error;
61
+ this._onError(error);
62
+ }
36
63
  }
37
64
  dispose() {
65
+ this._disposed = true;
38
66
  this._subscriptions.forEach((subscription)=>{
39
- subscription.isActive = false;
67
+ subscription[1] = false;
40
68
  });
41
69
  this._subscriptions = [];
42
70
  }
43
- constructor(){
44
- this._subscriptions = [];
45
- this.listener = (handler)=>{
46
- const subscription = {
47
- handler,
48
- isActive: true
49
- };
50
- this._subscriptions.push(subscription);
51
- return (0, external_disposable_js_namespaceObject.createDisposable)(()=>{
52
- subscription.isActive = false;
53
- const index = this._subscriptions.indexOf(subscription);
54
- if (-1 !== index) this._subscriptions.splice(index, 1);
55
- });
56
- };
57
- }
58
71
  }
59
72
  exports.Publisher = __webpack_exports__.Publisher;
60
73
  for(var __webpack_i__ in __webpack_exports__)if (-1 === [
package/dist/pubsub.mjs CHANGED
@@ -1,31 +1,44 @@
1
- import { createDisposable } from "./disposable.mjs";
2
1
  class Publisher {
2
+ constructor(onError){
3
+ this._subscriptions = [];
4
+ this._disposed = false;
5
+ this.listener = (handler)=>{
6
+ if (this._disposed) return {
7
+ dispose () {}
8
+ };
9
+ const subscription = [
10
+ handler,
11
+ true
12
+ ];
13
+ this._subscriptions.push(subscription);
14
+ let active = true;
15
+ return {
16
+ dispose: ()=>{
17
+ if (!active) return;
18
+ active = false;
19
+ subscription[1] = false;
20
+ const index = this._subscriptions.indexOf(subscription);
21
+ if (-1 !== index) this._subscriptions.splice(index, 1);
22
+ }
23
+ };
24
+ };
25
+ this._onError = onError;
26
+ }
3
27
  publish(payload) {
4
28
  const subscriptions = this._subscriptions.slice();
5
- subscriptions.forEach((subscription)=>{
6
- if (subscription.isActive) subscription.handler(payload);
7
- });
29
+ for (const subscription of subscriptions)if (subscription[1]) try {
30
+ subscription[0](payload);
31
+ } catch (error) {
32
+ if (!this._onError) throw error;
33
+ this._onError(error);
34
+ }
8
35
  }
9
36
  dispose() {
37
+ this._disposed = true;
10
38
  this._subscriptions.forEach((subscription)=>{
11
- subscription.isActive = false;
39
+ subscription[1] = false;
12
40
  });
13
41
  this._subscriptions = [];
14
42
  }
15
- constructor(){
16
- this._subscriptions = [];
17
- this.listener = (handler)=>{
18
- const subscription = {
19
- handler,
20
- isActive: true
21
- };
22
- this._subscriptions.push(subscription);
23
- return createDisposable(()=>{
24
- subscription.isActive = false;
25
- const index = this._subscriptions.indexOf(subscription);
26
- if (-1 !== index) this._subscriptions.splice(index, 1);
27
- });
28
- };
29
- }
30
43
  }
31
44
  export { Publisher };
@@ -427,6 +427,9 @@ function getElementsChainString(elements) {
427
427
  function escapeQuotes(input) {
428
428
  return input.replace(/"|\\"/g, '\\"');
429
429
  }
430
+ function lexicalCompare(a, b) {
431
+ return a < b ? -1 : a > b ? 1 : 0;
432
+ }
430
433
  function elementsToString(elements) {
431
434
  const ret = elements.map((element)=>{
432
435
  let el_string = '';
@@ -450,7 +453,7 @@ function elementsToString(elements) {
450
453
  ...element.attributes
451
454
  };
452
455
  const sortedAttributes = {};
453
- (0, external_general_utils_js_namespaceObject.entries)(attributes).sort(([a], [b])=>a.localeCompare(b)).forEach(([key, value])=>sortedAttributes[escapeQuotes(key.toString())] = escapeQuotes(value.toString()));
456
+ (0, external_general_utils_js_namespaceObject.entries)(attributes).sort(([a], [b])=>lexicalCompare(a, b)).forEach(([key, value])=>sortedAttributes[escapeQuotes(key.toString())] = escapeQuotes(value.toString()));
454
457
  el_string += ':';
455
458
  el_string += (0, external_general_utils_js_namespaceObject.entries)(sortedAttributes).map(([key, value])=>`${key}="${value}"`).join('');
456
459
  return el_string;
@@ -379,6 +379,9 @@ function getElementsChainString(elements) {
379
379
  function escapeQuotes(input) {
380
380
  return input.replace(/"|\\"/g, '\\"');
381
381
  }
382
+ function lexicalCompare(a, b) {
383
+ return a < b ? -1 : a > b ? 1 : 0;
384
+ }
382
385
  function elementsToString(elements) {
383
386
  const ret = elements.map((element)=>{
384
387
  let el_string = '';
@@ -402,7 +405,7 @@ function elementsToString(elements) {
402
405
  ...element.attributes
403
406
  };
404
407
  const sortedAttributes = {};
405
- entries(attributes).sort(([a], [b])=>a.localeCompare(b)).forEach(([key, value])=>sortedAttributes[escapeQuotes(key.toString())] = escapeQuotes(value.toString()));
408
+ entries(attributes).sort(([a], [b])=>lexicalCompare(a, b)).forEach(([key, value])=>sortedAttributes[escapeQuotes(key.toString())] = escapeQuotes(value.toString()));
406
409
  el_string += ':';
407
410
  el_string += entries(sortedAttributes).map(([key, value])=>`${key}="${value}"`).join('');
408
411
  return el_string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@posthog/browser-common",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "Internal shared browser utilities and extension primitives for PostHog Browser SDKs",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -32,6 +32,9 @@
32
32
  "extension-runtime": [
33
33
  "dist/extension-runtime.d.ts"
34
34
  ],
35
+ "pubsub": [
36
+ "dist/pubsub.d.ts"
37
+ ],
35
38
  "utils/*": [
36
39
  "dist/utils/*.d.ts"
37
40
  ]
@@ -58,6 +61,11 @@
58
61
  "require": "./dist/extension-runtime.js",
59
62
  "import": "./dist/extension-runtime.mjs"
60
63
  },
64
+ "./pubsub": {
65
+ "types": "./dist/pubsub.d.ts",
66
+ "require": "./dist/pubsub.js",
67
+ "import": "./dist/pubsub.mjs"
68
+ },
61
69
  "./utils/*": {
62
70
  "types": "./dist/utils/*.d.ts",
63
71
  "require": "./dist/utils/*.js",
@@ -65,8 +73,8 @@
65
73
  }
66
74
  },
67
75
  "dependencies": {
68
- "@posthog/types": "^1.407.0",
69
- "@posthog/core": "^1.49.1"
76
+ "@posthog/core": "^1.49.2",
77
+ "@posthog/types": "^1.407.1"
70
78
  },
71
79
  "devDependencies": {
72
80
  "@rslib/core": "0.10.6",