@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
package/dist/showcase/index.js
CHANGED
|
@@ -534,17 +534,31 @@ var failOpen = async (storage, key) => {
|
|
|
534
534
|
const cached3 = await readCachedFeatures(storage, key);
|
|
535
535
|
return (_a = cached3 == null ? void 0 : cached3.features) != null ? _a : defaultWireFeatures;
|
|
536
536
|
};
|
|
537
|
-
var
|
|
537
|
+
var NO_ANSWER = /* @__PURE__ */ Symbol("wire-features-no-answer");
|
|
538
|
+
var fetchFeaturesJson = async (url, apiKey, timeoutMs) => {
|
|
538
539
|
const controller = typeof AbortController !== "undefined" ? new AbortController() : void 0;
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
540
|
+
let timer;
|
|
541
|
+
const expired = new Promise((resolve) => {
|
|
542
|
+
timer = setTimeout(() => {
|
|
543
|
+
controller == null ? void 0 : controller.abort();
|
|
544
|
+
resolve(NO_ANSWER);
|
|
545
|
+
}, timeoutMs);
|
|
546
|
+
});
|
|
547
|
+
const exchange = (async () => {
|
|
548
|
+
const res = await fetch(url, {
|
|
542
549
|
method: "GET",
|
|
543
550
|
headers: { Accept: "application/json", Authorization: `Bearer ${apiKey}` },
|
|
544
551
|
signal: controller == null ? void 0 : controller.signal
|
|
545
552
|
});
|
|
553
|
+
if (!res || !res.ok) return NO_ANSWER;
|
|
554
|
+
return await res.json();
|
|
555
|
+
})();
|
|
556
|
+
try {
|
|
557
|
+
return await Promise.race([exchange, expired]);
|
|
546
558
|
} finally {
|
|
547
559
|
clearTimeout(timer);
|
|
560
|
+
void exchange.catch(() => {
|
|
561
|
+
});
|
|
548
562
|
}
|
|
549
563
|
};
|
|
550
564
|
var fetchWireFeatures = async (config) => {
|
|
@@ -554,9 +568,8 @@ var fetchWireFeatures = async (config) => {
|
|
|
554
568
|
const url = `${config.serverUrl.replace(/\/$/, "")}/v1/features`;
|
|
555
569
|
const timeoutMs = config.timeoutMs && config.timeoutMs > 0 ? config.timeoutMs : DEFAULT_TIMEOUT_MS;
|
|
556
570
|
try {
|
|
557
|
-
const
|
|
558
|
-
if (
|
|
559
|
-
const json = await res.json();
|
|
571
|
+
const json = await fetchFeaturesJson(url, config.apiKey, timeoutMs);
|
|
572
|
+
if (json === NO_ANSWER) return failOpen(storage, key);
|
|
560
573
|
const features = parseWireFeatures(json);
|
|
561
574
|
if (storage) writeCachedFeatures(storage, key, features);
|
|
562
575
|
return features;
|
|
@@ -572,41 +585,56 @@ var useStableValue = (value, isEqual) => {
|
|
|
572
585
|
return ref.current;
|
|
573
586
|
};
|
|
574
587
|
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);
|
|
575
|
-
var
|
|
588
|
+
var useWireFeaturesState = (config) => {
|
|
576
589
|
const stableConfig = useStableValue(config, sameFetchKey);
|
|
577
590
|
const [flags, setFlags] = React.useState(defaultWireFeatures);
|
|
578
591
|
const canFetch = !!(stableConfig == null ? void 0 : stableConfig.serverUrl) && !!(stableConfig == null ? void 0 : stableConfig.apiKey);
|
|
592
|
+
const [settled, setSettled] = React.useState(!canFetch);
|
|
579
593
|
React.useEffect(() => {
|
|
580
594
|
if (!canFetch) {
|
|
581
595
|
setFlags((prev) => featuresEqual(prev, defaultWireFeatures) ? prev : defaultWireFeatures);
|
|
596
|
+
setSettled(true);
|
|
582
597
|
return;
|
|
583
598
|
}
|
|
584
599
|
let alive = true;
|
|
585
600
|
void fetchWireFeatures(stableConfig).then((next) => {
|
|
586
601
|
if (!alive) return;
|
|
587
602
|
setFlags((prev) => featuresEqual(prev, next) ? prev : next);
|
|
603
|
+
setSettled(true);
|
|
588
604
|
});
|
|
589
605
|
return () => {
|
|
590
606
|
alive = false;
|
|
591
607
|
};
|
|
592
608
|
}, [canFetch, stableConfig]);
|
|
593
|
-
return flags;
|
|
609
|
+
return React.useMemo(() => ({ flags, settled }), [flags, settled]);
|
|
594
610
|
};
|
|
595
611
|
var CONTEXT_SYMBOL = /* @__PURE__ */ Symbol.for("wireai.features.context");
|
|
596
|
-
var
|
|
597
|
-
if (!
|
|
598
|
-
|
|
612
|
+
var featuresContextGlobal = globalThis;
|
|
613
|
+
if (!featuresContextGlobal[CONTEXT_SYMBOL]) {
|
|
614
|
+
featuresContextGlobal[CONTEXT_SYMBOL] = React.createContext(null);
|
|
599
615
|
}
|
|
600
|
-
var WireFeaturesContext =
|
|
616
|
+
var WireFeaturesContext = featuresContextGlobal[CONTEXT_SYMBOL];
|
|
617
|
+
var SETTLED_SYMBOL = /* @__PURE__ */ Symbol.for("wireai.features.settled.context");
|
|
618
|
+
var settledContextGlobal = globalThis;
|
|
619
|
+
if (!settledContextGlobal[SETTLED_SYMBOL]) {
|
|
620
|
+
settledContextGlobal[SETTLED_SYMBOL] = React.createContext(true);
|
|
621
|
+
}
|
|
622
|
+
var WireFeaturesSettledContext = settledContextGlobal[SETTLED_SYMBOL];
|
|
601
623
|
var useWireFeaturesContext = () => React.useContext(WireFeaturesContext);
|
|
602
|
-
var
|
|
624
|
+
var useResolvedFeaturesState = (options) => {
|
|
603
625
|
var _a, _b, _c;
|
|
604
626
|
const ctx = useWireFeaturesContext();
|
|
627
|
+
const ctxSettled = React.useContext(WireFeaturesSettledContext);
|
|
605
628
|
const shouldFetch = !(options == null ? void 0 : options.flags) && ctx == null;
|
|
606
|
-
const fetched =
|
|
607
|
-
|
|
629
|
+
const fetched = useWireFeaturesState(shouldFetch ? options == null ? void 0 : options.config : void 0);
|
|
630
|
+
const flags = (_c = (_b = (_a = options == null ? void 0 : options.flags) != null ? _a : ctx) != null ? _b : fetched.flags) != null ? _c : defaultWireFeatures;
|
|
631
|
+
const settled = (options == null ? void 0 : options.flags) ? true : ctx != null ? ctxSettled : fetched.settled;
|
|
632
|
+
return React.useMemo(() => ({ flags, settled }), [flags, settled]);
|
|
608
633
|
};
|
|
609
634
|
|
|
635
|
+
// src/session/persistedSession.ts
|
|
636
|
+
var READ_TIMEOUT_MS2 = 1500;
|
|
637
|
+
|
|
610
638
|
// src/theme/defaultTheme.ts
|
|
611
639
|
var defaultOnboardingTheme = {
|
|
612
640
|
colors: {
|
|
@@ -766,7 +794,10 @@ var _FeatureShowcase = ({
|
|
|
766
794
|
[active, themeOverride]
|
|
767
795
|
);
|
|
768
796
|
const accent = accentColor != null ? accentColor : t.colors.primary;
|
|
769
|
-
const
|
|
797
|
+
const { flags, settled } = useResolvedFeaturesState({
|
|
798
|
+
flags: features,
|
|
799
|
+
config: featuresConfig
|
|
800
|
+
});
|
|
770
801
|
const disabled = !flags.showcase.enabled;
|
|
771
802
|
const Onboarding = React.useMemo(() => resolveShowcaseOnboarding(), []);
|
|
772
803
|
const gateKey = showcaseGateKey(config.id);
|
|
@@ -775,6 +806,14 @@ var _FeatureShowcase = ({
|
|
|
775
806
|
[gateKey, storage, isTesting]
|
|
776
807
|
);
|
|
777
808
|
const skip = seen || disabled || !Onboarding;
|
|
809
|
+
const flagsCouldMatter = !seen && !!Onboarding;
|
|
810
|
+
const [holdExpired, setHoldExpired] = React.useState(false);
|
|
811
|
+
React.useEffect(() => {
|
|
812
|
+
if (settled || holdExpired || !flagsCouldMatter) return void 0;
|
|
813
|
+
const timer = setTimeout(() => setHoldExpired(true), READ_TIMEOUT_MS2);
|
|
814
|
+
return () => clearTimeout(timer);
|
|
815
|
+
}, [settled, holdExpired, flagsCouldMatter]);
|
|
816
|
+
const holding = flagsCouldMatter && !settled && !holdExpired;
|
|
778
817
|
const doneRef = React.useRef(false);
|
|
779
818
|
const finish = React.useCallback(() => {
|
|
780
819
|
if (doneRef.current) return;
|
|
@@ -783,11 +822,12 @@ var _FeatureShowcase = ({
|
|
|
783
822
|
onDone();
|
|
784
823
|
}, [gateKey, storage, isTesting, onDone]);
|
|
785
824
|
React.useEffect(() => {
|
|
825
|
+
if (holding) return;
|
|
786
826
|
if (skip && !doneRef.current) {
|
|
787
827
|
doneRef.current = true;
|
|
788
828
|
onDone();
|
|
789
829
|
}
|
|
790
|
-
}, [skip, onDone]);
|
|
830
|
+
}, [holding, skip, onDone]);
|
|
791
831
|
const [activeIndex, setActiveIndex] = React.useState(0);
|
|
792
832
|
const steps = React.useMemo(
|
|
793
833
|
() => config.slides.map((slide) => {
|
|
@@ -854,6 +894,7 @@ var _FeatureShowcase = ({
|
|
|
854
894
|
}),
|
|
855
895
|
[t]
|
|
856
896
|
);
|
|
897
|
+
if (holding) return null;
|
|
857
898
|
if (skip || !Onboarding) return null;
|
|
858
899
|
const activeGesture = (_a = config.slides[activeIndex]) == null ? void 0 : _a.gesture;
|
|
859
900
|
const showGesture = !!activeGesture && activeGesture !== "none" && activeGesture !== "tap" && activeGesture !== "double_tap";
|