@knocklabs/client 0.16.4 → 0.17.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.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/clients/guide/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/clients/guide/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knocklabs/client",
3
- "version": "0.16.4",
3
+ "version": "0.17.0",
4
4
  "description": "The clientside library for interacting with Knock",
5
5
  "homepage": "https://github.com/knocklabs/javascript/tree/main/packages/client",
6
6
  "author": "@knocklabs",
@@ -50,7 +50,7 @@
50
50
  "@babel/plugin-proposal-class-properties": "^7.16.7",
51
51
  "@babel/plugin-proposal-object-rest-spread": "^7.16.7",
52
52
  "@babel/plugin-transform-runtime": "^7.28.0",
53
- "@babel/preset-env": "^7.27.1",
53
+ "@babel/preset-env": "^7.28.3",
54
54
  "@babel/preset-typescript": "^7.27.0",
55
55
  "@codecov/vite-plugin": "^1.9.1",
56
56
  "@types/jsonwebtoken": "^9.0.10",
@@ -62,7 +62,7 @@
62
62
  "jsonwebtoken": "^9.0.2",
63
63
  "prettier": "^3.5.3",
64
64
  "rimraf": "^6.0.1",
65
- "rollup": "^4.41.1",
65
+ "rollup": "^4.46.2",
66
66
  "typescript": "^5.8.3",
67
67
  "vite": "^5.4.19",
68
68
  "vitest": "^3.1.1"
@@ -13,9 +13,14 @@ import {
13
13
  findDefaultGroup,
14
14
  formatFilters,
15
15
  mockDefaultGroup,
16
+ newUrl,
17
+ predicateUrlPatterns,
18
+ predicateUrlRules,
16
19
  } from "./helpers";
17
20
  import {
21
+ Any,
18
22
  ConstructorOpts,
23
+ DebugState,
19
24
  GetGuidesQueryParams,
20
25
  GetGuidesResponse,
21
26
  GroupStage,
@@ -23,6 +28,7 @@ import {
23
28
  GuideData,
24
29
  GuideGroupAddedEvent,
25
30
  GuideGroupUpdatedEvent,
31
+ GuideLivePreviewUpdatedEvent,
26
32
  GuideRemovedEvent,
27
33
  GuideSocketEvent,
28
34
  GuideStepData,
@@ -49,6 +55,15 @@ const DEFAULT_ORDER_RESOLUTION_DURATION = 50; // in milliseconds
49
55
  // trigger subscribed callbacks.
50
56
  const DEFAULT_COUNTER_INCREMENT_INTERVAL = 30 * 1000; // in milliseconds
51
57
 
58
+ // Maximum number of retry attempts for channel subscription
59
+ const SUBSCRIBE_RETRY_LIMIT = 3;
60
+
61
+ // Debug query param keys
62
+ export const DEBUG_QUERY_PARAMS = {
63
+ GUIDE_KEY: "knock_guide_key",
64
+ PREVIEW_SESSION_ID: "knock_preview_session_id",
65
+ };
66
+
52
67
  // Return the global window object if defined, so to safely guard against SSR.
53
68
  const checkForWindow = () => {
54
69
  if (typeof window !== "undefined") {
@@ -59,6 +74,20 @@ const checkForWindow = () => {
59
74
  export const guidesApiRootPath = (userId: string | undefined | null) =>
60
75
  `/v1/users/${userId}/guides`;
61
76
 
77
+ // Detect debug params like "knock_guide_key" from URL.
78
+ const detectDebugParams = (): DebugState => {
79
+ const win = checkForWindow();
80
+ if (!win) {
81
+ return { forcedGuideKey: null, previewSessionId: null };
82
+ }
83
+
84
+ const urlParams = new URLSearchParams(win.location.search);
85
+ const forcedGuideKey = urlParams.get(DEBUG_QUERY_PARAMS.GUIDE_KEY);
86
+ const previewSessionId = urlParams.get(DEBUG_QUERY_PARAMS.PREVIEW_SESSION_ID);
87
+
88
+ return { forcedGuideKey, previewSessionId };
89
+ };
90
+
62
91
  const select = (state: StoreState, filters: SelectFilterParams = {}) => {
63
92
  // A map of selected guides as values, with its order index as keys.
64
93
  const result = new SelectionResult();
@@ -66,16 +95,37 @@ const select = (state: StoreState, filters: SelectFilterParams = {}) => {
66
95
  const defaultGroup = findDefaultGroup(state.guideGroups);
67
96
  if (!defaultGroup) return result;
68
97
 
69
- const displaySequence = defaultGroup.display_sequence;
98
+ const displaySequence = [...defaultGroup.display_sequence];
70
99
  const location = state.location;
71
100
 
101
+ // If in debug mode, put the forced guide at the beginning of the display sequence.
102
+ if (state.debug.forcedGuideKey) {
103
+ const forcedKeyIndex = displaySequence.indexOf(state.debug.forcedGuideKey);
104
+ if (forcedKeyIndex > -1) {
105
+ displaySequence.splice(forcedKeyIndex, 1);
106
+ }
107
+ displaySequence.unshift(state.debug.forcedGuideKey);
108
+ }
109
+
72
110
  for (const [index, guideKey] of displaySequence.entries()) {
73
- const guide = state.guides[guideKey];
111
+ let guide = state.guides[guideKey];
74
112
  if (!guide) continue;
75
113
 
76
- const affirmed = predicate(guide, { location, filters });
114
+ const affirmed = predicate(guide, {
115
+ location,
116
+ filters,
117
+ debug: state.debug,
118
+ });
77
119
  if (!affirmed) continue;
78
120
 
121
+ // Use preview guide if it exists and matches the forced guide key
122
+ if (
123
+ state.debug.forcedGuideKey === guideKey &&
124
+ state.previewGuides[guideKey]
125
+ ) {
126
+ guide = state.previewGuides[guideKey];
127
+ }
128
+
79
129
  result.set(index, guide);
80
130
  }
81
131
 
@@ -86,12 +136,18 @@ const select = (state: StoreState, filters: SelectFilterParams = {}) => {
86
136
  type PredicateOpts = {
87
137
  location?: string | undefined;
88
138
  filters?: SelectFilterParams | undefined;
139
+ debug: DebugState;
89
140
  };
90
141
 
91
142
  const predicate = (
92
143
  guide: KnockGuide,
93
- { location, filters = {} }: PredicateOpts,
144
+ { location, filters = {}, debug = {} }: PredicateOpts,
94
145
  ) => {
146
+ // Bypass filtering if debugging the current guide.
147
+ if (debug.forcedGuideKey === guide.key) {
148
+ return true;
149
+ }
150
+
95
151
  if (filters.type && filters.type !== guide.type) {
96
152
  return false;
97
153
  }
@@ -104,36 +160,17 @@ const predicate = (
104
160
  return false;
105
161
  }
106
162
 
107
- const locationRules = guide.activation_location_rules || [];
108
-
109
- if (locationRules.length > 0 && location) {
110
- const allowed = locationRules.reduce<boolean | undefined>((acc, rule) => {
111
- // Any matched block rule prevails so no need to evaluate further
112
- // as soon as there is one.
113
- if (acc === false) return false;
114
-
115
- // At this point we either have a matched allow rule (acc is true),
116
- // or no matched rule found yet (acc is undefined).
163
+ const url = location ? newUrl(location) : undefined;
117
164
 
118
- switch (rule.directive) {
119
- case "allow": {
120
- // No need to evaluate more allow rules once we matched one
121
- // since any matched allowed rule means allow.
122
- if (acc === true) return true;
123
-
124
- const matched = rule.pattern.test(location);
125
- return matched ? true : undefined;
126
- }
127
-
128
- case "block": {
129
- // Always test block rules (unless already matched to block)
130
- // because they'd prevail over matched allow rules.
131
- const matched = rule.pattern.test(location);
132
- return matched ? false : acc;
133
- }
134
- }
135
- }, undefined);
165
+ const urlRules = guide.activation_url_rules || [];
166
+ const urlPatterns = guide.activation_url_patterns || [];
136
167
 
168
+ // A guide can have either activation url rules XOR url patterns, but not both.
169
+ if (url && urlRules.length > 0) {
170
+ const allowed = predicateUrlRules(url, urlRules);
171
+ if (!allowed) return false;
172
+ } else if (url && urlPatterns.length > 0) {
173
+ const allowed = predicateUrlPatterns(url, urlPatterns);
137
174
  if (!allowed) return false;
138
175
  }
139
176
 
@@ -153,7 +190,9 @@ export class KnockGuideClient {
153
190
  "guide.removed",
154
191
  "guide_group.added",
155
192
  "guide_group.updated",
193
+ "guide.live_preview_updated",
156
194
  ];
195
+ private subscribeRetryCount = 0;
157
196
 
158
197
  // Original history methods to monkey patch, or restore in cleanups.
159
198
  private pushStateFn: History["pushState"] | undefined;
@@ -177,14 +216,18 @@ export class KnockGuideClient {
177
216
 
178
217
  const location = trackLocationFromWindow ? win?.location.href : undefined;
179
218
 
219
+ const debug = detectDebugParams();
220
+
180
221
  this.store = new Store<StoreState>({
181
222
  guideGroups: [],
182
223
  guideGroupDisplayLogs: {},
183
224
  guides: {},
225
+ previewGuides: {},
184
226
  queries: {},
185
227
  location,
186
228
  // Increment to update the state store and trigger re-selection.
187
229
  counter: 0,
230
+ debug,
188
231
  });
189
232
 
190
233
  // In server environments we might not have a socket connection.
@@ -298,7 +341,14 @@ export class KnockGuideClient {
298
341
  }
299
342
 
300
343
  // Join the channel topic and subscribe to supported events.
301
- const params = { ...this.targetParams, user_id: this.knock.userId };
344
+ const debugState = this.store.state.debug;
345
+ const params = {
346
+ ...this.targetParams,
347
+ user_id: this.knock.userId,
348
+ force_all_guides: debugState.forcedGuideKey ? true : undefined,
349
+ preview_session_id: debugState.previewSessionId || undefined,
350
+ };
351
+
302
352
  const newChannel = this.socket.channel(this.socketChannelTopic, params);
303
353
 
304
354
  for (const eventType of this.socketEventTypes) {
@@ -306,13 +356,44 @@ export class KnockGuideClient {
306
356
  }
307
357
 
308
358
  if (["closed", "errored"].includes(newChannel.state)) {
309
- newChannel.join();
359
+ // Reset retry count for new subscription attempt
360
+ this.subscribeRetryCount = 0;
361
+
362
+ newChannel
363
+ .join()
364
+ .receive("ok", () => {
365
+ this.knock.log("[Guide] Successfully joined channel");
366
+ })
367
+ .receive("error", (resp) => {
368
+ this.knock.log(
369
+ `[Guide] Failed to join channel: ${JSON.stringify(resp)}`,
370
+ );
371
+ this.handleChannelJoinError();
372
+ })
373
+ .receive("timeout", () => {
374
+ this.knock.log("[Guide] Channel join timed out");
375
+ this.handleChannelJoinError();
376
+ });
310
377
  }
311
378
 
312
379
  // Track the joined channel.
313
380
  this.socketChannel = newChannel;
314
381
  }
315
382
 
383
+ private handleChannelJoinError() {
384
+ // Prevent phx channel from retrying forever in case of either network or
385
+ // other errors (e.g. auth error, invalid channel etc)
386
+ if (this.subscribeRetryCount >= SUBSCRIBE_RETRY_LIMIT) {
387
+ this.knock.log(
388
+ `[Guide] Channel join max retry limit reached: ${this.subscribeRetryCount}`,
389
+ );
390
+ this.unsubscribe();
391
+ return;
392
+ }
393
+
394
+ this.subscribeRetryCount++;
395
+ }
396
+
316
397
  unsubscribe() {
317
398
  if (!this.socketChannel) return;
318
399
  this.knock.log("[Guide] Unsubscribing from real time updates");
@@ -346,23 +427,41 @@ export class KnockGuideClient {
346
427
  case "guide_group.updated":
347
428
  return this.addOrReplaceGuideGroup(payload);
348
429
 
430
+ case "guide.live_preview_updated":
431
+ return this.updatePreviewGuide(payload);
432
+
349
433
  default:
350
434
  return;
351
435
  }
352
436
  }
353
437
 
354
- setLocation(href: string) {
438
+ setLocation(href: string, additionalParams: Partial<StoreState> = {}) {
355
439
  // Make sure to clear out the stage.
356
440
  this.clearGroupStage();
357
441
 
358
- this.store.setState((state) => ({ ...state, location: href }));
442
+ this.store.setState((state) => {
443
+ // Clear preview guides if no longer in preview mode
444
+ const previewGuides = additionalParams?.debug?.previewSessionId
445
+ ? state.previewGuides
446
+ : {};
447
+
448
+ return {
449
+ ...state,
450
+ ...additionalParams,
451
+ previewGuides,
452
+ location: href,
453
+ };
454
+ });
359
455
  }
360
456
 
361
457
  //
362
458
  // Store selector
363
459
  //
364
460
 
365
- selectGuides(state: StoreState, filters: SelectFilterParams = {}) {
461
+ selectGuides<C = Any>(
462
+ state: StoreState,
463
+ filters: SelectFilterParams = {},
464
+ ): KnockGuide<C>[] {
366
465
  if (Object.keys(state.guides).length === 0) {
367
466
  return [];
368
467
  }
@@ -381,7 +480,10 @@ export class KnockGuideClient {
381
480
  return [...result.values()];
382
481
  }
383
482
 
384
- selectGuide(state: StoreState, filters: SelectFilterParams = {}) {
483
+ selectGuide<C = Any>(
484
+ state: StoreState,
485
+ filters: SelectFilterParams = {},
486
+ ): KnockGuide<C> | undefined {
385
487
  if (Object.keys(state.guides).length === 0) {
386
488
  return undefined;
387
489
  }
@@ -504,10 +606,22 @@ export class KnockGuideClient {
504
606
  // callback to a setTimeout, but just to be safe.
505
607
  this.ensureClearTimeout();
506
608
 
609
+ // If in debug mode, try to resolve the forced guide, otherwise return the first non-undefined guide.
610
+ let resolved = undefined;
611
+ if (this.store.state.debug.forcedGuideKey) {
612
+ resolved = this.stage.ordered.find(
613
+ (x) => x === this.store.state.debug.forcedGuideKey,
614
+ );
615
+ }
616
+
617
+ if (!resolved) {
618
+ resolved = this.stage.ordered.find((x) => x !== undefined);
619
+ }
620
+
507
621
  this.stage = {
508
622
  ...this.stage,
509
623
  status: "closed",
510
- resolved: this.stage.ordered.find((x) => x !== undefined),
624
+ resolved,
511
625
  timeoutId: null,
512
626
  };
513
627
 
@@ -671,6 +785,11 @@ export class KnockGuideClient {
671
785
  ...remoteGuide,
672
786
  // Get the next unarchived step.
673
787
  getStep() {
788
+ // If debugging this guide, return the first step regardless of archive status
789
+ if (self.store.state.debug.forcedGuideKey === this.key) {
790
+ return this.steps[0];
791
+ }
792
+
674
793
  return this.steps.find((s) => !s.message.archived_at);
675
794
  },
676
795
  } as KnockGuide;
@@ -706,8 +825,8 @@ export class KnockGuideClient {
706
825
  return localStep;
707
826
  });
708
827
 
709
- localGuide.activation_location_rules =
710
- remoteGuide.activation_location_rules.map((rule) => {
828
+ localGuide.activation_url_patterns =
829
+ remoteGuide.activation_url_patterns.map((rule) => {
711
830
  return {
712
831
  ...rule,
713
832
  pattern: new URLPattern({ pathname: rule.pathname }),
@@ -719,7 +838,16 @@ export class KnockGuideClient {
719
838
 
720
839
  private buildQueryParams(filterParams: QueryFilterParams = {}) {
721
840
  // Combine the target params with the given filter params.
722
- const combinedParams = { ...this.targetParams, ...filterParams };
841
+ const combinedParams: GenericData = {
842
+ ...this.targetParams,
843
+ ...filterParams,
844
+ };
845
+
846
+ // Append debug params
847
+ const debugState = this.store.state.debug;
848
+ if (debugState.forcedGuideKey) {
849
+ combinedParams.force_all_guides = true;
850
+ }
723
851
 
724
852
  // Prune out any keys that have an undefined or null value.
725
853
  let params = Object.fromEntries(
@@ -864,6 +992,15 @@ export class KnockGuideClient {
864
992
  });
865
993
  }
866
994
 
995
+ private updatePreviewGuide({ data }: GuideLivePreviewUpdatedEvent) {
996
+ const guide = this.localCopy(data.guide);
997
+
998
+ this.store.setState((state) => {
999
+ const previewGuides = { ...state.previewGuides, [guide.key]: guide };
1000
+ return { ...state, previewGuides };
1001
+ });
1002
+ }
1003
+
867
1004
  // Define as an arrow func property to always bind this to the class instance.
868
1005
  private handleLocationChange = () => {
869
1006
  const win = checkForWindow();
@@ -873,9 +1010,36 @@ export class KnockGuideClient {
873
1010
  if (this.store.state.location === href) return;
874
1011
 
875
1012
  this.knock.log(`[Guide] Handle Location change: ${href}`);
876
- this.setLocation(href);
1013
+
1014
+ // If entering debug mode, fetch all guides.
1015
+ const currentDebugParams = this.store.state.debug;
1016
+ const newDebugParams = detectDebugParams();
1017
+ this.setLocation(href, { debug: newDebugParams });
1018
+
1019
+ // If debug state has changed, refetch guides and resubscribe to the websocket channel
1020
+ const debugStateChanged = this.checkDebugStateChanged(
1021
+ currentDebugParams,
1022
+ newDebugParams,
1023
+ );
1024
+
1025
+ if (debugStateChanged) {
1026
+ this.knock.log(
1027
+ `[Guide] Debug state changed, refetching guides and resubscribing to the websocket channel`,
1028
+ );
1029
+ this.fetch();
1030
+ this.subscribe();
1031
+ }
877
1032
  };
878
1033
 
1034
+ // Returns whether debug params have changed. For guide key, we only check
1035
+ // presence since the exact value has no impact on fetch/subscribe
1036
+ private checkDebugStateChanged(a: DebugState, b: DebugState): boolean {
1037
+ return (
1038
+ Boolean(a.forcedGuideKey) !== Boolean(b.forcedGuideKey) ||
1039
+ a.previewSessionId !== b.previewSessionId
1040
+ );
1041
+ }
1042
+
879
1043
  private listenForLocationChangesFromWindow() {
880
1044
  const win = checkForWindow();
881
1045
  if (win?.history) {
@@ -1,7 +1,9 @@
1
1
  import {
2
+ GuideActivationUrlRuleData,
2
3
  GuideData,
3
4
  GuideGroupData,
4
5
  KnockGuide,
6
+ KnockGuideActivationUrlPattern,
5
7
  SelectFilterParams,
6
8
  } from "./types";
7
9
 
@@ -96,3 +98,100 @@ export const checkIfThrottled = (
96
98
  // accurate regardless of local timezones.
97
99
  return currentTimeInMilliseconds <= throttleWindowEndInMilliseconds;
98
100
  };
101
+
102
+ // Safely parse and build a new URL object.
103
+ export const newUrl = (location: string) => {
104
+ try {
105
+ return new URL(location);
106
+ } catch {
107
+ return undefined;
108
+ }
109
+ };
110
+
111
+ // Evaluates whether the given location url satisfies the url rule.
112
+ export const evaluateUrlRule = (
113
+ url: URL,
114
+ urlRule: GuideActivationUrlRuleData,
115
+ ) => {
116
+ if (urlRule.variable === "pathname") {
117
+ if (urlRule.operator === "equal_to") {
118
+ const argument = urlRule.argument.startsWith("/")
119
+ ? urlRule.argument
120
+ : `/${urlRule.argument}`;
121
+
122
+ return argument === url.pathname;
123
+ }
124
+
125
+ if (urlRule.operator === "contains") {
126
+ return url.pathname.includes(urlRule.argument);
127
+ }
128
+
129
+ return false;
130
+ }
131
+
132
+ return false;
133
+ };
134
+
135
+ export const predicateUrlRules = (
136
+ url: URL,
137
+ urlRules: GuideActivationUrlRuleData[],
138
+ ) => {
139
+ return urlRules.reduce<boolean | undefined>((acc, urlRule) => {
140
+ // Any matched block rule prevails so no need to evaluate further
141
+ // as soon as there is one.
142
+ if (acc === false) return false;
143
+
144
+ // At this point we either have a matched allow rule (acc is true),
145
+ // or no matched rule found yet (acc is undefined).
146
+
147
+ switch (urlRule.directive) {
148
+ case "allow": {
149
+ // No need to evaluate more allow rules once we matched one
150
+ // since any matched allowed rule means allow.
151
+ if (acc === true) return true;
152
+
153
+ const matched = evaluateUrlRule(url, urlRule);
154
+ return matched ? true : undefined;
155
+ }
156
+
157
+ case "block": {
158
+ // Always test block rules (unless already matched to block)
159
+ // because they'd prevail over matched allow rules.
160
+ const matched = evaluateUrlRule(url, urlRule);
161
+ return matched ? false : acc;
162
+ }
163
+ }
164
+ }, undefined);
165
+ };
166
+
167
+ export const predicateUrlPatterns = (
168
+ url: URL,
169
+ urlPatterns: KnockGuideActivationUrlPattern[],
170
+ ) => {
171
+ return urlPatterns.reduce<boolean | undefined>((acc, urlPattern) => {
172
+ // Any matched block rule prevails so no need to evaluate further
173
+ // as soon as there is one.
174
+ if (acc === false) return false;
175
+
176
+ // At this point we either have a matched allow rule (acc is true),
177
+ // or no matched rule found yet (acc is undefined).
178
+
179
+ switch (urlPattern.directive) {
180
+ case "allow": {
181
+ // No need to evaluate more allow rules once we matched one
182
+ // since any matched allowed rule means allow.
183
+ if (acc === true) return true;
184
+
185
+ const matched = urlPattern.pattern.test(url);
186
+ return matched ? true : undefined;
187
+ }
188
+
189
+ case "block": {
190
+ // Always test block rules (unless already matched to block)
191
+ // because they'd prevail over matched allow rules.
192
+ const matched = urlPattern.pattern.test(url);
193
+ return matched ? false : acc;
194
+ }
195
+ }
196
+ }, undefined);
197
+ };
@@ -1,4 +1,4 @@
1
- export { KnockGuideClient } from "./client";
1
+ export { KnockGuideClient, DEBUG_QUERY_PARAMS } from "./client";
2
2
  export type {
3
3
  KnockGuide,
4
4
  KnockGuideStep,