@jam.dev/recording-links 0.1.1 → 0.1.3

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
@@ -56,6 +56,7 @@ jam.initialize(); // Automatically loads recorder and opens recording "abc123"
56
56
  jam.initialize({
57
57
  teamId: "team-123,team-456", // Manually provide team ID(s); default: reads `<meta name="jam:team">` from the page
58
58
  openImmediately: false, // Don't auto-open recorder from URL params
59
+ // OR: "recording-123" to auto-open a recording by ID
59
60
  parseJamData: (href) => {
60
61
  // Custom logic to extract recording data from URL
61
62
  const url = new URL(href);
@@ -93,7 +94,7 @@ Initializes the SDK with optional configuration.
93
94
 
94
95
  **Parameters:**
95
96
  - `options.teamId?: string` - Team ID for recording validation
96
- - `options.openImmediately?: boolean` - Whether to auto-open from URL (default: `true`)
97
+ - `options.openImmediately?: boolean | string` - Whether to auto-open from URL (default: `true`), or a recording ID string to open immediately
97
98
  - `options.parseJamData?: (input: string) => SerializableJamData | null` - Custom URL parser
98
99
  - `options.applyJamData?: (data: SerializableJamData) => string` - Custom URL applier
99
100
  - `options.recorderRefCounter?: RefCounter` - Custom reference counter (advanced)
@@ -106,8 +107,7 @@ Initializes the SDK with optional configuration.
106
107
  Loads the Jam recorder module and returns a promise that resolves to the recorder interface.
107
108
 
108
109
  **Parameters:**
109
- - `options.recordingId?: string` - Recording ID to open immediately
110
- - Plus all options from `InitializeOptions`
110
+ - `Omit<InitializeOptions, "recorderRefCounter">`
111
111
 
112
112
  **Returns:**
113
113
  - `Promise<RecorderSingleton>` - The Recorder singleton
@@ -115,6 +115,13 @@ Loads the Jam recorder module and returns a promise that resolves to the recorde
115
115
  **Throws:**
116
116
  - Error if SDK is not initialized
117
117
 
118
+ ### `isInitialized()`
119
+
120
+ Returns whether the SDK has been initialized.
121
+
122
+ **Returns:**
123
+ - `boolean` - True if the SDK has been initialized, false otherwise
124
+
118
125
  ### `addEventListener(type, listener, options?)`
119
126
 
120
127
  Add an event listener for SDK events.
@@ -159,7 +166,7 @@ type SerializableJamData = {
159
166
  ```typescript
160
167
  type InitializeOptions = {
161
168
  teamId?: string;
162
- openImmediately?: boolean;
169
+ openImmediately?: boolean | string | undefined | null;
163
170
  parseJamData?(input: string): SerializableJamData | null;
164
171
  applyJamData?(data: SerializableJamData): string;
165
172
  recorderRefCounter?: RefCounter;
package/lib/sdk.d.ts CHANGED
@@ -48,9 +48,11 @@ type InitializeOptions = {
48
48
  teamId?: string;
49
49
  /**
50
50
  * Whether to open the JamRecorder immediately on initialization.
51
+ * May be provided a recording ID as a string, in which case we will open it.
52
+ * If the value resolves to `undefined` or `null`, we will default to `true`.
51
53
  * Default: `true`
52
54
  */
53
- openImmediately?: boolean;
55
+ openImmediately?: boolean | string | undefined | null;
54
56
  /**
55
57
  * Extract a `recordingId` and `jamTitle` from the provided string.
56
58
  * Defaults to reading the `jam-recording` and `jam-title` QSPs off the URL.
@@ -86,6 +88,8 @@ export declare const addEventListener: <K extends "loaded">(type: K, listener: (
86
88
  * @param options - Optional event listener configuration
87
89
  */
88
90
  export declare const removeEventListener: <K extends "loaded">(type: K, listener: (event: CustomEvent<Events[K]>) => void, options?: boolean | AddEventListenerOptions) => void;
91
+ /** Whether the SDK has been initialized. */
92
+ export declare const isInitialized: () => false;
89
93
  /**
90
94
  * The loaded Recorder singleton instance. Will be null until loadRecorder() is called successfully.
91
95
  */
@@ -101,6 +105,7 @@ export declare let Recorder: RecorderSingleton | null;
101
105
  * @param options.recorderRefCounter - Custom reference counter for managing recorder instances across tabs
102
106
  * @param options.teamId - Team ID for validating recording IDs
103
107
  * @param options.openImmediately - Whether to automatically open recorder from URL parameters (default: true)
108
+ * Can be set to a specific recording ID as a string to open that recording.
104
109
  * @param options.parseJamData - Custom function to extract recording data from URLs
105
110
  * @param options.applyJamData - Custom function to apply recording data to URLs
106
111
  *
@@ -114,7 +119,7 @@ export declare let Recorder: RecorderSingleton | null;
114
119
  * // Custom configuration
115
120
  * jam.initialize({
116
121
  * teamId: "team-123",
117
- * openImmediately: false
122
+ * openImmediately: false // or "abc-123" to open a specific recording
118
123
  * });
119
124
  * ```
120
125
  */
@@ -127,9 +132,9 @@ export declare function initialize({ recorderRefCounter, ...config }?: Initializ
127
132
  * for cross-tab coordination.
128
133
  *
129
134
  * @param options - Configuration options for loading the recorder
130
- * @param options.recordingId - Optional recording ID to open immediately after loading
131
135
  * @param options.teamId - Team ID for validating recording IDs
132
136
  * @param options.openImmediately - Whether to automatically open the recorder (default: true)
137
+ * Can be set to a specific recording ID as a string to open that recording.
133
138
  * @param options.parseJamData - Custom function to extract recording data from URLs
134
139
  * @param options.applyJamData - Custom function to apply recording data to URLs
135
140
  *
@@ -145,18 +150,13 @@ export declare function initialize({ recorderRefCounter, ...config }?: Initializ
145
150
  *
146
151
  * // Load recorder and open a specific recording
147
152
  * const recorder = await jam.loadRecorder({
148
- * recordingId: "recording-abc123"
153
+ * openImmediately: false, // or "recording-abc123"
149
154
  * });
150
155
  *
151
156
  * // Use the recorder
152
157
  * recorder.open("recording-xyz789", { jamTitle: "Bug Report" });
153
158
  * ```
154
159
  */
155
- export declare function loadRecorder({ recordingId, ...config }?: Omit<InitializeOptions, "recorderRefCounter"> & {
156
- /**
157
- * An optional recording ID; if provided, a recorder will to open the recorder with.
158
- */
159
- recordingId?: string | null;
160
- }): Promise<RecorderSingleton>;
160
+ export declare function loadRecorder({ ...config }?: Omit<InitializeOptions, "recorderRefCounter">): Promise<RecorderSingleton>;
161
161
  export {};
162
162
  //# sourceMappingURL=sdk.d.ts.map
package/lib/sdk.js CHANGED
@@ -1,5 +1,5 @@
1
- function e(){const e=new EventTarget;return{addEventListener(t,r,n){e.addEventListener(t,r,n)},removeEventListener(t,r,n){e.removeEventListener(t,r,n)},dispatch:(t,r)=>e.dispatchEvent(new CustomEvent(t,{detail:r}))}}const t=t=>{const r=`jam:${t}`,n=e();let i=Number.parseInt(localStorage.getItem(r)??"0",10)||0;return window.addEventListener("storage",e=>{if(e.storageArea===localStorage&&e.key===r){const t=Number.parseInt(e.newValue??"",10);Number.isNaN(t)||t===i||(i=t,n.dispatch("update",i))}}),{count:i,addEventListener:n.addEventListener.bind(n),removeEventListener:n.removeEventListener.bind(n),update(e){const t=i;switch(e){case"increment":i+=1;break;case"decrement":i-=1;break;default:i=e}return i<0&&(i=0),i!==t&&(localStorage.setItem(r,`${i}`),n.dispatch("update",i)),i}}},r=e=>{try{const t=new URL(e);return{recordingId:t.searchParams.get("jam-recording"),jamTitle:t.searchParams.get("jam-title")}}catch(e){}return null},n={isInitialized:!1},i=e(),a=i.addEventListener.bind(i),o=i.removeEventListener.bind(i);let d=null;function c({recorderRefCounter:e=t("numRecorders"),...i}={}){if(n.isInitialized)throw new Error("SDK already initialized.");Object.assign(n,{isInitialized:!0,recorderRefCounter:e,config:i}),e.count>0?u("capture"):e.addEventListener("update",()=>u("capture"),{once:!0}),window.addEventListener("popstate",o);const a={apply(e,t,r){const n=Reflect.apply(e,t,r);return o(),n}};function o(){if(d)return;const e=n.config?.parseJamData??r,t=e(window.location.href)?.recordingId;t&&s({recordingId:t})}history.pushState=new Proxy(history.pushState,a),history.replaceState=new Proxy(history.replaceState,a),o()}async function s({recordingId:e,...t}={}){if(d)return d;if(!n.isInitialized)throw new Error("SDK not initialized. Call initialize() first.");if(({Recorder:d}=await u("recorder")),!d)throw new Error("Failed to load recorder script.");const{openImmediately:r,...i}={...n.config,...t};return d.initialize({...i,openImmediately:!e&&r}),n.recorderRefCounter.update("increment"),window.addEventListener("pagehide",()=>{n.recorderRefCounter.update("decrement")}),e&&!1!==r&&d.open(e,i),d}async function u(e){const t=`https://js.jam.dev/${e}.js`,r=await import(
1
+ function e(){const e=new EventTarget;return{addEventListener(t,r,n){e.addEventListener(t,r,n)},removeEventListener(t,r,n){e.removeEventListener(t,r,n)},dispatch:(t,r)=>e.dispatchEvent(new CustomEvent(t,{detail:r}))}}const t=t=>{const r=`jam:${t}`,n=e();let i=Number.parseInt(localStorage.getItem(r)??"0",10)||0;return window.addEventListener("storage",e=>{if(e.storageArea===localStorage&&e.key===r){const t=Number.parseInt(e.newValue??"",10);Number.isNaN(t)||t===i||(i=t,n.dispatch("update",i))}}),{count:i,addEventListener:n.addEventListener.bind(n),removeEventListener:n.removeEventListener.bind(n),update(e){const t=i;switch(e){case"increment":i+=1;break;case"decrement":i-=1;break;default:i=e}return i<0&&(i=0),i!==t&&(localStorage.setItem(r,`${i}`),n.dispatch("update",i)),i}}},r=e=>{try{const t=new URL(e);return{recordingId:t.searchParams.get("jam-recording"),jamTitle:t.searchParams.get("jam-title")}}catch(e){}return null},n={isInitialized:!1},i=e(),a=i.addEventListener.bind(i),o=i.removeEventListener.bind(i),d=()=>n.isInitialized;let c=null;function s({recorderRefCounter:e=t("numRecorders"),...i}={}){if(n.isInitialized)throw new Error("SDK already initialized.");Object.assign(n,{isInitialized:!0,recorderRefCounter:e,config:i}),e.count>0?p("capture"):e.addEventListener("update",()=>p("capture"),{once:!0}),window.addEventListener("popstate",o);const a={apply(e,t,r){const n=Reflect.apply(e,t,r);return o(),n}};function o(){if(c)return;const e=n.config?.parseJamData??r,t="string"==typeof n.config?.openImmediately?n.config.openImmediately:e(window.location.href)?.recordingId;t&&l({openImmediately:!1!==n.config?.openImmediately&&t})}history.pushState=new Proxy(history.pushState,a),history.replaceState=new Proxy(history.replaceState,a),o()}async function l({...e}={}){if(c)return c;if(!n.isInitialized)throw new Error("SDK not initialized. Call initialize() first.");if(({Recorder:c}=await p("recorder")),!c)throw new Error("Failed to load recorder script.");const{openImmediately:t,...r}={...n.config,...e},i="string"==typeof t?t:null;return c.initialize({...r,openImmediately:!i&&(t??!0)}),n.recorderRefCounter.update("increment"),window.addEventListener("pagehide",()=>{n.recorderRefCounter.update("decrement")}),i&&c.open(i,r),c}async function p(e){const t=`https://js.jam.dev/${e}.js`,r=await import(
2
2
  /* webpackIgnore: true */
3
3
  /* @vite-ignore */
4
4
  /* @rollup/plugin-dynamic-import-vars ignore */
5
- t);if("recorder"===e){if(!r.Recorder)throw new Error("Loaded recorder script, but Recorder not found.");i.dispatch("loaded",{type:"script",name:e,Recorder:r.Recorder})}else i.dispatch("loaded",{type:"script",name:e});return r}export{d as Recorder,a as addEventListener,c as initialize,s as loadRecorder,o as removeEventListener};//# sourceMappingURL=sdk.js.map
5
+ t);if("recorder"===e){if(!r.Recorder)throw new Error("Loaded recorder script, but Recorder not found.");i.dispatch("loaded",{type:"script",name:e,Recorder:r.Recorder})}else i.dispatch("loaded",{type:"script",name:e});return r}export{c as Recorder,a as addEventListener,s as initialize,d as isInitialized,l as loadRecorder,o as removeEventListener};//# sourceMappingURL=sdk.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jam.dev/recording-links",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Capture bug reports from your users with the Jam recording links SDK",
5
5
  "keywords": [
6
6
  "jam",
@@ -25,6 +25,10 @@
25
25
  "./sdk": {
26
26
  "types": "./lib/sdk.d.ts",
27
27
  "import": "./lib/sdk.js"
28
+ },
29
+ "./lib/sdk": {
30
+ "types": "./lib/sdk.d.ts",
31
+ "import": "./lib/sdk.js"
28
32
  }
29
33
  },
30
34
  "files": [