@wireai/activation 0.15.0 → 0.16.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/AGENTS.md +95 -20
- package/CHANGELOG.md +707 -0
- package/INTEGRATION_PROMPT.md +61 -23
- package/README.md +100 -25
- package/dist/analytics/index.d.mts +32 -10
- package/dist/analytics/index.d.ts +32 -10
- package/dist/analytics/index.js +288 -127
- package/dist/analytics/index.js.map +1 -1
- package/dist/analytics/index.mjs +288 -127
- package/dist/analytics/index.mjs.map +1 -1
- package/dist/coachmarks/index.d.mts +14 -0
- package/dist/coachmarks/index.d.ts +14 -0
- package/dist/coachmarks/index.js +73 -20
- package/dist/coachmarks/index.js.map +1 -1
- package/dist/coachmarks/index.mjs +73 -20
- package/dist/coachmarks/index.mjs.map +1 -1
- package/dist/{currentSession-orZy5p1e.d.mts → currentSession-Bz7G6lno.d.mts} +25 -35
- package/dist/{currentSession-CFSRZ2wg.d.ts → currentSession-z-CZ55ad.d.ts} +25 -35
- package/dist/index.d.mts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +125 -36
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +125 -36
- package/dist/index.mjs.map +1 -1
- package/dist/questionnaire/index.d.mts +0 -13
- package/dist/questionnaire/index.d.ts +0 -13
- package/dist/questionnaire/index.js +154 -43
- package/dist/questionnaire/index.js.map +1 -1
- package/dist/questionnaire/index.mjs +155 -44
- package/dist/questionnaire/index.mjs.map +1 -1
- package/dist/reviews/index.js +159 -91
- package/dist/reviews/index.js.map +1 -1
- package/dist/reviews/index.mjs +160 -92
- package/dist/reviews/index.mjs.map +1 -1
- package/dist/showcase/index.js +59 -18
- package/dist/showcase/index.js.map +1 -1
- package/dist/showcase/index.mjs +60 -19
- package/dist/showcase/index.mjs.map +1 -1
- package/llms.txt +9 -9
- package/package.json +6 -9
- package/src/analytics/currentSession.ts +141 -4
- package/src/analytics/index.ts +6 -1
- package/src/analytics/reportClientEvent.ts +19 -10
- package/src/analytics/useAnalytics.ts +74 -15
- package/src/analytics/wireDoctor.ts +152 -7
- package/src/coachmarks/CoachmarkProvider.tsx +26 -5
- package/src/coachmarks/runtime.ts +53 -0
- package/src/coachmarks/useCoachmarkTour.ts +51 -1
- package/src/context/deviceId.ts +49 -15
- package/src/features/WireFeaturesProvider.tsx +72 -12
- package/src/features/fetchWireFeatures.ts +49 -11
- package/src/features/useWireFeatures.ts +39 -3
- package/src/identity/identityRecord.ts +15 -2
- package/src/questionnaire/QuestionnaireGate.tsx +40 -1
- package/src/questionnaire/transport.ts +22 -8
- package/src/questionnaire/useQuestionnaireGate.ts +58 -7
- package/src/reviews/ReviewGate.tsx +39 -0
- package/src/reviews/idempotency.ts +38 -0
- package/src/reviews/runtime.ts +39 -10
- package/src/reviews/transport.ts +22 -8
- package/src/reviews/useReviewGate.ts +57 -7
- package/src/session-analytics/lifecycle.ts +16 -0
- package/src/session-analytics/useLifecycleEvents.ts +30 -2
- package/src/session-analytics/useSessionStart.ts +22 -2
- package/src/showcase/FeatureShowcase.tsx +50 -3
- package/src/types.ts +5 -4
- package/src/utils/withDeadline.ts +70 -0
|
@@ -89,17 +89,31 @@ var failOpen = async (storage, key) => {
|
|
|
89
89
|
const cached3 = await readCachedFeatures(storage, key);
|
|
90
90
|
return (_a = cached3 == null ? void 0 : cached3.features) != null ? _a : defaultWireFeatures;
|
|
91
91
|
};
|
|
92
|
-
var
|
|
92
|
+
var NO_ANSWER = /* @__PURE__ */ Symbol("wire-features-no-answer");
|
|
93
|
+
var fetchFeaturesJson = async (url, apiKey, timeoutMs) => {
|
|
93
94
|
const controller = typeof AbortController !== "undefined" ? new AbortController() : void 0;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
let timer;
|
|
96
|
+
const expired = new Promise((resolve) => {
|
|
97
|
+
timer = setTimeout(() => {
|
|
98
|
+
controller == null ? void 0 : controller.abort();
|
|
99
|
+
resolve(NO_ANSWER);
|
|
100
|
+
}, timeoutMs);
|
|
101
|
+
});
|
|
102
|
+
const exchange = (async () => {
|
|
103
|
+
const res = await fetch(url, {
|
|
97
104
|
method: "GET",
|
|
98
105
|
headers: { Accept: "application/json", Authorization: `Bearer ${apiKey}` },
|
|
99
106
|
signal: controller == null ? void 0 : controller.signal
|
|
100
107
|
});
|
|
108
|
+
if (!res || !res.ok) return NO_ANSWER;
|
|
109
|
+
return await res.json();
|
|
110
|
+
})();
|
|
111
|
+
try {
|
|
112
|
+
return await Promise.race([exchange, expired]);
|
|
101
113
|
} finally {
|
|
102
114
|
clearTimeout(timer);
|
|
115
|
+
void exchange.catch(() => {
|
|
116
|
+
});
|
|
103
117
|
}
|
|
104
118
|
};
|
|
105
119
|
var fetchWireFeatures = async (config) => {
|
|
@@ -109,9 +123,8 @@ var fetchWireFeatures = async (config) => {
|
|
|
109
123
|
const url = `${config.serverUrl.replace(/\/$/, "")}/v1/features`;
|
|
110
124
|
const timeoutMs = config.timeoutMs && config.timeoutMs > 0 ? config.timeoutMs : DEFAULT_TIMEOUT_MS;
|
|
111
125
|
try {
|
|
112
|
-
const
|
|
113
|
-
if (
|
|
114
|
-
const json = await res.json();
|
|
126
|
+
const json = await fetchFeaturesJson(url, config.apiKey, timeoutMs);
|
|
127
|
+
if (json === NO_ANSWER) return failOpen(storage, key);
|
|
115
128
|
const features = parseWireFeatures(json);
|
|
116
129
|
if (storage) writeCachedFeatures(storage, key, features);
|
|
117
130
|
return features;
|
|
@@ -127,39 +140,51 @@ var useStableValue = (value, isEqual) => {
|
|
|
127
140
|
return ref.current;
|
|
128
141
|
};
|
|
129
142
|
var sameFetchKey = (a, b) => (a == null ? void 0 : a.serverUrl) === (b == null ? void 0 : b.serverUrl) && (a == null ? void 0 : a.apiKey) === (b == null ? void 0 : b.apiKey) && (a == null ? void 0 : a.appId) === (b == null ? void 0 : b.appId);
|
|
130
|
-
var
|
|
143
|
+
var useWireFeaturesState = (config) => {
|
|
131
144
|
const stableConfig = useStableValue(config, sameFetchKey);
|
|
132
145
|
const [flags, setFlags] = useState(defaultWireFeatures);
|
|
133
146
|
const canFetch = !!(stableConfig == null ? void 0 : stableConfig.serverUrl) && !!(stableConfig == null ? void 0 : stableConfig.apiKey);
|
|
147
|
+
const [settled, setSettled] = useState(!canFetch);
|
|
134
148
|
useEffect(() => {
|
|
135
149
|
if (!canFetch) {
|
|
136
150
|
setFlags((prev) => featuresEqual(prev, defaultWireFeatures) ? prev : defaultWireFeatures);
|
|
151
|
+
setSettled(true);
|
|
137
152
|
return;
|
|
138
153
|
}
|
|
139
154
|
let alive = true;
|
|
140
155
|
void fetchWireFeatures(stableConfig).then((next) => {
|
|
141
156
|
if (!alive) return;
|
|
142
157
|
setFlags((prev) => featuresEqual(prev, next) ? prev : next);
|
|
158
|
+
setSettled(true);
|
|
143
159
|
});
|
|
144
160
|
return () => {
|
|
145
161
|
alive = false;
|
|
146
162
|
};
|
|
147
163
|
}, [canFetch, stableConfig]);
|
|
148
|
-
return flags;
|
|
164
|
+
return useMemo(() => ({ flags, settled }), [flags, settled]);
|
|
149
165
|
};
|
|
150
166
|
var CONTEXT_SYMBOL = /* @__PURE__ */ Symbol.for("wireai.features.context");
|
|
151
|
-
var
|
|
152
|
-
if (!
|
|
153
|
-
|
|
167
|
+
var featuresContextGlobal = globalThis;
|
|
168
|
+
if (!featuresContextGlobal[CONTEXT_SYMBOL]) {
|
|
169
|
+
featuresContextGlobal[CONTEXT_SYMBOL] = createContext(null);
|
|
154
170
|
}
|
|
155
|
-
var WireFeaturesContext =
|
|
171
|
+
var WireFeaturesContext = featuresContextGlobal[CONTEXT_SYMBOL];
|
|
172
|
+
var SETTLED_SYMBOL = /* @__PURE__ */ Symbol.for("wireai.features.settled.context");
|
|
173
|
+
var settledContextGlobal = globalThis;
|
|
174
|
+
if (!settledContextGlobal[SETTLED_SYMBOL]) {
|
|
175
|
+
settledContextGlobal[SETTLED_SYMBOL] = createContext(true);
|
|
176
|
+
}
|
|
177
|
+
var WireFeaturesSettledContext = settledContextGlobal[SETTLED_SYMBOL];
|
|
156
178
|
var useWireFeaturesContext = () => useContext(WireFeaturesContext);
|
|
157
|
-
var
|
|
179
|
+
var useResolvedFeaturesState = (options) => {
|
|
158
180
|
var _a, _b, _c;
|
|
159
181
|
const ctx = useWireFeaturesContext();
|
|
182
|
+
const ctxSettled = useContext(WireFeaturesSettledContext);
|
|
160
183
|
const shouldFetch = !(options == null ? void 0 : options.flags) && ctx == null;
|
|
161
|
-
const fetched =
|
|
162
|
-
|
|
184
|
+
const fetched = useWireFeaturesState(shouldFetch ? options == null ? void 0 : options.config : void 0);
|
|
185
|
+
const flags = (_c = (_b = (_a = options == null ? void 0 : options.flags) != null ? _a : ctx) != null ? _b : fetched.flags) != null ? _c : defaultWireFeatures;
|
|
186
|
+
const settled = (options == null ? void 0 : options.flags) ? true : ctx != null ? ctxSettled : fetched.settled;
|
|
187
|
+
return useMemo(() => ({ flags, settled }), [flags, settled]);
|
|
163
188
|
};
|
|
164
189
|
|
|
165
190
|
// src/coachmarks/runtime.ts
|
|
@@ -195,6 +220,17 @@ var setCoachmarksEnabled = (value) => {
|
|
|
195
220
|
notifyCoachmarksEnabled();
|
|
196
221
|
};
|
|
197
222
|
var areCoachmarksEnabled = () => coachmarkRuntime().coachmarksEnabled;
|
|
223
|
+
var setCoachmarksResolved = (value) => {
|
|
224
|
+
var _a;
|
|
225
|
+
const runtime = coachmarkRuntime();
|
|
226
|
+
if (((_a = runtime.coachmarksResolved) != null ? _a : true) === value) return;
|
|
227
|
+
runtime.coachmarksResolved = value;
|
|
228
|
+
notifyCoachmarksEnabled();
|
|
229
|
+
};
|
|
230
|
+
var areCoachmarksResolved = () => {
|
|
231
|
+
var _a;
|
|
232
|
+
return (_a = coachmarkRuntime().coachmarksResolved) != null ? _a : true;
|
|
233
|
+
};
|
|
198
234
|
var subscribeCoachmarksEnabled = (listener) => {
|
|
199
235
|
const listeners2 = enabledListeners();
|
|
200
236
|
listeners2.add(listener);
|
|
@@ -1007,22 +1043,28 @@ var CoachmarkProvider = ({
|
|
|
1007
1043
|
featuresConfig,
|
|
1008
1044
|
children
|
|
1009
1045
|
}) => {
|
|
1010
|
-
const
|
|
1011
|
-
|
|
1046
|
+
const { flags, settled } = useResolvedFeaturesState({
|
|
1047
|
+
flags: features,
|
|
1048
|
+
config: featuresConfig
|
|
1049
|
+
});
|
|
1050
|
+
const coachmarksOn = settled ? flags.coachmarks.enabled : true;
|
|
1012
1051
|
setCoachmarkStorage(storage);
|
|
1013
1052
|
setCoachmarkTesting(isTestingCoachmark);
|
|
1053
|
+
setCoachmarksResolved(settled);
|
|
1014
1054
|
setCoachmarksEnabled(coachmarksOn);
|
|
1015
1055
|
useEffect(() => {
|
|
1016
1056
|
setCoachmarkStorage(storage);
|
|
1017
1057
|
setCoachmarkTesting(isTestingCoachmark);
|
|
1058
|
+
setCoachmarksResolved(settled);
|
|
1018
1059
|
setCoachmarksEnabled(coachmarksOn);
|
|
1019
1060
|
return () => {
|
|
1020
1061
|
if (getCoachmarkStorage() === storage) {
|
|
1021
1062
|
setCoachmarkStorage(null);
|
|
1022
1063
|
}
|
|
1023
1064
|
setCoachmarksEnabled(true);
|
|
1065
|
+
setCoachmarksResolved(true);
|
|
1024
1066
|
};
|
|
1025
|
-
}, [storage, isTestingCoachmark, coachmarksOn]);
|
|
1067
|
+
}, [storage, isTestingCoachmark, coachmarksOn, settled]);
|
|
1026
1068
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1027
1069
|
children,
|
|
1028
1070
|
/* @__PURE__ */ jsx(
|
|
@@ -1125,6 +1167,11 @@ var useCoachmarkTour = (steps, {
|
|
|
1125
1167
|
areCoachmarksEnabled,
|
|
1126
1168
|
areCoachmarksEnabled
|
|
1127
1169
|
);
|
|
1170
|
+
const coachmarksResolved = useSyncExternalStore(
|
|
1171
|
+
subscribeCoachmarksEnabled,
|
|
1172
|
+
areCoachmarksResolved,
|
|
1173
|
+
areCoachmarksResolved
|
|
1174
|
+
);
|
|
1128
1175
|
const exit = useCallback(
|
|
1129
1176
|
(writeGate) => {
|
|
1130
1177
|
if (finishedRef.current) return;
|
|
@@ -1139,14 +1186,16 @@ var useCoachmarkTour = (steps, {
|
|
|
1139
1186
|
const finish = useCallback(() => exit(true), [exit]);
|
|
1140
1187
|
useEffect(() => {
|
|
1141
1188
|
if (!enabled || startedRef.current) return void 0;
|
|
1189
|
+
if (steps.length === 0) return void 0;
|
|
1142
1190
|
if (!coachmarksOn) return void 0;
|
|
1191
|
+
if (!coachmarksResolved) return void 0;
|
|
1143
1192
|
if (showOnce && hasSeenGate(coachmarkGateKey(tourId))) return void 0;
|
|
1144
1193
|
const timer = setTimeout(() => {
|
|
1145
1194
|
startedRef.current = true;
|
|
1146
1195
|
setActiveIndex(0);
|
|
1147
1196
|
}, startDelayMs);
|
|
1148
1197
|
return () => clearTimeout(timer);
|
|
1149
|
-
}, [enabled, coachmarksOn, startDelayMs, showOnce, tourId]);
|
|
1198
|
+
}, [enabled, coachmarksOn, coachmarksResolved, startDelayMs, showOnce, tourId, steps.length]);
|
|
1150
1199
|
useEffect(() => {
|
|
1151
1200
|
if (activeIndex === null) return void 0;
|
|
1152
1201
|
if (!coachmarksOn) {
|
|
@@ -1157,6 +1206,10 @@ var useCoachmarkTour = (steps, {
|
|
|
1157
1206
|
if (startedRef.current && !finishedRef.current) coachmarkOverlay.hide();
|
|
1158
1207
|
return void 0;
|
|
1159
1208
|
}
|
|
1209
|
+
if (steps.length === 0) {
|
|
1210
|
+
exit(false);
|
|
1211
|
+
return void 0;
|
|
1212
|
+
}
|
|
1160
1213
|
if (activeIndex >= steps.length) {
|
|
1161
1214
|
finish();
|
|
1162
1215
|
return void 0;
|