@knocklabs/client 0.21.0 → 0.21.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/CHANGELOG.md +6 -0
- package/dist/cjs/api.js +1 -1
- package/dist/cjs/clients/feed/utils.js.map +1 -1
- package/dist/cjs/clients/guide/client.js +1 -1
- package/dist/cjs/clients/guide/client.js.map +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/esm/api.mjs +1 -1
- package/dist/esm/clients/feed/utils.mjs.map +1 -1
- package/dist/esm/clients/guide/client.mjs +212 -190
- package/dist/esm/clients/guide/client.mjs.map +1 -1
- package/dist/esm/index.mjs +11 -10
- package/dist/types/clients/feed/interfaces.d.ts +15 -1
- package/dist/types/clients/feed/interfaces.d.ts.map +1 -1
- package/dist/types/clients/feed/utils.d.ts.map +1 -1
- package/dist/types/clients/guide/client.d.ts +4 -1
- package/dist/types/clients/guide/client.d.ts.map +1 -1
- package/dist/types/clients/guide/index.d.ts +2 -2
- package/dist/types/clients/guide/index.d.ts.map +1 -1
- package/dist/types/clients/guide/types.d.ts +12 -1
- package/dist/types/clients/guide/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/clients/feed/interfaces.ts +15 -4
- package/src/clients/feed/utils.ts +11 -2
- package/src/clients/guide/client.ts +89 -52
- package/src/clients/guide/index.ts +7 -1
- package/src/clients/guide/types.ts +21 -1
|
@@ -157,34 +157,16 @@ const select = (state: StoreState, filters: SelectFilterParams = {}) => {
|
|
|
157
157
|
const defaultGroup = findDefaultGroup(state.guideGroups);
|
|
158
158
|
if (!defaultGroup) return result;
|
|
159
159
|
|
|
160
|
-
const displaySequence =
|
|
160
|
+
const displaySequence = defaultGroup.display_sequence;
|
|
161
161
|
const location = state.location;
|
|
162
162
|
|
|
163
|
-
// If in debug mode, put the forced guide at the beginning of the display sequence.
|
|
164
|
-
if (state.debug.forcedGuideKey) {
|
|
165
|
-
const forcedKeyIndex = displaySequence.indexOf(state.debug.forcedGuideKey);
|
|
166
|
-
if (forcedKeyIndex > -1) {
|
|
167
|
-
displaySequence.splice(forcedKeyIndex, 1);
|
|
168
|
-
}
|
|
169
|
-
displaySequence.unshift(state.debug.forcedGuideKey);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
163
|
for (const [index, guideKey] of displaySequence.entries()) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
// Use preview guide if it exists and matches the forced guide key
|
|
176
|
-
if (
|
|
177
|
-
state.debug.forcedGuideKey === guideKey &&
|
|
178
|
-
state.previewGuides[guideKey]
|
|
179
|
-
) {
|
|
180
|
-
guide = state.previewGuides[guideKey];
|
|
181
|
-
}
|
|
182
|
-
|
|
164
|
+
const guide = state.previewGuides[guideKey] || state.guides[guideKey];
|
|
183
165
|
if (!guide) continue;
|
|
184
166
|
|
|
185
|
-
const affirmed = predicate(guide, {
|
|
167
|
+
const affirmed = predicate(guide, filters, {
|
|
186
168
|
location,
|
|
187
|
-
|
|
169
|
+
ineligibleGuides: state.ineligibleGuides,
|
|
188
170
|
debug: state.debug,
|
|
189
171
|
});
|
|
190
172
|
|
|
@@ -197,15 +179,15 @@ const select = (state: StoreState, filters: SelectFilterParams = {}) => {
|
|
|
197
179
|
return result;
|
|
198
180
|
};
|
|
199
181
|
|
|
200
|
-
type PredicateOpts =
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
};
|
|
182
|
+
type PredicateOpts = Pick<
|
|
183
|
+
StoreState,
|
|
184
|
+
"location" | "ineligibleGuides" | "debug"
|
|
185
|
+
>;
|
|
205
186
|
|
|
206
187
|
const predicate = (
|
|
207
188
|
guide: KnockGuide,
|
|
208
|
-
|
|
189
|
+
filters: SelectFilterParams,
|
|
190
|
+
{ location, ineligibleGuides = {}, debug = {} }: PredicateOpts,
|
|
209
191
|
) => {
|
|
210
192
|
if (filters.type && filters.type !== guide.type) {
|
|
211
193
|
return false;
|
|
@@ -215,11 +197,16 @@ const predicate = (
|
|
|
215
197
|
return false;
|
|
216
198
|
}
|
|
217
199
|
|
|
218
|
-
//
|
|
219
|
-
// This should always run AFTER checking the
|
|
220
|
-
// checking archived status and location rules.
|
|
221
|
-
if (debug.forcedGuideKey
|
|
222
|
-
return
|
|
200
|
+
// If in debug mode with a forced guide key, bypass other filtering and always
|
|
201
|
+
// return true for that guide only. This should always run AFTER checking the
|
|
202
|
+
// filters but BEFORE checking archived status and location rules.
|
|
203
|
+
if (debug.forcedGuideKey) {
|
|
204
|
+
return debug.forcedGuideKey === guide.key;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const ineligible = ineligibleGuides[guide.key];
|
|
208
|
+
if (ineligible) {
|
|
209
|
+
return false;
|
|
223
210
|
}
|
|
224
211
|
|
|
225
212
|
if (!guide.active) {
|
|
@@ -230,6 +217,13 @@ const predicate = (
|
|
|
230
217
|
return false;
|
|
231
218
|
}
|
|
232
219
|
|
|
220
|
+
return checkActivatable(guide, location);
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
export const checkActivatable = (
|
|
224
|
+
guide: KnockGuide,
|
|
225
|
+
location: string | undefined,
|
|
226
|
+
) => {
|
|
233
227
|
const url = location ? newUrl(location) : undefined;
|
|
234
228
|
|
|
235
229
|
const urlRules = guide.activation_url_rules || [];
|
|
@@ -283,18 +277,21 @@ export class KnockGuideClient {
|
|
|
283
277
|
) {
|
|
284
278
|
const {
|
|
285
279
|
trackLocationFromWindow = true,
|
|
280
|
+
// TODO(KNO-11523): Remove once we ship guide toolbar v2, and offload as
|
|
281
|
+
// much debugging specific logic and responsibilities to toolbar.
|
|
282
|
+
trackDebugParams = false,
|
|
286
283
|
throttleCheckInterval = DEFAULT_COUNTER_INCREMENT_INTERVAL,
|
|
287
284
|
} = options;
|
|
288
285
|
const win = checkForWindow();
|
|
289
286
|
|
|
290
287
|
const location = trackLocationFromWindow ? win?.location?.href : undefined;
|
|
291
|
-
|
|
292
|
-
const debug = detectDebugParams();
|
|
288
|
+
const debug = trackDebugParams ? detectDebugParams() : undefined;
|
|
293
289
|
|
|
294
290
|
this.store = new Store<StoreState>({
|
|
295
291
|
guideGroups: [],
|
|
296
292
|
guideGroupDisplayLogs: {},
|
|
297
293
|
guides: {},
|
|
294
|
+
ineligibleGuides: {},
|
|
298
295
|
previewGuides: {},
|
|
299
296
|
queries: {},
|
|
300
297
|
location,
|
|
@@ -376,7 +373,12 @@ export class KnockGuideClient {
|
|
|
376
373
|
>(this.channelId, queryParams);
|
|
377
374
|
queryStatus = { status: "ok" };
|
|
378
375
|
|
|
379
|
-
const {
|
|
376
|
+
const {
|
|
377
|
+
entries,
|
|
378
|
+
guide_groups: groups,
|
|
379
|
+
guide_group_display_logs,
|
|
380
|
+
ineligible_guides,
|
|
381
|
+
} = data;
|
|
380
382
|
|
|
381
383
|
this.knock.log("[Guide] Loading fetched guides");
|
|
382
384
|
this.store.setState((state) => ({
|
|
@@ -384,6 +386,7 @@ export class KnockGuideClient {
|
|
|
384
386
|
guideGroups: groups?.length > 0 ? groups : [mockDefaultGroup(entries)],
|
|
385
387
|
guideGroupDisplayLogs: guide_group_display_logs || {},
|
|
386
388
|
guides: byKey(entries.map((g) => this.localCopy(g))),
|
|
389
|
+
ineligibleGuides: byKey(ineligible_guides || []),
|
|
387
390
|
queries: { ...state.queries, [queryKey]: queryStatus },
|
|
388
391
|
}));
|
|
389
392
|
} catch (e) {
|
|
@@ -418,8 +421,9 @@ export class KnockGuideClient {
|
|
|
418
421
|
const params = {
|
|
419
422
|
...this.targetParams,
|
|
420
423
|
user_id: this.knock.userId,
|
|
421
|
-
force_all_guides:
|
|
422
|
-
|
|
424
|
+
force_all_guides:
|
|
425
|
+
debugState?.forcedGuideKey || debugState?.debugging ? true : undefined,
|
|
426
|
+
preview_session_id: debugState?.previewSessionId || undefined,
|
|
423
427
|
};
|
|
424
428
|
|
|
425
429
|
const newChannel = this.socket.channel(this.socketChannelTopic, params);
|
|
@@ -484,6 +488,8 @@ export class KnockGuideClient {
|
|
|
484
488
|
private handleSocketEvent(payload: GuideSocketEvent) {
|
|
485
489
|
const { event, data } = payload;
|
|
486
490
|
|
|
491
|
+
// TODO(KNO-11489): Include an ineligible guide in the socket payload too
|
|
492
|
+
// and process it when handling socket events in real time.
|
|
487
493
|
switch (event) {
|
|
488
494
|
case "guide.added":
|
|
489
495
|
return this.addOrReplaceGuide(payload);
|
|
@@ -565,6 +571,39 @@ export class KnockGuideClient {
|
|
|
565
571
|
}
|
|
566
572
|
}
|
|
567
573
|
|
|
574
|
+
setDebug(debugOpts?: Omit<DebugState, "debugging">) {
|
|
575
|
+
this.knock.log("[Guide] .setDebug()");
|
|
576
|
+
const shouldRefetch = !this.store.state.debug?.debugging;
|
|
577
|
+
|
|
578
|
+
this.store.setState((state) => ({
|
|
579
|
+
...state,
|
|
580
|
+
debug: { ...debugOpts, debugging: true },
|
|
581
|
+
}));
|
|
582
|
+
|
|
583
|
+
if (shouldRefetch) {
|
|
584
|
+
this.knock.log(
|
|
585
|
+
`[Guide] Start debugging, refetching guides and resubscribing to the websocket channel`,
|
|
586
|
+
);
|
|
587
|
+
this.fetch();
|
|
588
|
+
this.subscribe();
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
unsetDebug() {
|
|
593
|
+
this.knock.log("[Guide] .unsetDebug()");
|
|
594
|
+
const shouldRefetch = this.store.state.debug?.debugging;
|
|
595
|
+
|
|
596
|
+
this.store.setState((state) => ({ ...state, debug: undefined }));
|
|
597
|
+
|
|
598
|
+
if (shouldRefetch) {
|
|
599
|
+
this.knock.log(
|
|
600
|
+
`[Guide] Stop debugging, refetching guides and resubscribing to the websocket channel`,
|
|
601
|
+
);
|
|
602
|
+
this.fetch();
|
|
603
|
+
this.subscribe();
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
568
607
|
//
|
|
569
608
|
// Store selector
|
|
570
609
|
//
|
|
@@ -736,17 +775,8 @@ export class KnockGuideClient {
|
|
|
736
775
|
// callback to a setTimeout, but just to be safe.
|
|
737
776
|
this.ensureClearTimeout();
|
|
738
777
|
|
|
739
|
-
//
|
|
740
|
-
|
|
741
|
-
if (this.store.state.debug.forcedGuideKey) {
|
|
742
|
-
resolved = this.stage.ordered.find(
|
|
743
|
-
(x) => x === this.store.state.debug.forcedGuideKey,
|
|
744
|
-
);
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
if (!resolved) {
|
|
748
|
-
resolved = this.stage.ordered.find((x) => x !== undefined);
|
|
749
|
-
}
|
|
778
|
+
// Resolve to the first non-undefined guide in the stage.
|
|
779
|
+
const resolved = this.stage.ordered.find((x) => x !== undefined);
|
|
750
780
|
|
|
751
781
|
this.knock.log(
|
|
752
782
|
`[Guide] Closing the current group stage: resolved=${resolved}`,
|
|
@@ -937,7 +967,7 @@ export class KnockGuideClient {
|
|
|
937
967
|
// Get the next unarchived step.
|
|
938
968
|
getStep() {
|
|
939
969
|
// If debugging this guide, return the first step regardless of archive status
|
|
940
|
-
if (self.store.state.debug
|
|
970
|
+
if (self.store.state.debug?.forcedGuideKey === this.key) {
|
|
941
971
|
return this.steps[0];
|
|
942
972
|
}
|
|
943
973
|
|
|
@@ -994,7 +1024,7 @@ export class KnockGuideClient {
|
|
|
994
1024
|
|
|
995
1025
|
// Append debug params
|
|
996
1026
|
const debugState = this.store.state.debug;
|
|
997
|
-
if (debugState
|
|
1027
|
+
if (debugState?.forcedGuideKey || debugState?.debugging) {
|
|
998
1028
|
combinedParams.force_all_guides = true;
|
|
999
1029
|
}
|
|
1000
1030
|
|
|
@@ -1163,8 +1193,15 @@ export class KnockGuideClient {
|
|
|
1163
1193
|
|
|
1164
1194
|
this.knock.log(`[Guide] Detected a location change: ${href}`);
|
|
1165
1195
|
|
|
1196
|
+
if (!this.options.trackDebugParams) {
|
|
1197
|
+
this.setLocation(href);
|
|
1198
|
+
return;
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
// TODO(KNO-11523): Remove below once we ship toolbar v2.
|
|
1202
|
+
|
|
1166
1203
|
// If entering debug mode, fetch all guides.
|
|
1167
|
-
const currentDebugParams = this.store.state.debug;
|
|
1204
|
+
const currentDebugParams = this.store.state.debug || {};
|
|
1168
1205
|
const newDebugParams = detectDebugParams();
|
|
1169
1206
|
|
|
1170
1207
|
this.setLocation(href, { debug: newDebugParams });
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {
|
|
2
|
+
KnockGuideClient,
|
|
3
|
+
DEBUG_QUERY_PARAMS,
|
|
4
|
+
checkActivatable,
|
|
5
|
+
} from "./client";
|
|
2
6
|
export type {
|
|
3
7
|
KnockGuide,
|
|
4
8
|
KnockGuideStep,
|
|
9
|
+
GuideIneligibilityMarker as KnockGuideIneligibilityMarker,
|
|
5
10
|
TargetParams as KnockGuideTargetParams,
|
|
6
11
|
SelectFilterParams as KnockGuideFilterParams,
|
|
7
12
|
SelectGuideOpts as KnockSelectGuideOpts,
|
|
8
13
|
SelectGuidesOpts as KnockSelectGuidesOpts,
|
|
14
|
+
StoreState as KnockGuideClientStoreState,
|
|
9
15
|
} from "./types";
|
|
@@ -65,6 +65,19 @@ export interface GuideGroupData {
|
|
|
65
65
|
updated_at: string;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
type GuideIneligibilityReason =
|
|
69
|
+
| "guide_not_active"
|
|
70
|
+
| "marked_as_archived"
|
|
71
|
+
| "target_conditions_not_met"
|
|
72
|
+
| "not_in_target_audience";
|
|
73
|
+
|
|
74
|
+
export type GuideIneligibilityMarker = {
|
|
75
|
+
__typename: "GuideIneligibilityMarker";
|
|
76
|
+
key: KnockGuide["key"];
|
|
77
|
+
reason: GuideIneligibilityReason;
|
|
78
|
+
message: string;
|
|
79
|
+
};
|
|
80
|
+
|
|
68
81
|
export type GetGuidesQueryParams = {
|
|
69
82
|
data?: string;
|
|
70
83
|
tenant?: string;
|
|
@@ -76,6 +89,7 @@ export type GetGuidesResponse = {
|
|
|
76
89
|
entries: GuideData[];
|
|
77
90
|
guide_groups: GuideGroupData[];
|
|
78
91
|
guide_group_display_logs: Record<GuideGroupData["key"], string>;
|
|
92
|
+
ineligible_guides: GuideIneligibilityMarker[];
|
|
79
93
|
};
|
|
80
94
|
|
|
81
95
|
//
|
|
@@ -194,6 +208,7 @@ export type QueryStatus = {
|
|
|
194
208
|
};
|
|
195
209
|
|
|
196
210
|
export type DebugState = {
|
|
211
|
+
debugging?: boolean;
|
|
197
212
|
forcedGuideKey?: string | null;
|
|
198
213
|
previewSessionId?: string | null;
|
|
199
214
|
};
|
|
@@ -202,11 +217,15 @@ export type StoreState = {
|
|
|
202
217
|
guideGroups: GuideGroupData[];
|
|
203
218
|
guideGroupDisplayLogs: Record<GuideGroupData["key"], string>;
|
|
204
219
|
guides: Record<KnockGuide["key"], KnockGuide>;
|
|
220
|
+
ineligibleGuides: Record<
|
|
221
|
+
GuideIneligibilityMarker["key"],
|
|
222
|
+
GuideIneligibilityMarker
|
|
223
|
+
>;
|
|
205
224
|
previewGuides: Record<KnockGuide["key"], KnockGuide>;
|
|
206
225
|
queries: Record<QueryKey, QueryStatus>;
|
|
207
226
|
location: string | undefined;
|
|
208
227
|
counter: number;
|
|
209
|
-
debug
|
|
228
|
+
debug?: DebugState;
|
|
210
229
|
};
|
|
211
230
|
|
|
212
231
|
export type QueryFilterParams = Pick<GetGuidesQueryParams, "type">;
|
|
@@ -229,6 +248,7 @@ export type TargetParams = {
|
|
|
229
248
|
|
|
230
249
|
export type ConstructorOpts = {
|
|
231
250
|
trackLocationFromWindow?: boolean;
|
|
251
|
+
trackDebugParams?: boolean;
|
|
232
252
|
orderResolutionDuration?: number;
|
|
233
253
|
throttleCheckInterval?: number;
|
|
234
254
|
};
|