@birdie-so/snippet 1.0.1 → 1.1.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.
package/README.md CHANGED
@@ -43,15 +43,44 @@ initBirdie({
43
43
 
44
44
  // Optional hook once Birdie is ready
45
45
  onReady(birdie) {
46
+ // you can register for the following events
47
+ birdie.on("recorderOpen", (data) => {
48
+ console.log("Recorder tab is opened", data);
49
+ });
46
50
  birdie.on("start", (data) => {
47
51
  console.log("Recording started", data);
48
52
  birdie.metadata = { dynamicKey: "value" };
49
53
  });
50
-
54
+ birdie.on("pause", (data) => {
55
+ console.log("Recording paused", data);
56
+ });
57
+ birdie.on("resume", (data) => {
58
+ console.log("Recording resumed", data);
59
+ });
51
60
  birdie.on("stop", (data) => {
52
61
  console.log("Recording stopped", data);
53
62
  });
54
- },
63
+ birdie.on("restart", (data) => {
64
+ console.log("Recording restarted", data);
65
+ });
66
+ birdie.on("captureStarted", (data) => {
67
+ console.log("Capturing logs started", data);
68
+ });
69
+ birdie.on("captureStopped", (data) => {
70
+ console.log("Capturing logs stopped", data);
71
+ });
72
+ birdie.on("recordingSent", (data) => {
73
+ // data.link contains the link to the video
74
+ console.log("A new recording has been sent", data);
75
+ });
76
+ birdie.on("recorderClose", (data) => {
77
+ console.log("Recorder tab was closed", data);
78
+ });
79
+ birdie.on("error", (error) => {
80
+ console.log("Something went wrong", error);
81
+ });
82
+ }
83
+
55
84
  });
56
85
  ```
57
86
 
package/package.json CHANGED
@@ -1,14 +1,10 @@
1
1
  {
2
2
  "name": "@birdie-so/snippet",
3
- "version": "1.0.1",
3
+ "version": "1.1.1",
4
4
  "description": "Helper for integrating the Birdie screen recording snippet into modern JavaScript apps. Requires a Birdie account.",
5
+ "type": "module",
5
6
  "main": "src/index.js",
6
- "exports": {
7
- ".": {
8
- "require": "./src/index.js",
9
- "import": "./src/index.js"
10
- }
11
- },
7
+ "exports": { ".": "./src/index.js" },
12
8
  "types": "src/index.d.ts",
13
9
  "keywords": [
14
10
  "birdie",
package/src/index.d.ts CHANGED
@@ -17,11 +17,49 @@ export interface BirdieSettings {
17
17
  * Callback when Birdie is fully loaded and available as `window.birdie`.
18
18
  */
19
19
  onReady?: (birdie: BirdieAPI) => void;
20
+
21
+ /**
22
+ * If true (default), guarantees at most one active handler per event.
23
+ * Re-registering the same event replaces the previous handler (prevents double fires on remount/HMR).
24
+ */
25
+ singleHandlerPerEvent?: boolean;
20
26
  }
21
27
 
28
+ // export interface BirdieAPI {
29
+ // metadata: BirdieMetadata;
30
+ // on(event: 'start' | 'stop' | 'captureStarted' | 'captureStopped' | 'pause' | 'restart' | 'resume' | 'recorderClose' | 'recorderOpen' | 'recordingSent' | 'error', callback: (data: any) => void): void;
31
+ // }
32
+
22
33
  export interface BirdieAPI {
23
34
  metadata: BirdieMetadata;
24
- on(event: 'start' | 'stop', callback: (data: any) => void): void;
35
+
36
+ on(
37
+ event:
38
+ | 'start' | 'stop' | 'captureStarted' | 'captureStopped'
39
+ | 'pause' | 'restart' | 'resume'
40
+ | 'recorderClose' | 'recorderOpen'
41
+ | 'recordingSent' | 'error',
42
+ callback: (data: any) => void
43
+ ): void;
44
+
45
+ off(
46
+ event:
47
+ | 'start' | 'stop' | 'captureStarted' | 'captureStopped'
48
+ | 'pause' | 'restart' | 'resume'
49
+ | 'recorderClose' | 'recorderOpen'
50
+ | 'recordingSent' | 'error',
51
+ callback: (data: any) => void
52
+ ): void;
53
+
54
+ /** Auto-unsubscribes after the first event emission. */
55
+ onOnce(
56
+ event:
57
+ | 'start' | 'stop' | 'captureStarted' | 'captureStopped'
58
+ | 'pause' | 'restart' | 'resume'
59
+ | 'recorderClose' | 'recorderOpen'
60
+ | 'recordingSent' | 'error',
61
+ callback: (data: any) => void
62
+ ): void;
25
63
  }
26
64
 
27
65
  /**
package/src/index.js CHANGED
@@ -1,6 +1,9 @@
1
1
  let _readyCallbacks = [];
2
2
 
3
- export function initBirdie({ clientId, metadata, onReady, ...otherSettings }) {
3
+ export function initBirdie({ clientId, metadata, onReady, singleHandlerPerEvent = true, ...otherSettings }) {
4
+
5
+
6
+
4
7
  if (!clientId) {
5
8
  console.error('[Birdie] Missing required clientId in initBirdie()');
6
9
  return;
@@ -17,9 +20,13 @@ export function initBirdie({ clientId, metadata, onReady, ...otherSettings }) {
17
20
  window.birdieSettings.metadata = metadata;
18
21
  Object.assign(window.birdieSettings, otherSettings);
19
22
 
20
- // Assign onBirdieReady BEFORE appending the script
21
23
  window.birdieSettings.onBirdieReady = () => {
22
- _readyCallbacks.forEach(cb => cb(window.birdie));
24
+ try {
25
+ installBirdieGuards({ singleHandlerPerEvent });
26
+ } catch (e) {
27
+ console.error('[Birdie] guard install error', e);
28
+ }
29
+ _readyCallbacks.forEach(cb => { try { cb(window.birdie); } catch (e) { console.error('[Birdie] onReady error', e); } });
23
30
  _readyCallbacks = [];
24
31
  };
25
32
 
@@ -36,9 +43,17 @@ export function initBirdie({ clientId, metadata, onReady, ...otherSettings }) {
36
43
  script.id = 'birdie-snippet';
37
44
  document.body.appendChild(script);
38
45
  }
46
+ // if (!document.getElementById('birdie-snippet')) {
47
+ // const script = document.createElement('script');
48
+ // script.src = `https://birdie.eu.ngrok.io/snippet/index.local.min.js`;
49
+ // script.async = true;
50
+ // script.id = 'birdie-snippet';
51
+ // document.body.appendChild(script);
52
+ // }
39
53
  }
40
54
 
41
55
  function registerBirdieReadyCallback(callback) {
56
+ if (typeof window === 'undefined') return;
42
57
  if (window.birdie) {
43
58
  callback(window.birdie);
44
59
  } else {
@@ -47,6 +62,7 @@ function registerBirdieReadyCallback(callback) {
47
62
  }
48
63
 
49
64
  export function getBirdieInstance(onReady) {
65
+ if (typeof window === 'undefined') return null;
50
66
  if (window.birdie) {
51
67
  onReady?.(window.birdie);
52
68
  return window.birdie;
@@ -55,3 +71,45 @@ export function getBirdieInstance(onReady) {
55
71
  return null;
56
72
  }
57
73
  }
74
+
75
+ // ---- guards & helpers ----
76
+ function installBirdieGuards({ singleHandlerPerEvent }) {
77
+ const b = window.birdie;
78
+ if (!b || b.__pkgGuardsInstalled) return;
79
+
80
+ // Keep originals
81
+ const originalOn = b.on?.bind(b);
82
+ const originalOff = b.off?.bind(b);
83
+
84
+ // Registry of the single active handler per event (for dedupe)
85
+ const singletons = new Map();
86
+
87
+ // Add onOnce
88
+ b.onOnce = (event, cb) => {
89
+ const wrapper = (data) => {
90
+ try { cb(data); } finally { b.off?.(event, wrapper); }
91
+ };
92
+ b.on(event, wrapper);
93
+ };
94
+
95
+ if (singleHandlerPerEvent && originalOn && originalOff) {
96
+ b.on = (event, cb) => {
97
+ // If there was a previous handler for this event installed via this layer, remove it
98
+ const prev = singletons.get(event);
99
+ if (prev) {
100
+ try { originalOff(event, prev); } catch { }
101
+ }
102
+ singletons.set(event, cb);
103
+ return originalOn(event, cb);
104
+ };
105
+
106
+ b.off = (event, cb) => {
107
+ // Clean our registry if the same cb is removed
108
+ const prev = singletons.get(event);
109
+ if (prev === cb) singletons.delete(event);
110
+ return originalOff(event, cb);
111
+ };
112
+ }
113
+
114
+ b.__pkgGuardsInstalled = true;
115
+ }