@guidelytech/react 0.6.2 → 0.7.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/LICENSE +21 -0
- package/README.md +35 -2
- package/dist/index.cjs +170 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +57 -2
- package/dist/index.d.ts +57 -2
- package/dist/index.js +162 -26
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Guidely
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -33,7 +33,40 @@ function HelpMenu() {
|
|
|
33
33
|
| `useGuidelyEvent(event, handler)` | Subscribes for the component lifetime (latest handler is used). |
|
|
34
34
|
| `useChecklistProgress(idOrKey)` | Live `{ completedTaskIds, completedAt, dismissedAt }`. |
|
|
35
35
|
| `useGuideState(idOrKey)` | Live `{ active, completed, stepId, stepIndex, guide }`. |
|
|
36
|
-
| `noopClient` | The no-op client instance. |
|
|
36
|
+
| `noopClient` | The no-op client instance (flag getters return their fallbacks). |
|
|
37
|
+
| `useFlag(key, fallback = false)` | Is the boolean flag on? |
|
|
38
|
+
| `useFeatureValue(key, fallback)` | A flag's value (string, number, JSON); `fallback` when missing or of another type. |
|
|
39
|
+
| `useFlagDetails(key, fallback)` | Value plus `reason`, `ruleId`, `variationId`, `experiment`. |
|
|
40
|
+
| `useFlags()` / `useFlagsReady()` / `useFlagsClient()` | Every flag's value / loaded yet / the flags client (`null` on the server). |
|
|
41
|
+
| `<Feature flag="x" fallback={…}>` (alias `<FeatureFlag>`) | Renders children when the flag is on, else `fallback`. |
|
|
42
|
+
| `<FeatureValue flag="x" value="green" fallback={…}>` | Renders children when the flag's value equals `value`. |
|
|
43
|
+
| `<FlagsProvider sdkKey="pk_…" attributes={…} payload={…}>` | Flags only, without guides or analytics (accepts every flags client option). |
|
|
44
|
+
|
|
45
|
+
## Feature flags
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import { Feature, useFeatureValue, useFlag } from "@guidelytech/react";
|
|
49
|
+
|
|
50
|
+
function Checkout() {
|
|
51
|
+
const newCheckout = useFlag("new-checkout");
|
|
52
|
+
const color = useFeatureValue("checkout-button-color", "blue");
|
|
53
|
+
return (
|
|
54
|
+
<Feature flag="new-dashboard-banner" fallback={<OldBanner />}>
|
|
55
|
+
<NewBanner />
|
|
56
|
+
</Feature>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The hooks read the `GuidelyProvider`'s client (`client.flags`, same public key, identity/page/device
|
|
62
|
+
attributes maintained for you) or a `<FlagsProvider>`. They subscribe with `useSyncExternalStore`
|
|
63
|
+
and re-render only when a value changes. Before the client exists (server rendering, hydration)
|
|
64
|
+
they read the bootstrap payload — `<GuidelyProvider flagsPayload={…} flagAttributes={…}>` or
|
|
65
|
+
`<FlagsProvider payload={…}>` — evaluated with `flagAttributes` plus the `user` prop (`id`, traits,
|
|
66
|
+
`account`), so server HTML and hydration match; without a payload they return fallbacks.
|
|
67
|
+
`GuidelyProvider` also accepts `flags={false}` to turn flags off or `flags={{ … }}` for client options.
|
|
37
68
|
|
|
38
69
|
Types re-exported: `GuidelyClient`, `GuidelyOptions`, `GuidelyEvents`, `GuidelyUser`,
|
|
39
|
-
`ChecklistProgressState`, `PublishedGuide`, `GuideState`, `GuidelyProviderProps
|
|
70
|
+
`ChecklistProgressState`, `PublishedGuide`, `GuideState`, `GuidelyProviderProps`, and from
|
|
71
|
+
`@guidelytech/flags`: `FlagsClient`, `FlagsClientOptions`, `FlagDetails`, `FlagsBootstrap`,
|
|
72
|
+
`FlagsPayload`, `Attributes`, `JsonValue`, `EvaluationResult`.
|
package/dist/index.cjs
CHANGED
|
@@ -21,9 +21,19 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
// src/index.tsx
|
|
22
22
|
var index_exports = {};
|
|
23
23
|
__export(index_exports, {
|
|
24
|
+
Feature: () => Feature,
|
|
25
|
+
FeatureFlag: () => FeatureFlag,
|
|
26
|
+
FeatureValue: () => FeatureValue,
|
|
27
|
+
FlagsProvider: () => FlagsProvider,
|
|
24
28
|
GuidelyProvider: () => GuidelyProvider,
|
|
25
29
|
noopClient: () => noopClient,
|
|
26
30
|
useChecklistProgress: () => useChecklistProgress,
|
|
31
|
+
useFeatureValue: () => useFeatureValue,
|
|
32
|
+
useFlag: () => useFlag,
|
|
33
|
+
useFlagDetails: () => useFlagDetails,
|
|
34
|
+
useFlags: () => useFlags,
|
|
35
|
+
useFlagsClient: () => useFlagsClient,
|
|
36
|
+
useFlagsReady: () => useFlagsReady,
|
|
27
37
|
useGuideState: () => useGuideState,
|
|
28
38
|
useGuidely: () => useGuidely,
|
|
29
39
|
useGuidelyEvent: () => useGuidelyEvent,
|
|
@@ -31,27 +41,133 @@ __export(index_exports, {
|
|
|
31
41
|
useGuidelyReady: () => useGuidelyReady
|
|
32
42
|
});
|
|
33
43
|
module.exports = __toCommonJS(index_exports);
|
|
44
|
+
var import_flags2 = require("@guidelytech/flags");
|
|
34
45
|
var import_sdk_core = require("@guidelytech/sdk-core");
|
|
46
|
+
var import_react2 = require("react");
|
|
47
|
+
|
|
48
|
+
// src/flags.tsx
|
|
49
|
+
var import_flags = require("@guidelytech/flags");
|
|
35
50
|
var import_react = require("react");
|
|
36
51
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
37
|
-
var
|
|
38
|
-
|
|
39
|
-
|
|
52
|
+
var FlagsContext = (0, import_react.createContext)(null);
|
|
53
|
+
var EMPTY = (0, import_flags.createStaticFlags)();
|
|
54
|
+
function useReader() {
|
|
55
|
+
const src = (0, import_react.useContext)(FlagsContext);
|
|
56
|
+
return src?.client ?? src?.bootstrap ?? EMPTY;
|
|
57
|
+
}
|
|
58
|
+
function useFlagsValue(select) {
|
|
59
|
+
const reader = useReader();
|
|
60
|
+
const cache = (0, import_react.useRef)(null);
|
|
61
|
+
const get = () => {
|
|
62
|
+
const value = select(reader);
|
|
63
|
+
const c = cache.current;
|
|
64
|
+
if (c && c.reader === reader && (0, import_flags.jsonEquals)(c.value, value)) return c.value;
|
|
65
|
+
cache.current = { reader, value };
|
|
66
|
+
return value;
|
|
67
|
+
};
|
|
68
|
+
return (0, import_react.useSyncExternalStore)(reader.subscribe, get, get);
|
|
69
|
+
}
|
|
70
|
+
function useFlag(key, fallback = false) {
|
|
71
|
+
return useFlagsValue((r) => r.isEnabled(key, fallback));
|
|
72
|
+
}
|
|
73
|
+
function useFeatureValue(key, fallback) {
|
|
74
|
+
return useFlagsValue((r) => r.getValue(key, fallback));
|
|
75
|
+
}
|
|
76
|
+
function useFlagDetails(key, fallback) {
|
|
77
|
+
return useFlagsValue((r) => r.getDetails(key, fallback));
|
|
78
|
+
}
|
|
79
|
+
function useFlags() {
|
|
80
|
+
return useFlagsValue((r) => r.getAll());
|
|
81
|
+
}
|
|
82
|
+
function useFlagsReady() {
|
|
83
|
+
return useFlagsValue((r) => r.isReady());
|
|
84
|
+
}
|
|
85
|
+
function useFlagsClient() {
|
|
86
|
+
return (0, import_react.useContext)(FlagsContext)?.client ?? null;
|
|
87
|
+
}
|
|
88
|
+
function Feature({ flag, children, fallback = null }) {
|
|
89
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: useFlag(flag) ? children : fallback });
|
|
90
|
+
}
|
|
91
|
+
var FeatureFlag = Feature;
|
|
92
|
+
function FeatureValue({ flag, value, children, fallback = null }) {
|
|
93
|
+
const current = useFeatureValue(flag, null);
|
|
94
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: (0, import_flags.jsonEquals)(current, value) ? children : fallback });
|
|
95
|
+
}
|
|
96
|
+
function useBootstrap(payload, attributes) {
|
|
97
|
+
const key = (0, import_flags.stableStringify)(attributes);
|
|
98
|
+
return (0, import_react.useMemo)(() => payload ? (0, import_flags.createStaticFlags)({ payload, attributes }) : EMPTY, [payload, key]);
|
|
99
|
+
}
|
|
100
|
+
function FlagsProvider({ children, client: external, payload, ...options }) {
|
|
101
|
+
const [created, setCreated] = (0, import_react.useState)(null);
|
|
40
102
|
const optionsRef = (0, import_react.useRef)(options);
|
|
41
103
|
optionsRef.current = options;
|
|
42
|
-
const
|
|
104
|
+
const sdkKey = options.sdkKey ?? options.projectId;
|
|
105
|
+
const { apiUrl, environment } = options;
|
|
106
|
+
const payloadRef = (0, import_react.useRef)(payload);
|
|
107
|
+
payloadRef.current = payload;
|
|
43
108
|
(0, import_react.useEffect)(() => {
|
|
109
|
+
if (external || !sdkKey || typeof window === "undefined") return;
|
|
110
|
+
let c;
|
|
111
|
+
try {
|
|
112
|
+
c = (0, import_flags.createFlagsClient)({ ...optionsRef.current, sdkKey, payload: payloadRef.current ?? void 0 });
|
|
113
|
+
} catch (err) {
|
|
114
|
+
optionsRef.current.onError?.(err instanceof Error ? err : new Error(String(err)));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
setCreated(c);
|
|
118
|
+
return () => {
|
|
119
|
+
c.destroy();
|
|
120
|
+
setCreated((cur) => cur === c ? null : cur);
|
|
121
|
+
};
|
|
122
|
+
}, [external, sdkKey, apiUrl, environment]);
|
|
123
|
+
const client = external ?? created;
|
|
124
|
+
const attributes = options.attributes ?? {};
|
|
125
|
+
const attrsKey = (0, import_flags.stableStringify)(attributes);
|
|
126
|
+
(0, import_react.useEffect)(() => {
|
|
127
|
+
if (client && options.attributes) client.setAttributes(options.attributes);
|
|
128
|
+
}, [client, attrsKey]);
|
|
129
|
+
const bootstrap = useBootstrap(payload, attributes);
|
|
130
|
+
const value = (0, import_react.useMemo)(() => ({ client, bootstrap }), [client, bootstrap]);
|
|
131
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FlagsContext.Provider, { value, children });
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// src/index.tsx
|
|
135
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
136
|
+
var GuidelyContext = (0, import_react2.createContext)(null);
|
|
137
|
+
function userAttributes(user) {
|
|
138
|
+
if (!user?.id) return {};
|
|
139
|
+
return { ...user.traits ?? {}, id: user.id, ...user.account ? { account: { ...user.account.traits ?? {}, id: user.account.id } } : {} };
|
|
140
|
+
}
|
|
141
|
+
function GuidelyProvider({ children, user, flagsPayload, flagAttributes, ...options }) {
|
|
142
|
+
const [client, setClient] = (0, import_react2.useState)(null);
|
|
143
|
+
const optionsRef = (0, import_react2.useRef)(options);
|
|
144
|
+
optionsRef.current = options;
|
|
145
|
+
const userRef = (0, import_react2.useRef)(user);
|
|
146
|
+
userRef.current = user;
|
|
147
|
+
const flagsOpts = options.flags === false ? null : options.flags ?? {};
|
|
148
|
+
const payload = flagsPayload ?? flagsOpts?.payload ?? null;
|
|
149
|
+
const payloadRef = (0, import_react2.useRef)(payload);
|
|
150
|
+
payloadRef.current = payload;
|
|
151
|
+
const appAttributes = (0, import_react2.useMemo)(() => ({ ...flagsOpts?.attributes ?? {}, ...flagAttributes ?? {} }), [(0, import_flags2.stableStringify)(flagsOpts?.attributes ?? {}), (0, import_flags2.stableStringify)(flagAttributes ?? {})]);
|
|
152
|
+
const appAttributesRef = (0, import_react2.useRef)(appAttributes);
|
|
153
|
+
appAttributesRef.current = appAttributes;
|
|
154
|
+
const { projectId, environment, apiUrl } = options;
|
|
155
|
+
(0, import_react2.useEffect)(() => {
|
|
44
156
|
if (typeof window === "undefined" || !projectId) return;
|
|
45
|
-
const
|
|
157
|
+
const o = optionsRef.current;
|
|
158
|
+
const c = (0, import_sdk_core.createGuidely)({ ...o, projectId, environment, apiUrl, user: userRef.current?.id ? userRef.current : void 0, flags: o.flags === false ? false : { ...o.flags ?? {}, payload: payloadRef.current ?? void 0, attributes: appAttributesRef.current } });
|
|
46
159
|
setClient(c);
|
|
47
160
|
return () => {
|
|
48
161
|
c.destroy();
|
|
49
162
|
setClient((cur) => cur === c ? null : cur);
|
|
50
163
|
};
|
|
51
164
|
}, [projectId, environment, apiUrl]);
|
|
165
|
+
(0, import_react2.useEffect)(() => {
|
|
166
|
+
client?.flags.setAttributes(appAttributes);
|
|
167
|
+
}, [client, appAttributes]);
|
|
52
168
|
const userKey = user ? JSON.stringify([user.id, user.traits ?? null, user.account ?? null]) : "";
|
|
53
|
-
const hadUser = (0,
|
|
54
|
-
(0,
|
|
169
|
+
const hadUser = (0, import_react2.useRef)(false);
|
|
170
|
+
(0, import_react2.useEffect)(() => {
|
|
55
171
|
if (!client) return;
|
|
56
172
|
if (user && user.id) {
|
|
57
173
|
hadUser.current = true;
|
|
@@ -61,7 +177,9 @@ function GuidelyProvider({ children, user, ...options }) {
|
|
|
61
177
|
client.reset();
|
|
62
178
|
}
|
|
63
179
|
}, [client, userKey]);
|
|
64
|
-
|
|
180
|
+
const bootstrap = useBootstrap(payload, { ...userAttributes(user), ...appAttributes });
|
|
181
|
+
const flags = (0, import_react2.useMemo)(() => ({ client: client?.flags ?? null, bootstrap }), [client, bootstrap]);
|
|
182
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GuidelyContext.Provider, { value: client, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(FlagsContext.Provider, { value: flags, children }) });
|
|
65
183
|
}
|
|
66
184
|
var NOOP_RESULTS = {
|
|
67
185
|
init: Promise.resolve(),
|
|
@@ -82,20 +200,38 @@ var NOOP_RESULTS = {
|
|
|
82
200
|
getSessionId: "",
|
|
83
201
|
isRecording: false
|
|
84
202
|
};
|
|
203
|
+
var noopFlags = new Proxy((0, import_flags2.createStaticFlags)(), {
|
|
204
|
+
get(target, prop, receiver) {
|
|
205
|
+
if (prop in target) return Reflect.get(target, prop, receiver);
|
|
206
|
+
if (prop === "ready" || prop === "refresh" || prop === "flush") return () => Promise.resolve();
|
|
207
|
+
if (prop === "getPayload") return () => null;
|
|
208
|
+
if (prop === "forUser") return () => target;
|
|
209
|
+
return typeof prop === "string" ? () => void 0 : void 0;
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
var missing = (key, fallback) => ({ key, value: fallback, reason: "FLAG_NOT_FOUND", inExperiment: false, usedFallback: true });
|
|
213
|
+
var NOOP_FUNCTIONS = {
|
|
214
|
+
isFeatureEnabled: (_key, fallback = false) => fallback,
|
|
215
|
+
getFeatureValue: (_key, fallback) => fallback,
|
|
216
|
+
getFeatureDetails: (key, fallback) => missing(key, fallback),
|
|
217
|
+
onFlagsChange: () => () => {
|
|
218
|
+
}
|
|
219
|
+
};
|
|
85
220
|
var noopClient = new Proxy({}, {
|
|
86
221
|
get(_target, prop) {
|
|
87
222
|
if (prop === "options") return { projectId: "" };
|
|
223
|
+
if (prop === "flags") return noopFlags;
|
|
88
224
|
if (typeof prop !== "string") return void 0;
|
|
89
|
-
return () => NOOP_RESULTS[prop];
|
|
225
|
+
return NOOP_FUNCTIONS[prop] ?? (() => NOOP_RESULTS[prop]);
|
|
90
226
|
}
|
|
91
227
|
});
|
|
92
228
|
function useGuidely() {
|
|
93
|
-
return (0,
|
|
229
|
+
return (0, import_react2.useContext)(GuidelyContext) ?? noopClient;
|
|
94
230
|
}
|
|
95
231
|
function useGuidelyReady() {
|
|
96
|
-
const client = (0,
|
|
97
|
-
const [ready, setReady] = (0,
|
|
98
|
-
(0,
|
|
232
|
+
const client = (0, import_react2.useContext)(GuidelyContext);
|
|
233
|
+
const [ready, setReady] = (0, import_react2.useState)(false);
|
|
234
|
+
(0, import_react2.useEffect)(() => {
|
|
99
235
|
if (!client) {
|
|
100
236
|
setReady(false);
|
|
101
237
|
return;
|
|
@@ -106,27 +242,27 @@ function useGuidelyReady() {
|
|
|
106
242
|
return ready;
|
|
107
243
|
}
|
|
108
244
|
function useGuidelyIdentify(userId, traits, account) {
|
|
109
|
-
const client = (0,
|
|
245
|
+
const client = (0, import_react2.useContext)(GuidelyContext);
|
|
110
246
|
const key = JSON.stringify([userId ?? null, traits ?? null, account ?? null]);
|
|
111
|
-
(0,
|
|
247
|
+
(0, import_react2.useEffect)(() => {
|
|
112
248
|
if (!client || !userId) return;
|
|
113
249
|
void client.identify(userId, traits, account);
|
|
114
250
|
}, [client, key]);
|
|
115
251
|
}
|
|
116
252
|
function useGuidelyEvent(event, handler) {
|
|
117
|
-
const client = (0,
|
|
118
|
-
const ref = (0,
|
|
253
|
+
const client = (0, import_react2.useContext)(GuidelyContext);
|
|
254
|
+
const ref = (0, import_react2.useRef)(handler);
|
|
119
255
|
ref.current = handler;
|
|
120
|
-
(0,
|
|
256
|
+
(0, import_react2.useEffect)(() => {
|
|
121
257
|
if (!client) return;
|
|
122
258
|
const cb = ((...args) => ref.current(...args));
|
|
123
259
|
return client.on(event, cb);
|
|
124
260
|
}, [client, event]);
|
|
125
261
|
}
|
|
126
262
|
function useChecklistProgress(idOrKey) {
|
|
127
|
-
const client = (0,
|
|
128
|
-
const [progress, setProgress] = (0,
|
|
129
|
-
(0,
|
|
263
|
+
const client = (0, import_react2.useContext)(GuidelyContext);
|
|
264
|
+
const [progress, setProgress] = (0, import_react2.useState)({ completedTaskIds: [], completedAt: null, dismissedAt: null });
|
|
265
|
+
(0, import_react2.useEffect)(() => {
|
|
130
266
|
if (!client) return;
|
|
131
267
|
const update = () => setProgress(client.getChecklistProgress(idOrKey));
|
|
132
268
|
update();
|
|
@@ -136,9 +272,9 @@ function useChecklistProgress(idOrKey) {
|
|
|
136
272
|
return progress;
|
|
137
273
|
}
|
|
138
274
|
function useGuideState(idOrKey) {
|
|
139
|
-
const client = (0,
|
|
140
|
-
const [state, setState] = (0,
|
|
141
|
-
(0,
|
|
275
|
+
const client = (0, import_react2.useContext)(GuidelyContext);
|
|
276
|
+
const [state, setState] = (0, import_react2.useState)({ active: false, completed: false, stepId: null, stepIndex: -1, guide: null });
|
|
277
|
+
(0, import_react2.useEffect)(() => {
|
|
142
278
|
if (!client) return;
|
|
143
279
|
const matches = (g) => g.id === idOrKey || g.key === idOrKey;
|
|
144
280
|
const compute = () => {
|
|
@@ -155,9 +291,19 @@ function useGuideState(idOrKey) {
|
|
|
155
291
|
}
|
|
156
292
|
// Annotate the CommonJS export names for ESM import in node:
|
|
157
293
|
0 && (module.exports = {
|
|
294
|
+
Feature,
|
|
295
|
+
FeatureFlag,
|
|
296
|
+
FeatureValue,
|
|
297
|
+
FlagsProvider,
|
|
158
298
|
GuidelyProvider,
|
|
159
299
|
noopClient,
|
|
160
300
|
useChecklistProgress,
|
|
301
|
+
useFeatureValue,
|
|
302
|
+
useFlag,
|
|
303
|
+
useFlagDetails,
|
|
304
|
+
useFlags,
|
|
305
|
+
useFlagsClient,
|
|
306
|
+
useFlagsReady,
|
|
161
307
|
useGuideState,
|
|
162
308
|
useGuidely,
|
|
163
309
|
useGuidelyEvent,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.tsx"],"sourcesContent":["import { createGuidely, type ChecklistProgressState, type GuidelyClient, type GuidelyEvents, type GuidelyOptions, type GuidelyUser, type PublishedGuide } from \"@guidelytech/sdk-core\";\nimport { createContext, useContext, useEffect, useRef, useState, type ReactNode } from \"react\";\n\nexport type { GuidelyClient, GuidelyOptions, GuidelyEvents, GuidelyUser, ChecklistProgressState, PublishedGuide } from \"@guidelytech/sdk-core\";\n\nconst GuidelyContext = createContext<GuidelyClient | null>(null);\n\nexport interface GuidelyProviderProps extends Omit<GuidelyOptions, \"user\"> {\n /** Identify this user as soon as the client is ready; `undefined` resets the identity. */\n user?: GuidelyUser | null;\n children?: ReactNode;\n}\n\n/**\n * Creates one Guidely client for the subtree. The client is created inside an effect (never\n * during SSR) and destroyed on unmount, so React Strict Mode's double-invoke is harmless.\n */\nexport function GuidelyProvider({ children, user, ...options }: GuidelyProviderProps) {\n const [client, setClient] = useState<GuidelyClient | null>(null);\n const optionsRef = useRef(options);\n optionsRef.current = options;\n const { projectId, environment, apiUrl } = options;\n\n useEffect(() => {\n if (typeof window === \"undefined\" || !projectId) return;\n const c = createGuidely({ ...optionsRef.current, projectId, environment, apiUrl });\n setClient(c);\n return () => {\n c.destroy();\n setClient((cur) => (cur === c ? null : cur));\n };\n }, [projectId, environment, apiUrl]);\n\n const userKey = user ? JSON.stringify([user.id, user.traits ?? null, user.account ?? null]) : \"\";\n const hadUser = useRef(false);\n useEffect(() => {\n if (!client) return;\n if (user && user.id) {\n hadUser.current = true;\n void client.identify(user.id, user.traits, user.account);\n } else if (hadUser.current) {\n hadUser.current = false;\n client.reset();\n }\n }, [client, userKey]);\n\n return <GuidelyContext.Provider value={client}>{children}</GuidelyContext.Provider>;\n}\n\nconst NOOP_RESULTS: Record<string, unknown> = {\n init: Promise.resolve(),\n ready: Promise.resolve(),\n identify: Promise.resolve(),\n setAccount: Promise.resolve(),\n updateTraits: Promise.resolve(),\n refresh: Promise.resolve(),\n startGuide: false,\n getActiveGuide: null,\n getGuides: [],\n getChecklistProgress: { completedTaskIds: [], completedAt: null, dismissedAt: null },\n isGuideCompleted: false,\n on: () => {},\n getState: { ready: false, destroyed: false },\n getContext: null,\n getSessionId: \"\",\n isRecording: false,\n};\n\n/** A client that ignores every call; returned by `useGuidely()` on the server and before the provider mounts. */\nexport const noopClient: GuidelyClient = new Proxy({} as GuidelyClient, {\n get(_target, prop) {\n if (prop === \"options\") return { projectId: \"\" };\n if (typeof prop !== \"string\") return undefined;\n return () => NOOP_RESULTS[prop];\n },\n});\n\n/** The Guidely client, or a no-op client during SSR / before the provider has mounted. */\nexport function useGuidely(): GuidelyClient {\n return useContext(GuidelyContext) ?? noopClient;\n}\n\n/** True once the client has loaded its configuration. */\nexport function useGuidelyReady(): boolean {\n const client = useContext(GuidelyContext);\n const [ready, setReady] = useState(false);\n useEffect(() => {\n if (!client) {\n setReady(false);\n return;\n }\n if (client.getState().ready) setReady(true);\n return client.on(\"ready\", () => setReady(true));\n }, [client]);\n return ready;\n}\n\n/** Identifies the user whenever the arguments change. */\nexport function useGuidelyIdentify(userId: string | null | undefined, traits?: Record<string, unknown>, account?: GuidelyUser[\"account\"]): void {\n const client = useContext(GuidelyContext);\n const key = JSON.stringify([userId ?? null, traits ?? null, account ?? null]);\n useEffect(() => {\n if (!client || !userId) return;\n void client.identify(userId, traits, account);\n }, [client, key]);\n}\n\n/** Subscribes to a client event for the lifetime of the component. */\nexport function useGuidelyEvent<K extends keyof GuidelyEvents>(event: K, handler: GuidelyEvents[K]): void {\n const client = useContext(GuidelyContext);\n const ref = useRef(handler);\n ref.current = handler;\n useEffect(() => {\n if (!client) return;\n const cb = ((...args: unknown[]) => (ref.current as (...a: unknown[]) => void)(...args)) as GuidelyEvents[K];\n return client.on(event, cb);\n }, [client, event]);\n}\n\n/** Live checklist progress for a checklist guide (by id or key). */\nexport function useChecklistProgress(idOrKey: string): ChecklistProgressState {\n const client = useContext(GuidelyContext);\n const [progress, setProgress] = useState<ChecklistProgressState>({ completedTaskIds: [], completedAt: null, dismissedAt: null });\n useEffect(() => {\n if (!client) return;\n const update = () => setProgress(client.getChecklistProgress(idOrKey));\n update();\n const offs = [client.on(\"ready\", update), client.on(\"identify\", update), client.on(\"checklist:task\", update), client.on(\"checklist:complete\", update)];\n return () => offs.forEach((off) => off());\n }, [client, idOrKey]);\n return progress;\n}\n\nexport interface GuideState {\n /** The guide is currently showing. */\n active: boolean;\n completed: boolean;\n stepId: string | null;\n stepIndex: number;\n guide: PublishedGuide | null;\n}\n\n/** Live state of a guide (by id or key): active, completed, current step. */\nexport function useGuideState(idOrKey: string): GuideState {\n const client = useContext(GuidelyContext);\n const [state, setState] = useState<GuideState>({ active: false, completed: false, stepId: null, stepIndex: -1, guide: null });\n useEffect(() => {\n if (!client) return;\n const matches = (g: PublishedGuide) => g.id === idOrKey || g.key === idOrKey;\n const compute = () => {\n const guide = client.getGuides().find(matches) ?? null;\n const active = client.getActiveGuide();\n const s = client.getState().activeGuide;\n setState({ active: !!active && matches(active), completed: client.isGuideCompleted(idOrKey), stepId: active && matches(active) ? ((s as { stepId?: string | null } | null)?.stepId ?? null) : null, stepIndex: active && matches(active) ? ((s as { stepIndex?: number } | null)?.stepIndex ?? -1) : -1, guide });\n };\n compute();\n const offs = ([\"ready\", \"identify\", \"guide:start\", \"guide:step\", \"guide:complete\", \"guide:dismiss\", \"guide:skip\"] as const).map((e) => client.on(e, compute));\n return () => offs.forEach((off) => off());\n }, [client, idOrKey]);\n return state;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx","../src/flags.tsx"],"sourcesContent":["import { createStaticFlags, stableStringify, type Attributes, type FlagDetails, type FlagsBootstrap, type FlagsClient } from \"@guidelytech/flags\";\nimport { createGuidely, type ChecklistProgressState, type GuidelyClient, type GuidelyEvents, type GuidelyOptions, type GuidelyUser, type PublishedGuide } from \"@guidelytech/sdk-core\";\nimport { createContext, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport { FlagsContext, useBootstrap, type FlagsSource } from \"./flags\";\n\nexport type { GuidelyClient, GuidelyOptions, GuidelyEvents, GuidelyUser, ChecklistProgressState, PublishedGuide } from \"@guidelytech/sdk-core\";\nexport { useFlag, useFeatureValue, useFlagDetails, useFlags, useFlagsReady, useFlagsClient, Feature, FeatureFlag, FeatureValue, FlagsProvider } from \"./flags\";\nexport type { FeatureProps, FeatureValueProps, FlagsProviderProps } from \"./flags\";\nexport type { FlagsClient, FlagsClientOptions, FlagDetails, FlagsBootstrap, FlagsPayload, Attributes, JsonValue, EvaluationResult } from \"@guidelytech/flags\";\n\nconst GuidelyContext = createContext<GuidelyClient | null>(null);\n\nexport interface GuidelyProviderProps extends Omit<GuidelyOptions, \"user\"> {\n /** Identify this user as soon as the client is ready; `undefined` resets the identity. */\n user?: GuidelyUser | null;\n /**\n * Flags bootstrap from the server (`getFlagsBootstrap()` / `client.getPayload()`): flag hooks\n * render the same values on the server, during hydration and after.\n */\n flagsPayload?: FlagsBootstrap | null;\n /** Extra flag attributes (merged over the automatic identity, page and device attributes). */\n flagAttributes?: Attributes;\n children?: ReactNode;\n}\n\n/** The attributes the server knows about a user: what bootstrap snapshots evaluate with. */\nfunction userAttributes(user: GuidelyUser | null | undefined): Attributes {\n if (!user?.id) return {};\n return { ...(user.traits ?? {}), id: user.id, ...(user.account ? { account: { ...(user.account.traits ?? {}), id: user.account.id } } : {}) };\n}\n\n/**\n * Creates one Guidely client for the subtree. The client is created inside an effect (never\n * during SSR) and destroyed on unmount, so React Strict Mode's double-invoke is harmless.\n */\nexport function GuidelyProvider({ children, user, flagsPayload, flagAttributes, ...options }: GuidelyProviderProps) {\n const [client, setClient] = useState<GuidelyClient | null>(null);\n const optionsRef = useRef(options);\n optionsRef.current = options;\n const userRef = useRef(user);\n userRef.current = user;\n const flagsOpts = options.flags === false ? null : (options.flags ?? {});\n const payload = flagsPayload ?? flagsOpts?.payload ?? null;\n const payloadRef = useRef(payload);\n payloadRef.current = payload;\n const appAttributes = useMemo(() => ({ ...(flagsOpts?.attributes ?? {}), ...(flagAttributes ?? {}) }), [stableStringify(flagsOpts?.attributes ?? {}), stableStringify(flagAttributes ?? {})]);\n const appAttributesRef = useRef(appAttributes);\n appAttributesRef.current = appAttributes;\n const { projectId, environment, apiUrl } = options;\n\n useEffect(() => {\n if (typeof window === \"undefined\" || !projectId) return;\n const o = optionsRef.current;\n // The user is known up front so flags evaluate for them from the first render (no flicker).\n const c = createGuidely({ ...o, projectId, environment, apiUrl, user: userRef.current?.id ? userRef.current : undefined, flags: o.flags === false ? false : { ...(o.flags ?? {}), payload: payloadRef.current ?? undefined, attributes: appAttributesRef.current } });\n setClient(c);\n return () => {\n c.destroy();\n setClient((cur) => (cur === c ? null : cur));\n };\n }, [projectId, environment, apiUrl]);\n\n useEffect(() => {\n client?.flags.setAttributes(appAttributes);\n }, [client, appAttributes]);\n\n const userKey = user ? JSON.stringify([user.id, user.traits ?? null, user.account ?? null]) : \"\";\n const hadUser = useRef(false);\n useEffect(() => {\n if (!client) return;\n if (user && user.id) {\n hadUser.current = true;\n void client.identify(user.id, user.traits, user.account);\n } else if (hadUser.current) {\n hadUser.current = false;\n client.reset();\n }\n }, [client, userKey]);\n\n const bootstrap = useBootstrap(payload, { ...userAttributes(user), ...appAttributes });\n const flags = useMemo<FlagsSource>(() => ({ client: client?.flags ?? null, bootstrap }), [client, bootstrap]);\n return (\n <GuidelyContext.Provider value={client}>\n <FlagsContext.Provider value={flags}>{children}</FlagsContext.Provider>\n </GuidelyContext.Provider>\n );\n}\n\nconst NOOP_RESULTS: Record<string, unknown> = {\n init: Promise.resolve(),\n ready: Promise.resolve(),\n identify: Promise.resolve(),\n setAccount: Promise.resolve(),\n updateTraits: Promise.resolve(),\n refresh: Promise.resolve(),\n startGuide: false,\n getActiveGuide: null,\n getGuides: [],\n getChecklistProgress: { completedTaskIds: [], completedAt: null, dismissedAt: null },\n isGuideCompleted: false,\n on: () => {},\n getState: { ready: false, destroyed: false },\n getContext: null,\n getSessionId: \"\",\n isRecording: false,\n};\n\n/** Flags that serve every fallback; `useGuidely().flags` before the provider has a client. */\nconst noopFlags = new Proxy(createStaticFlags() as unknown as FlagsClient, {\n get(target, prop, receiver) {\n if (prop in target) return Reflect.get(target, prop, receiver);\n if (prop === \"ready\" || prop === \"refresh\" || prop === \"flush\") return () => Promise.resolve();\n if (prop === \"getPayload\") return () => null;\n if (prop === \"forUser\") return () => target;\n return typeof prop === \"string\" ? () => undefined : undefined;\n },\n});\n\nconst missing = <T,>(key: string, fallback: T): FlagDetails<T> => ({ key, value: fallback, reason: \"FLAG_NOT_FOUND\", inExperiment: false, usedFallback: true });\n\n/** Methods whose no-op answer depends on the arguments (flag getters return the fallback). */\nconst NOOP_FUNCTIONS: Record<string, (...args: any[]) => unknown> = {\n isFeatureEnabled: (_key: string, fallback = false) => fallback,\n getFeatureValue: (_key: string, fallback: unknown) => fallback,\n getFeatureDetails: (key: string, fallback: unknown) => missing(key, fallback),\n onFlagsChange: () => () => {},\n};\n\n/** A client that ignores every call; returned by `useGuidely()` on the server and before the provider mounts. */\nexport const noopClient: GuidelyClient = new Proxy({} as GuidelyClient, {\n get(_target, prop) {\n if (prop === \"options\") return { projectId: \"\" };\n if (prop === \"flags\") return noopFlags;\n if (typeof prop !== \"string\") return undefined;\n return NOOP_FUNCTIONS[prop] ?? (() => NOOP_RESULTS[prop]);\n },\n});\n\n/** The Guidely client, or a no-op client during SSR / before the provider has mounted. */\nexport function useGuidely(): GuidelyClient {\n return useContext(GuidelyContext) ?? noopClient;\n}\n\n/** True once the client has loaded its configuration. */\nexport function useGuidelyReady(): boolean {\n const client = useContext(GuidelyContext);\n const [ready, setReady] = useState(false);\n useEffect(() => {\n if (!client) {\n setReady(false);\n return;\n }\n if (client.getState().ready) setReady(true);\n return client.on(\"ready\", () => setReady(true));\n }, [client]);\n return ready;\n}\n\n/** Identifies the user whenever the arguments change. */\nexport function useGuidelyIdentify(userId: string | null | undefined, traits?: Record<string, unknown>, account?: GuidelyUser[\"account\"]): void {\n const client = useContext(GuidelyContext);\n const key = JSON.stringify([userId ?? null, traits ?? null, account ?? null]);\n useEffect(() => {\n if (!client || !userId) return;\n void client.identify(userId, traits, account);\n }, [client, key]);\n}\n\n/** Subscribes to a client event for the lifetime of the component. */\nexport function useGuidelyEvent<K extends keyof GuidelyEvents>(event: K, handler: GuidelyEvents[K]): void {\n const client = useContext(GuidelyContext);\n const ref = useRef(handler);\n ref.current = handler;\n useEffect(() => {\n if (!client) return;\n const cb = ((...args: unknown[]) => (ref.current as (...a: unknown[]) => void)(...args)) as GuidelyEvents[K];\n return client.on(event, cb);\n }, [client, event]);\n}\n\n/** Live checklist progress for a checklist guide (by id or key). */\nexport function useChecklistProgress(idOrKey: string): ChecklistProgressState {\n const client = useContext(GuidelyContext);\n const [progress, setProgress] = useState<ChecklistProgressState>({ completedTaskIds: [], completedAt: null, dismissedAt: null });\n useEffect(() => {\n if (!client) return;\n const update = () => setProgress(client.getChecklistProgress(idOrKey));\n update();\n const offs = [client.on(\"ready\", update), client.on(\"identify\", update), client.on(\"checklist:task\", update), client.on(\"checklist:complete\", update)];\n return () => offs.forEach((off) => off());\n }, [client, idOrKey]);\n return progress;\n}\n\nexport interface GuideState {\n /** The guide is currently showing. */\n active: boolean;\n completed: boolean;\n stepId: string | null;\n stepIndex: number;\n guide: PublishedGuide | null;\n}\n\n/** Live state of a guide (by id or key): active, completed, current step. */\nexport function useGuideState(idOrKey: string): GuideState {\n const client = useContext(GuidelyContext);\n const [state, setState] = useState<GuideState>({ active: false, completed: false, stepId: null, stepIndex: -1, guide: null });\n useEffect(() => {\n if (!client) return;\n const matches = (g: PublishedGuide) => g.id === idOrKey || g.key === idOrKey;\n const compute = () => {\n const guide = client.getGuides().find(matches) ?? null;\n const active = client.getActiveGuide();\n const s = client.getState().activeGuide;\n setState({ active: !!active && matches(active), completed: client.isGuideCompleted(idOrKey), stepId: active && matches(active) ? ((s as { stepId?: string | null } | null)?.stepId ?? null) : null, stepIndex: active && matches(active) ? ((s as { stepIndex?: number } | null)?.stepIndex ?? -1) : -1, guide });\n };\n compute();\n const offs = ([\"ready\", \"identify\", \"guide:start\", \"guide:step\", \"guide:complete\", \"guide:dismiss\", \"guide:skip\"] as const).map((e) => client.on(e, compute));\n return () => offs.forEach((off) => off());\n }, [client, idOrKey]);\n return state;\n}\n","import { createFlagsClient, createStaticFlags, jsonEquals, stableStringify, type Attributes, type FlagDetails, type FlagValue, type FlagsBootstrap, type FlagsClient, type FlagsClientOptions, type FlagsReader, type JsonValue } from \"@guidelytech/flags\";\nimport { createContext, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore, type ReactNode } from \"react\";\n\n/** What the flag hooks read: the live client once created, else a static snapshot of the bootstrap payload. */\nexport interface FlagsSource {\n client: FlagsClient | null;\n bootstrap: FlagsReader;\n}\n\nexport const FlagsContext = createContext<FlagsSource | null>(null);\n\nconst EMPTY = createStaticFlags();\n\nfunction useReader(): FlagsReader {\n const src = useContext(FlagsContext);\n return src?.client ?? src?.bootstrap ?? EMPTY;\n}\n\n/**\n * Subscribes to the flags with `useSyncExternalStore`. Values are compared deeply so object\n * flags keep their identity between renders. The server snapshot is the bootstrap payload, so\n * server-rendered HTML and hydration agree.\n */\nfunction useFlagsValue<T>(select: (reader: FlagsReader) => T): T {\n const reader = useReader();\n const cache = useRef<{ reader: FlagsReader; value: T } | null>(null);\n const get = () => {\n const value = select(reader);\n const c = cache.current;\n if (c && c.reader === reader && jsonEquals(c.value, value)) return c.value;\n cache.current = { reader, value };\n return value;\n };\n return useSyncExternalStore(reader.subscribe, get, get);\n}\n\n/** Is the boolean flag on? `fallback` (default `false`) until flags load, or when missing. */\nexport function useFlag(key: string, fallback = false): boolean {\n return useFlagsValue((r) => r.isEnabled(key, fallback));\n}\n\n/** A flag's value (string, number, JSON…); `fallback` when missing or of a different type. */\nexport function useFeatureValue<T extends JsonValue>(key: string, fallback: T): FlagValue<T> {\n return useFlagsValue((r) => r.getValue(key, fallback));\n}\n\n/** A flag's value plus why it was served (reason, rule, variation, experiment). */\nexport function useFlagDetails<T extends JsonValue>(key: string, fallback: T): FlagDetails<FlagValue<T>> {\n return useFlagsValue((r) => r.getDetails(key, fallback));\n}\n\n/** Every flag's value (records no exposures). */\nexport function useFlags(): Record<string, JsonValue> {\n return useFlagsValue((r) => r.getAll());\n}\n\n/** True once flags have loaded (or failed to and serve fallbacks); true from the start with a bootstrap payload. */\nexport function useFlagsReady(): boolean {\n return useFlagsValue((r) => r.isReady());\n}\n\n/** The flags client (`null` on the server and before the provider has created it). */\nexport function useFlagsClient(): FlagsClient | null {\n return useContext(FlagsContext)?.client ?? null;\n}\n\nexport interface FeatureProps {\n flag: string;\n children?: ReactNode;\n /** Rendered while the flag is off (default: nothing). */\n fallback?: ReactNode;\n}\n\n/** Renders `children` when the boolean flag is on, else `fallback`. */\nexport function Feature({ flag, children, fallback = null }: FeatureProps) {\n return <>{useFlag(flag) ? children : fallback}</>;\n}\n\n/** Alias of {@link Feature}. */\nexport const FeatureFlag = Feature;\n\nexport interface FeatureValueProps extends FeatureProps {\n /** Renders `children` when the flag's value equals this (deep equality). */\n value: JsonValue;\n}\n\n/** Renders `children` when the flag's value equals `value` (e.g. an experiment variation), else `fallback`. */\nexport function FeatureValue({ flag, value, children, fallback = null }: FeatureValueProps) {\n const current = useFeatureValue<JsonValue>(flag, null);\n return <>{jsonEquals(current, value) ? children : fallback}</>;\n}\n\n/** A static snapshot for SSR and hydration, rebuilt only when the payload or attributes change. */\nexport function useBootstrap(payload: FlagsBootstrap | null | undefined, attributes: Attributes): FlagsReader {\n const key = stableStringify(attributes);\n return useMemo(() => (payload ? createStaticFlags({ payload, attributes }) : EMPTY), [payload, key]);\n}\n\nexport interface FlagsProviderProps extends Omit<FlagsClientOptions, \"payload\"> {\n /** Bootstrap from the server (`getPayload()`): renders the same values on the server and in the browser. */\n payload?: FlagsBootstrap | null;\n /** Use an existing client instead of creating one. */\n client?: FlagsClient;\n children?: ReactNode;\n}\n\n/**\n * Feature flags only (no guides or analytics). Creates a flags client in an effect (never during\n * SSR) and destroys it on unmount; until then hooks read the `payload` snapshot. Changing\n * `attributes` re-evaluates without recreating the client.\n *\n * ```tsx\n * <FlagsProvider sdkKey=\"pk_prod_…\" attributes={{ id: user.id, plan: user.plan }} payload={bootstrap}>\n * ```\n */\nexport function FlagsProvider({ children, client: external, payload, ...options }: FlagsProviderProps) {\n const [created, setCreated] = useState<FlagsClient | null>(null);\n const optionsRef = useRef(options);\n optionsRef.current = options;\n const sdkKey = options.sdkKey ?? options.projectId;\n const { apiUrl, environment } = options;\n const payloadRef = useRef(payload);\n payloadRef.current = payload;\n\n useEffect(() => {\n if (external || !sdkKey || typeof window === \"undefined\") return;\n let c: FlagsClient;\n try {\n c = createFlagsClient({ ...optionsRef.current, sdkKey, payload: payloadRef.current ?? undefined });\n } catch (err) {\n optionsRef.current.onError?.(err instanceof Error ? err : new Error(String(err)));\n return;\n }\n setCreated(c);\n return () => {\n c.destroy();\n setCreated((cur) => (cur === c ? null : cur));\n };\n }, [external, sdkKey, apiUrl, environment]);\n\n const client = external ?? created;\n const attributes = options.attributes ?? {};\n const attrsKey = stableStringify(attributes);\n useEffect(() => {\n if (client && options.attributes) client.setAttributes(options.attributes);\n }, [client, attrsKey]);\n\n const bootstrap = useBootstrap(payload, attributes);\n const value = useMemo<FlagsSource>(() => ({ client, bootstrap }), [client, bootstrap]);\n return <FlagsContext.Provider value={value}>{children}</FlagsContext.Provider>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,gBAA6H;AAC7H,sBAA+J;AAC/J,IAAAC,gBAAgG;;;ACFhG,mBAAuO;AACvO,mBAAsH;AA0E7G;AAlEF,IAAM,mBAAe,4BAAkC,IAAI;AAElE,IAAM,YAAQ,gCAAkB;AAEhC,SAAS,YAAyB;AAChC,QAAM,UAAM,yBAAW,YAAY;AACnC,SAAO,KAAK,UAAU,KAAK,aAAa;AAC1C;AAOA,SAAS,cAAiB,QAAuC;AAC/D,QAAM,SAAS,UAAU;AACzB,QAAM,YAAQ,qBAAiD,IAAI;AACnE,QAAM,MAAM,MAAM;AAChB,UAAM,QAAQ,OAAO,MAAM;AAC3B,UAAM,IAAI,MAAM;AAChB,QAAI,KAAK,EAAE,WAAW,cAAU,yBAAW,EAAE,OAAO,KAAK,EAAG,QAAO,EAAE;AACrE,UAAM,UAAU,EAAE,QAAQ,MAAM;AAChC,WAAO;AAAA,EACT;AACA,aAAO,mCAAqB,OAAO,WAAW,KAAK,GAAG;AACxD;AAGO,SAAS,QAAQ,KAAa,WAAW,OAAgB;AAC9D,SAAO,cAAc,CAAC,MAAM,EAAE,UAAU,KAAK,QAAQ,CAAC;AACxD;AAGO,SAAS,gBAAqC,KAAa,UAA2B;AAC3F,SAAO,cAAc,CAAC,MAAM,EAAE,SAAS,KAAK,QAAQ,CAAC;AACvD;AAGO,SAAS,eAAoC,KAAa,UAAwC;AACvG,SAAO,cAAc,CAAC,MAAM,EAAE,WAAW,KAAK,QAAQ,CAAC;AACzD;AAGO,SAAS,WAAsC;AACpD,SAAO,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC;AACxC;AAGO,SAAS,gBAAyB;AACvC,SAAO,cAAc,CAAC,MAAM,EAAE,QAAQ,CAAC;AACzC;AAGO,SAAS,iBAAqC;AACnD,aAAO,yBAAW,YAAY,GAAG,UAAU;AAC7C;AAUO,SAAS,QAAQ,EAAE,MAAM,UAAU,WAAW,KAAK,GAAiB;AACzE,SAAO,2EAAG,kBAAQ,IAAI,IAAI,WAAW,UAAS;AAChD;AAGO,IAAM,cAAc;AAQpB,SAAS,aAAa,EAAE,MAAM,OAAO,UAAU,WAAW,KAAK,GAAsB;AAC1F,QAAM,UAAU,gBAA2B,MAAM,IAAI;AACrD,SAAO,2EAAG,uCAAW,SAAS,KAAK,IAAI,WAAW,UAAS;AAC7D;AAGO,SAAS,aAAa,SAA4C,YAAqC;AAC5G,QAAM,UAAM,8BAAgB,UAAU;AACtC,aAAO,sBAAQ,MAAO,cAAU,gCAAkB,EAAE,SAAS,WAAW,CAAC,IAAI,OAAQ,CAAC,SAAS,GAAG,CAAC;AACrG;AAmBO,SAAS,cAAc,EAAE,UAAU,QAAQ,UAAU,SAAS,GAAG,QAAQ,GAAuB;AACrG,QAAM,CAAC,SAAS,UAAU,QAAI,uBAA6B,IAAI;AAC/D,QAAM,iBAAa,qBAAO,OAAO;AACjC,aAAW,UAAU;AACrB,QAAM,SAAS,QAAQ,UAAU,QAAQ;AACzC,QAAM,EAAE,QAAQ,YAAY,IAAI;AAChC,QAAM,iBAAa,qBAAO,OAAO;AACjC,aAAW,UAAU;AAErB,8BAAU,MAAM;AACd,QAAI,YAAY,CAAC,UAAU,OAAO,WAAW,YAAa;AAC1D,QAAI;AACJ,QAAI;AACF,cAAI,gCAAkB,EAAE,GAAG,WAAW,SAAS,QAAQ,SAAS,WAAW,WAAW,OAAU,CAAC;AAAA,IACnG,SAAS,KAAK;AACZ,iBAAW,QAAQ,UAAU,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAChF;AAAA,IACF;AACA,eAAW,CAAC;AACZ,WAAO,MAAM;AACX,QAAE,QAAQ;AACV,iBAAW,CAAC,QAAS,QAAQ,IAAI,OAAO,GAAI;AAAA,IAC9C;AAAA,EACF,GAAG,CAAC,UAAU,QAAQ,QAAQ,WAAW,CAAC;AAE1C,QAAM,SAAS,YAAY;AAC3B,QAAM,aAAa,QAAQ,cAAc,CAAC;AAC1C,QAAM,eAAW,8BAAgB,UAAU;AAC3C,8BAAU,MAAM;AACd,QAAI,UAAU,QAAQ,WAAY,QAAO,cAAc,QAAQ,UAAU;AAAA,EAC3E,GAAG,CAAC,QAAQ,QAAQ,CAAC;AAErB,QAAM,YAAY,aAAa,SAAS,UAAU;AAClD,QAAM,YAAQ,sBAAqB,OAAO,EAAE,QAAQ,UAAU,IAAI,CAAC,QAAQ,SAAS,CAAC;AACrF,SAAO,4CAAC,aAAa,UAAb,EAAsB,OAAe,UAAS;AACxD;;;ADnEM,IAAAC,sBAAA;AAzEN,IAAM,qBAAiB,6BAAoC,IAAI;AAgB/D,SAAS,eAAe,MAAkD;AACxE,MAAI,CAAC,MAAM,GAAI,QAAO,CAAC;AACvB,SAAO,EAAE,GAAI,KAAK,UAAU,CAAC,GAAI,IAAI,KAAK,IAAI,GAAI,KAAK,UAAU,EAAE,SAAS,EAAE,GAAI,KAAK,QAAQ,UAAU,CAAC,GAAI,IAAI,KAAK,QAAQ,GAAG,EAAE,IAAI,CAAC,EAAG;AAC9I;AAMO,SAAS,gBAAgB,EAAE,UAAU,MAAM,cAAc,gBAAgB,GAAG,QAAQ,GAAyB;AAClH,QAAM,CAAC,QAAQ,SAAS,QAAI,wBAA+B,IAAI;AAC/D,QAAM,iBAAa,sBAAO,OAAO;AACjC,aAAW,UAAU;AACrB,QAAM,cAAU,sBAAO,IAAI;AAC3B,UAAQ,UAAU;AAClB,QAAM,YAAY,QAAQ,UAAU,QAAQ,OAAQ,QAAQ,SAAS,CAAC;AACtE,QAAM,UAAU,gBAAgB,WAAW,WAAW;AACtD,QAAM,iBAAa,sBAAO,OAAO;AACjC,aAAW,UAAU;AACrB,QAAM,oBAAgB,uBAAQ,OAAO,EAAE,GAAI,WAAW,cAAc,CAAC,GAAI,GAAI,kBAAkB,CAAC,EAAG,IAAI,KAAC,+BAAgB,WAAW,cAAc,CAAC,CAAC,OAAG,+BAAgB,kBAAkB,CAAC,CAAC,CAAC,CAAC;AAC5L,QAAM,uBAAmB,sBAAO,aAAa;AAC7C,mBAAiB,UAAU;AAC3B,QAAM,EAAE,WAAW,aAAa,OAAO,IAAI;AAE3C,+BAAU,MAAM;AACd,QAAI,OAAO,WAAW,eAAe,CAAC,UAAW;AACjD,UAAM,IAAI,WAAW;AAErB,UAAM,QAAI,+BAAc,EAAE,GAAG,GAAG,WAAW,aAAa,QAAQ,MAAM,QAAQ,SAAS,KAAK,QAAQ,UAAU,QAAW,OAAO,EAAE,UAAU,QAAQ,QAAQ,EAAE,GAAI,EAAE,SAAS,CAAC,GAAI,SAAS,WAAW,WAAW,QAAW,YAAY,iBAAiB,QAAQ,EAAE,CAAC;AACpQ,cAAU,CAAC;AACX,WAAO,MAAM;AACX,QAAE,QAAQ;AACV,gBAAU,CAAC,QAAS,QAAQ,IAAI,OAAO,GAAI;AAAA,IAC7C;AAAA,EACF,GAAG,CAAC,WAAW,aAAa,MAAM,CAAC;AAEnC,+BAAU,MAAM;AACd,YAAQ,MAAM,cAAc,aAAa;AAAA,EAC3C,GAAG,CAAC,QAAQ,aAAa,CAAC;AAE1B,QAAM,UAAU,OAAO,KAAK,UAAU,CAAC,KAAK,IAAI,KAAK,UAAU,MAAM,KAAK,WAAW,IAAI,CAAC,IAAI;AAC9F,QAAM,cAAU,sBAAO,KAAK;AAC5B,+BAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AACb,QAAI,QAAQ,KAAK,IAAI;AACnB,cAAQ,UAAU;AAClB,WAAK,OAAO,SAAS,KAAK,IAAI,KAAK,QAAQ,KAAK,OAAO;AAAA,IACzD,WAAW,QAAQ,SAAS;AAC1B,cAAQ,UAAU;AAClB,aAAO,MAAM;AAAA,IACf;AAAA,EACF,GAAG,CAAC,QAAQ,OAAO,CAAC;AAEpB,QAAM,YAAY,aAAa,SAAS,EAAE,GAAG,eAAe,IAAI,GAAG,GAAG,cAAc,CAAC;AACrF,QAAM,YAAQ,uBAAqB,OAAO,EAAE,QAAQ,QAAQ,SAAS,MAAM,UAAU,IAAI,CAAC,QAAQ,SAAS,CAAC;AAC5G,SACE,6CAAC,eAAe,UAAf,EAAwB,OAAO,QAC9B,uDAAC,aAAa,UAAb,EAAsB,OAAO,OAAQ,UAAS,GACjD;AAEJ;AAEA,IAAM,eAAwC;AAAA,EAC5C,MAAM,QAAQ,QAAQ;AAAA,EACtB,OAAO,QAAQ,QAAQ;AAAA,EACvB,UAAU,QAAQ,QAAQ;AAAA,EAC1B,YAAY,QAAQ,QAAQ;AAAA,EAC5B,cAAc,QAAQ,QAAQ;AAAA,EAC9B,SAAS,QAAQ,QAAQ;AAAA,EACzB,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,WAAW,CAAC;AAAA,EACZ,sBAAsB,EAAE,kBAAkB,CAAC,GAAG,aAAa,MAAM,aAAa,KAAK;AAAA,EACnF,kBAAkB;AAAA,EAClB,IAAI,MAAM;AAAA,EAAC;AAAA,EACX,UAAU,EAAE,OAAO,OAAO,WAAW,MAAM;AAAA,EAC3C,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,aAAa;AACf;AAGA,IAAM,YAAY,IAAI,UAAM,iCAAkB,GAA6B;AAAA,EACzE,IAAI,QAAQ,MAAM,UAAU;AAC1B,QAAI,QAAQ,OAAQ,QAAO,QAAQ,IAAI,QAAQ,MAAM,QAAQ;AAC7D,QAAI,SAAS,WAAW,SAAS,aAAa,SAAS,QAAS,QAAO,MAAM,QAAQ,QAAQ;AAC7F,QAAI,SAAS,aAAc,QAAO,MAAM;AACxC,QAAI,SAAS,UAAW,QAAO,MAAM;AACrC,WAAO,OAAO,SAAS,WAAW,MAAM,SAAY;AAAA,EACtD;AACF,CAAC;AAED,IAAM,UAAU,CAAK,KAAa,cAAiC,EAAE,KAAK,OAAO,UAAU,QAAQ,kBAAkB,cAAc,OAAO,cAAc,KAAK;AAG7J,IAAM,iBAA8D;AAAA,EAClE,kBAAkB,CAAC,MAAc,WAAW,UAAU;AAAA,EACtD,iBAAiB,CAAC,MAAc,aAAsB;AAAA,EACtD,mBAAmB,CAAC,KAAa,aAAsB,QAAQ,KAAK,QAAQ;AAAA,EAC5E,eAAe,MAAM,MAAM;AAAA,EAAC;AAC9B;AAGO,IAAM,aAA4B,IAAI,MAAM,CAAC,GAAoB;AAAA,EACtE,IAAI,SAAS,MAAM;AACjB,QAAI,SAAS,UAAW,QAAO,EAAE,WAAW,GAAG;AAC/C,QAAI,SAAS,QAAS,QAAO;AAC7B,QAAI,OAAO,SAAS,SAAU,QAAO;AACrC,WAAO,eAAe,IAAI,MAAM,MAAM,aAAa,IAAI;AAAA,EACzD;AACF,CAAC;AAGM,SAAS,aAA4B;AAC1C,aAAO,0BAAW,cAAc,KAAK;AACvC;AAGO,SAAS,kBAA2B;AACzC,QAAM,aAAS,0BAAW,cAAc;AACxC,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAS,KAAK;AACxC,+BAAU,MAAM;AACd,QAAI,CAAC,QAAQ;AACX,eAAS,KAAK;AACd;AAAA,IACF;AACA,QAAI,OAAO,SAAS,EAAE,MAAO,UAAS,IAAI;AAC1C,WAAO,OAAO,GAAG,SAAS,MAAM,SAAS,IAAI,CAAC;AAAA,EAChD,GAAG,CAAC,MAAM,CAAC;AACX,SAAO;AACT;AAGO,SAAS,mBAAmB,QAAmC,QAAkC,SAAwC;AAC9I,QAAM,aAAS,0BAAW,cAAc;AACxC,QAAM,MAAM,KAAK,UAAU,CAAC,UAAU,MAAM,UAAU,MAAM,WAAW,IAAI,CAAC;AAC5E,+BAAU,MAAM;AACd,QAAI,CAAC,UAAU,CAAC,OAAQ;AACxB,SAAK,OAAO,SAAS,QAAQ,QAAQ,OAAO;AAAA,EAC9C,GAAG,CAAC,QAAQ,GAAG,CAAC;AAClB;AAGO,SAAS,gBAA+C,OAAU,SAAiC;AACxG,QAAM,aAAS,0BAAW,cAAc;AACxC,QAAM,UAAM,sBAAO,OAAO;AAC1B,MAAI,UAAU;AACd,+BAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AACb,UAAM,MAAM,IAAI,SAAqB,IAAI,QAAsC,GAAG,IAAI;AACtF,WAAO,OAAO,GAAG,OAAO,EAAE;AAAA,EAC5B,GAAG,CAAC,QAAQ,KAAK,CAAC;AACpB;AAGO,SAAS,qBAAqB,SAAyC;AAC5E,QAAM,aAAS,0BAAW,cAAc;AACxC,QAAM,CAAC,UAAU,WAAW,QAAI,wBAAiC,EAAE,kBAAkB,CAAC,GAAG,aAAa,MAAM,aAAa,KAAK,CAAC;AAC/H,+BAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AACb,UAAM,SAAS,MAAM,YAAY,OAAO,qBAAqB,OAAO,CAAC;AACrE,WAAO;AACP,UAAM,OAAO,CAAC,OAAO,GAAG,SAAS,MAAM,GAAG,OAAO,GAAG,YAAY,MAAM,GAAG,OAAO,GAAG,kBAAkB,MAAM,GAAG,OAAO,GAAG,sBAAsB,MAAM,CAAC;AACrJ,WAAO,MAAM,KAAK,QAAQ,CAAC,QAAQ,IAAI,CAAC;AAAA,EAC1C,GAAG,CAAC,QAAQ,OAAO,CAAC;AACpB,SAAO;AACT;AAYO,SAAS,cAAc,SAA6B;AACzD,QAAM,aAAS,0BAAW,cAAc;AACxC,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAqB,EAAE,QAAQ,OAAO,WAAW,OAAO,QAAQ,MAAM,WAAW,IAAI,OAAO,KAAK,CAAC;AAC5H,+BAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AACb,UAAM,UAAU,CAAC,MAAsB,EAAE,OAAO,WAAW,EAAE,QAAQ;AACrE,UAAM,UAAU,MAAM;AACpB,YAAM,QAAQ,OAAO,UAAU,EAAE,KAAK,OAAO,KAAK;AAClD,YAAM,SAAS,OAAO,eAAe;AACrC,YAAM,IAAI,OAAO,SAAS,EAAE;AAC5B,eAAS,EAAE,QAAQ,CAAC,CAAC,UAAU,QAAQ,MAAM,GAAG,WAAW,OAAO,iBAAiB,OAAO,GAAG,QAAQ,UAAU,QAAQ,MAAM,IAAM,GAAyC,UAAU,OAAQ,MAAM,WAAW,UAAU,QAAQ,MAAM,IAAM,GAAqC,aAAa,KAAM,IAAI,MAAM,CAAC;AAAA,IAClT;AACA,YAAQ;AACR,UAAM,OAAQ,CAAC,SAAS,YAAY,eAAe,cAAc,kBAAkB,iBAAiB,YAAY,EAAY,IAAI,CAAC,MAAM,OAAO,GAAG,GAAG,OAAO,CAAC;AAC5J,WAAO,MAAM,KAAK,QAAQ,CAAC,QAAQ,IAAI,CAAC;AAAA,EAC1C,GAAG,CAAC,QAAQ,OAAO,CAAC;AACpB,SAAO;AACT;","names":["import_flags","import_react","import_jsx_runtime"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,18 +1,73 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
+
import { JsonValue, FlagsClientOptions, FlagsBootstrap, FlagsClient, FlagValue, FlagDetails, Attributes } from '@guidelytech/flags';
|
|
4
|
+
export { Attributes, EvaluationResult, FlagDetails, FlagsBootstrap, FlagsClient, FlagsClientOptions, FlagsPayload, JsonValue } from '@guidelytech/flags';
|
|
3
5
|
import { PublishedGuide, GuidelyOptions, GuidelyUser, GuidelyClient, ChecklistProgressState, GuidelyEvents } from '@guidelytech/sdk-core';
|
|
4
6
|
export { ChecklistProgressState, GuidelyClient, GuidelyEvents, GuidelyOptions, GuidelyUser, PublishedGuide } from '@guidelytech/sdk-core';
|
|
5
7
|
|
|
8
|
+
/** Is the boolean flag on? `fallback` (default `false`) until flags load, or when missing. */
|
|
9
|
+
declare function useFlag(key: string, fallback?: boolean): boolean;
|
|
10
|
+
/** A flag's value (string, number, JSON…); `fallback` when missing or of a different type. */
|
|
11
|
+
declare function useFeatureValue<T extends JsonValue>(key: string, fallback: T): FlagValue<T>;
|
|
12
|
+
/** A flag's value plus why it was served (reason, rule, variation, experiment). */
|
|
13
|
+
declare function useFlagDetails<T extends JsonValue>(key: string, fallback: T): FlagDetails<FlagValue<T>>;
|
|
14
|
+
/** Every flag's value (records no exposures). */
|
|
15
|
+
declare function useFlags(): Record<string, JsonValue>;
|
|
16
|
+
/** True once flags have loaded (or failed to and serve fallbacks); true from the start with a bootstrap payload. */
|
|
17
|
+
declare function useFlagsReady(): boolean;
|
|
18
|
+
/** The flags client (`null` on the server and before the provider has created it). */
|
|
19
|
+
declare function useFlagsClient(): FlagsClient | null;
|
|
20
|
+
interface FeatureProps {
|
|
21
|
+
flag: string;
|
|
22
|
+
children?: ReactNode;
|
|
23
|
+
/** Rendered while the flag is off (default: nothing). */
|
|
24
|
+
fallback?: ReactNode;
|
|
25
|
+
}
|
|
26
|
+
/** Renders `children` when the boolean flag is on, else `fallback`. */
|
|
27
|
+
declare function Feature({ flag, children, fallback }: FeatureProps): react.JSX.Element;
|
|
28
|
+
/** Alias of {@link Feature}. */
|
|
29
|
+
declare const FeatureFlag: typeof Feature;
|
|
30
|
+
interface FeatureValueProps extends FeatureProps {
|
|
31
|
+
/** Renders `children` when the flag's value equals this (deep equality). */
|
|
32
|
+
value: JsonValue;
|
|
33
|
+
}
|
|
34
|
+
/** Renders `children` when the flag's value equals `value` (e.g. an experiment variation), else `fallback`. */
|
|
35
|
+
declare function FeatureValue({ flag, value, children, fallback }: FeatureValueProps): react.JSX.Element;
|
|
36
|
+
interface FlagsProviderProps extends Omit<FlagsClientOptions, "payload"> {
|
|
37
|
+
/** Bootstrap from the server (`getPayload()`): renders the same values on the server and in the browser. */
|
|
38
|
+
payload?: FlagsBootstrap | null;
|
|
39
|
+
/** Use an existing client instead of creating one. */
|
|
40
|
+
client?: FlagsClient;
|
|
41
|
+
children?: ReactNode;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Feature flags only (no guides or analytics). Creates a flags client in an effect (never during
|
|
45
|
+
* SSR) and destroys it on unmount; until then hooks read the `payload` snapshot. Changing
|
|
46
|
+
* `attributes` re-evaluates without recreating the client.
|
|
47
|
+
*
|
|
48
|
+
* ```tsx
|
|
49
|
+
* <FlagsProvider sdkKey="pk_prod_…" attributes={{ id: user.id, plan: user.plan }} payload={bootstrap}>
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
declare function FlagsProvider({ children, client: external, payload, ...options }: FlagsProviderProps): react.JSX.Element;
|
|
53
|
+
|
|
6
54
|
interface GuidelyProviderProps extends Omit<GuidelyOptions, "user"> {
|
|
7
55
|
/** Identify this user as soon as the client is ready; `undefined` resets the identity. */
|
|
8
56
|
user?: GuidelyUser | null;
|
|
57
|
+
/**
|
|
58
|
+
* Flags bootstrap from the server (`getFlagsBootstrap()` / `client.getPayload()`): flag hooks
|
|
59
|
+
* render the same values on the server, during hydration and after.
|
|
60
|
+
*/
|
|
61
|
+
flagsPayload?: FlagsBootstrap | null;
|
|
62
|
+
/** Extra flag attributes (merged over the automatic identity, page and device attributes). */
|
|
63
|
+
flagAttributes?: Attributes;
|
|
9
64
|
children?: ReactNode;
|
|
10
65
|
}
|
|
11
66
|
/**
|
|
12
67
|
* Creates one Guidely client for the subtree. The client is created inside an effect (never
|
|
13
68
|
* during SSR) and destroyed on unmount, so React Strict Mode's double-invoke is harmless.
|
|
14
69
|
*/
|
|
15
|
-
declare function GuidelyProvider({ children, user, ...options }: GuidelyProviderProps): react.JSX.Element;
|
|
70
|
+
declare function GuidelyProvider({ children, user, flagsPayload, flagAttributes, ...options }: GuidelyProviderProps): react.JSX.Element;
|
|
16
71
|
/** A client that ignores every call; returned by `useGuidely()` on the server and before the provider mounts. */
|
|
17
72
|
declare const noopClient: GuidelyClient;
|
|
18
73
|
/** The Guidely client, or a no-op client during SSR / before the provider has mounted. */
|
|
@@ -36,4 +91,4 @@ interface GuideState {
|
|
|
36
91
|
/** Live state of a guide (by id or key): active, completed, current step. */
|
|
37
92
|
declare function useGuideState(idOrKey: string): GuideState;
|
|
38
93
|
|
|
39
|
-
export { type GuideState, GuidelyProvider, type GuidelyProviderProps, noopClient, useChecklistProgress, useGuideState, useGuidely, useGuidelyEvent, useGuidelyIdentify, useGuidelyReady };
|
|
94
|
+
export { Feature, FeatureFlag, type FeatureProps, FeatureValue, type FeatureValueProps, FlagsProvider, type FlagsProviderProps, type GuideState, GuidelyProvider, type GuidelyProviderProps, noopClient, useChecklistProgress, useFeatureValue, useFlag, useFlagDetails, useFlags, useFlagsClient, useFlagsReady, useGuideState, useGuidely, useGuidelyEvent, useGuidelyIdentify, useGuidelyReady };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,18 +1,73 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
+
import { JsonValue, FlagsClientOptions, FlagsBootstrap, FlagsClient, FlagValue, FlagDetails, Attributes } from '@guidelytech/flags';
|
|
4
|
+
export { Attributes, EvaluationResult, FlagDetails, FlagsBootstrap, FlagsClient, FlagsClientOptions, FlagsPayload, JsonValue } from '@guidelytech/flags';
|
|
3
5
|
import { PublishedGuide, GuidelyOptions, GuidelyUser, GuidelyClient, ChecklistProgressState, GuidelyEvents } from '@guidelytech/sdk-core';
|
|
4
6
|
export { ChecklistProgressState, GuidelyClient, GuidelyEvents, GuidelyOptions, GuidelyUser, PublishedGuide } from '@guidelytech/sdk-core';
|
|
5
7
|
|
|
8
|
+
/** Is the boolean flag on? `fallback` (default `false`) until flags load, or when missing. */
|
|
9
|
+
declare function useFlag(key: string, fallback?: boolean): boolean;
|
|
10
|
+
/** A flag's value (string, number, JSON…); `fallback` when missing or of a different type. */
|
|
11
|
+
declare function useFeatureValue<T extends JsonValue>(key: string, fallback: T): FlagValue<T>;
|
|
12
|
+
/** A flag's value plus why it was served (reason, rule, variation, experiment). */
|
|
13
|
+
declare function useFlagDetails<T extends JsonValue>(key: string, fallback: T): FlagDetails<FlagValue<T>>;
|
|
14
|
+
/** Every flag's value (records no exposures). */
|
|
15
|
+
declare function useFlags(): Record<string, JsonValue>;
|
|
16
|
+
/** True once flags have loaded (or failed to and serve fallbacks); true from the start with a bootstrap payload. */
|
|
17
|
+
declare function useFlagsReady(): boolean;
|
|
18
|
+
/** The flags client (`null` on the server and before the provider has created it). */
|
|
19
|
+
declare function useFlagsClient(): FlagsClient | null;
|
|
20
|
+
interface FeatureProps {
|
|
21
|
+
flag: string;
|
|
22
|
+
children?: ReactNode;
|
|
23
|
+
/** Rendered while the flag is off (default: nothing). */
|
|
24
|
+
fallback?: ReactNode;
|
|
25
|
+
}
|
|
26
|
+
/** Renders `children` when the boolean flag is on, else `fallback`. */
|
|
27
|
+
declare function Feature({ flag, children, fallback }: FeatureProps): react.JSX.Element;
|
|
28
|
+
/** Alias of {@link Feature}. */
|
|
29
|
+
declare const FeatureFlag: typeof Feature;
|
|
30
|
+
interface FeatureValueProps extends FeatureProps {
|
|
31
|
+
/** Renders `children` when the flag's value equals this (deep equality). */
|
|
32
|
+
value: JsonValue;
|
|
33
|
+
}
|
|
34
|
+
/** Renders `children` when the flag's value equals `value` (e.g. an experiment variation), else `fallback`. */
|
|
35
|
+
declare function FeatureValue({ flag, value, children, fallback }: FeatureValueProps): react.JSX.Element;
|
|
36
|
+
interface FlagsProviderProps extends Omit<FlagsClientOptions, "payload"> {
|
|
37
|
+
/** Bootstrap from the server (`getPayload()`): renders the same values on the server and in the browser. */
|
|
38
|
+
payload?: FlagsBootstrap | null;
|
|
39
|
+
/** Use an existing client instead of creating one. */
|
|
40
|
+
client?: FlagsClient;
|
|
41
|
+
children?: ReactNode;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Feature flags only (no guides or analytics). Creates a flags client in an effect (never during
|
|
45
|
+
* SSR) and destroys it on unmount; until then hooks read the `payload` snapshot. Changing
|
|
46
|
+
* `attributes` re-evaluates without recreating the client.
|
|
47
|
+
*
|
|
48
|
+
* ```tsx
|
|
49
|
+
* <FlagsProvider sdkKey="pk_prod_…" attributes={{ id: user.id, plan: user.plan }} payload={bootstrap}>
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
declare function FlagsProvider({ children, client: external, payload, ...options }: FlagsProviderProps): react.JSX.Element;
|
|
53
|
+
|
|
6
54
|
interface GuidelyProviderProps extends Omit<GuidelyOptions, "user"> {
|
|
7
55
|
/** Identify this user as soon as the client is ready; `undefined` resets the identity. */
|
|
8
56
|
user?: GuidelyUser | null;
|
|
57
|
+
/**
|
|
58
|
+
* Flags bootstrap from the server (`getFlagsBootstrap()` / `client.getPayload()`): flag hooks
|
|
59
|
+
* render the same values on the server, during hydration and after.
|
|
60
|
+
*/
|
|
61
|
+
flagsPayload?: FlagsBootstrap | null;
|
|
62
|
+
/** Extra flag attributes (merged over the automatic identity, page and device attributes). */
|
|
63
|
+
flagAttributes?: Attributes;
|
|
9
64
|
children?: ReactNode;
|
|
10
65
|
}
|
|
11
66
|
/**
|
|
12
67
|
* Creates one Guidely client for the subtree. The client is created inside an effect (never
|
|
13
68
|
* during SSR) and destroyed on unmount, so React Strict Mode's double-invoke is harmless.
|
|
14
69
|
*/
|
|
15
|
-
declare function GuidelyProvider({ children, user, ...options }: GuidelyProviderProps): react.JSX.Element;
|
|
70
|
+
declare function GuidelyProvider({ children, user, flagsPayload, flagAttributes, ...options }: GuidelyProviderProps): react.JSX.Element;
|
|
16
71
|
/** A client that ignores every call; returned by `useGuidely()` on the server and before the provider mounts. */
|
|
17
72
|
declare const noopClient: GuidelyClient;
|
|
18
73
|
/** The Guidely client, or a no-op client during SSR / before the provider has mounted. */
|
|
@@ -36,4 +91,4 @@ interface GuideState {
|
|
|
36
91
|
/** Live state of a guide (by id or key): active, completed, current step. */
|
|
37
92
|
declare function useGuideState(idOrKey: string): GuideState;
|
|
38
93
|
|
|
39
|
-
export { type GuideState, GuidelyProvider, type GuidelyProviderProps, noopClient, useChecklistProgress, useGuideState, useGuidely, useGuidelyEvent, useGuidelyIdentify, useGuidelyReady };
|
|
94
|
+
export { Feature, FeatureFlag, type FeatureProps, FeatureValue, type FeatureValueProps, FlagsProvider, type FlagsProviderProps, type GuideState, GuidelyProvider, type GuidelyProviderProps, noopClient, useChecklistProgress, useFeatureValue, useFlag, useFlagDetails, useFlags, useFlagsClient, useFlagsReady, useGuideState, useGuidely, useGuidelyEvent, useGuidelyIdentify, useGuidelyReady };
|
package/dist/index.js
CHANGED
|
@@ -1,27 +1,133 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// src/index.tsx
|
|
4
|
+
import { createStaticFlags as createStaticFlags2, stableStringify as stableStringify2 } from "@guidelytech/flags";
|
|
4
5
|
import { createGuidely } from "@guidelytech/sdk-core";
|
|
5
|
-
import { createContext, useContext, useEffect, useRef, useState } from "react";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
import { createContext as createContext2, useContext as useContext2, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
|
|
7
|
+
|
|
8
|
+
// src/flags.tsx
|
|
9
|
+
import { createFlagsClient, createStaticFlags, jsonEquals, stableStringify } from "@guidelytech/flags";
|
|
10
|
+
import { createContext, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
11
|
+
import { Fragment, jsx } from "react/jsx-runtime";
|
|
12
|
+
var FlagsContext = createContext(null);
|
|
13
|
+
var EMPTY = createStaticFlags();
|
|
14
|
+
function useReader() {
|
|
15
|
+
const src = useContext(FlagsContext);
|
|
16
|
+
return src?.client ?? src?.bootstrap ?? EMPTY;
|
|
17
|
+
}
|
|
18
|
+
function useFlagsValue(select) {
|
|
19
|
+
const reader = useReader();
|
|
20
|
+
const cache = useRef(null);
|
|
21
|
+
const get = () => {
|
|
22
|
+
const value = select(reader);
|
|
23
|
+
const c = cache.current;
|
|
24
|
+
if (c && c.reader === reader && jsonEquals(c.value, value)) return c.value;
|
|
25
|
+
cache.current = { reader, value };
|
|
26
|
+
return value;
|
|
27
|
+
};
|
|
28
|
+
return useSyncExternalStore(reader.subscribe, get, get);
|
|
29
|
+
}
|
|
30
|
+
function useFlag(key, fallback = false) {
|
|
31
|
+
return useFlagsValue((r) => r.isEnabled(key, fallback));
|
|
32
|
+
}
|
|
33
|
+
function useFeatureValue(key, fallback) {
|
|
34
|
+
return useFlagsValue((r) => r.getValue(key, fallback));
|
|
35
|
+
}
|
|
36
|
+
function useFlagDetails(key, fallback) {
|
|
37
|
+
return useFlagsValue((r) => r.getDetails(key, fallback));
|
|
38
|
+
}
|
|
39
|
+
function useFlags() {
|
|
40
|
+
return useFlagsValue((r) => r.getAll());
|
|
41
|
+
}
|
|
42
|
+
function useFlagsReady() {
|
|
43
|
+
return useFlagsValue((r) => r.isReady());
|
|
44
|
+
}
|
|
45
|
+
function useFlagsClient() {
|
|
46
|
+
return useContext(FlagsContext)?.client ?? null;
|
|
47
|
+
}
|
|
48
|
+
function Feature({ flag, children, fallback = null }) {
|
|
49
|
+
return /* @__PURE__ */ jsx(Fragment, { children: useFlag(flag) ? children : fallback });
|
|
50
|
+
}
|
|
51
|
+
var FeatureFlag = Feature;
|
|
52
|
+
function FeatureValue({ flag, value, children, fallback = null }) {
|
|
53
|
+
const current = useFeatureValue(flag, null);
|
|
54
|
+
return /* @__PURE__ */ jsx(Fragment, { children: jsonEquals(current, value) ? children : fallback });
|
|
55
|
+
}
|
|
56
|
+
function useBootstrap(payload, attributes) {
|
|
57
|
+
const key = stableStringify(attributes);
|
|
58
|
+
return useMemo(() => payload ? createStaticFlags({ payload, attributes }) : EMPTY, [payload, key]);
|
|
59
|
+
}
|
|
60
|
+
function FlagsProvider({ children, client: external, payload, ...options }) {
|
|
61
|
+
const [created, setCreated] = useState(null);
|
|
10
62
|
const optionsRef = useRef(options);
|
|
11
63
|
optionsRef.current = options;
|
|
12
|
-
const
|
|
64
|
+
const sdkKey = options.sdkKey ?? options.projectId;
|
|
65
|
+
const { apiUrl, environment } = options;
|
|
66
|
+
const payloadRef = useRef(payload);
|
|
67
|
+
payloadRef.current = payload;
|
|
13
68
|
useEffect(() => {
|
|
69
|
+
if (external || !sdkKey || typeof window === "undefined") return;
|
|
70
|
+
let c;
|
|
71
|
+
try {
|
|
72
|
+
c = createFlagsClient({ ...optionsRef.current, sdkKey, payload: payloadRef.current ?? void 0 });
|
|
73
|
+
} catch (err) {
|
|
74
|
+
optionsRef.current.onError?.(err instanceof Error ? err : new Error(String(err)));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
setCreated(c);
|
|
78
|
+
return () => {
|
|
79
|
+
c.destroy();
|
|
80
|
+
setCreated((cur) => cur === c ? null : cur);
|
|
81
|
+
};
|
|
82
|
+
}, [external, sdkKey, apiUrl, environment]);
|
|
83
|
+
const client = external ?? created;
|
|
84
|
+
const attributes = options.attributes ?? {};
|
|
85
|
+
const attrsKey = stableStringify(attributes);
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
if (client && options.attributes) client.setAttributes(options.attributes);
|
|
88
|
+
}, [client, attrsKey]);
|
|
89
|
+
const bootstrap = useBootstrap(payload, attributes);
|
|
90
|
+
const value = useMemo(() => ({ client, bootstrap }), [client, bootstrap]);
|
|
91
|
+
return /* @__PURE__ */ jsx(FlagsContext.Provider, { value, children });
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// src/index.tsx
|
|
95
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
96
|
+
var GuidelyContext = createContext2(null);
|
|
97
|
+
function userAttributes(user) {
|
|
98
|
+
if (!user?.id) return {};
|
|
99
|
+
return { ...user.traits ?? {}, id: user.id, ...user.account ? { account: { ...user.account.traits ?? {}, id: user.account.id } } : {} };
|
|
100
|
+
}
|
|
101
|
+
function GuidelyProvider({ children, user, flagsPayload, flagAttributes, ...options }) {
|
|
102
|
+
const [client, setClient] = useState2(null);
|
|
103
|
+
const optionsRef = useRef2(options);
|
|
104
|
+
optionsRef.current = options;
|
|
105
|
+
const userRef = useRef2(user);
|
|
106
|
+
userRef.current = user;
|
|
107
|
+
const flagsOpts = options.flags === false ? null : options.flags ?? {};
|
|
108
|
+
const payload = flagsPayload ?? flagsOpts?.payload ?? null;
|
|
109
|
+
const payloadRef = useRef2(payload);
|
|
110
|
+
payloadRef.current = payload;
|
|
111
|
+
const appAttributes = useMemo2(() => ({ ...flagsOpts?.attributes ?? {}, ...flagAttributes ?? {} }), [stableStringify2(flagsOpts?.attributes ?? {}), stableStringify2(flagAttributes ?? {})]);
|
|
112
|
+
const appAttributesRef = useRef2(appAttributes);
|
|
113
|
+
appAttributesRef.current = appAttributes;
|
|
114
|
+
const { projectId, environment, apiUrl } = options;
|
|
115
|
+
useEffect2(() => {
|
|
14
116
|
if (typeof window === "undefined" || !projectId) return;
|
|
15
|
-
const
|
|
117
|
+
const o = optionsRef.current;
|
|
118
|
+
const c = createGuidely({ ...o, projectId, environment, apiUrl, user: userRef.current?.id ? userRef.current : void 0, flags: o.flags === false ? false : { ...o.flags ?? {}, payload: payloadRef.current ?? void 0, attributes: appAttributesRef.current } });
|
|
16
119
|
setClient(c);
|
|
17
120
|
return () => {
|
|
18
121
|
c.destroy();
|
|
19
122
|
setClient((cur) => cur === c ? null : cur);
|
|
20
123
|
};
|
|
21
124
|
}, [projectId, environment, apiUrl]);
|
|
125
|
+
useEffect2(() => {
|
|
126
|
+
client?.flags.setAttributes(appAttributes);
|
|
127
|
+
}, [client, appAttributes]);
|
|
22
128
|
const userKey = user ? JSON.stringify([user.id, user.traits ?? null, user.account ?? null]) : "";
|
|
23
|
-
const hadUser =
|
|
24
|
-
|
|
129
|
+
const hadUser = useRef2(false);
|
|
130
|
+
useEffect2(() => {
|
|
25
131
|
if (!client) return;
|
|
26
132
|
if (user && user.id) {
|
|
27
133
|
hadUser.current = true;
|
|
@@ -31,7 +137,9 @@ function GuidelyProvider({ children, user, ...options }) {
|
|
|
31
137
|
client.reset();
|
|
32
138
|
}
|
|
33
139
|
}, [client, userKey]);
|
|
34
|
-
|
|
140
|
+
const bootstrap = useBootstrap(payload, { ...userAttributes(user), ...appAttributes });
|
|
141
|
+
const flags = useMemo2(() => ({ client: client?.flags ?? null, bootstrap }), [client, bootstrap]);
|
|
142
|
+
return /* @__PURE__ */ jsx2(GuidelyContext.Provider, { value: client, children: /* @__PURE__ */ jsx2(FlagsContext.Provider, { value: flags, children }) });
|
|
35
143
|
}
|
|
36
144
|
var NOOP_RESULTS = {
|
|
37
145
|
init: Promise.resolve(),
|
|
@@ -52,20 +160,38 @@ var NOOP_RESULTS = {
|
|
|
52
160
|
getSessionId: "",
|
|
53
161
|
isRecording: false
|
|
54
162
|
};
|
|
163
|
+
var noopFlags = new Proxy(createStaticFlags2(), {
|
|
164
|
+
get(target, prop, receiver) {
|
|
165
|
+
if (prop in target) return Reflect.get(target, prop, receiver);
|
|
166
|
+
if (prop === "ready" || prop === "refresh" || prop === "flush") return () => Promise.resolve();
|
|
167
|
+
if (prop === "getPayload") return () => null;
|
|
168
|
+
if (prop === "forUser") return () => target;
|
|
169
|
+
return typeof prop === "string" ? () => void 0 : void 0;
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
var missing = (key, fallback) => ({ key, value: fallback, reason: "FLAG_NOT_FOUND", inExperiment: false, usedFallback: true });
|
|
173
|
+
var NOOP_FUNCTIONS = {
|
|
174
|
+
isFeatureEnabled: (_key, fallback = false) => fallback,
|
|
175
|
+
getFeatureValue: (_key, fallback) => fallback,
|
|
176
|
+
getFeatureDetails: (key, fallback) => missing(key, fallback),
|
|
177
|
+
onFlagsChange: () => () => {
|
|
178
|
+
}
|
|
179
|
+
};
|
|
55
180
|
var noopClient = new Proxy({}, {
|
|
56
181
|
get(_target, prop) {
|
|
57
182
|
if (prop === "options") return { projectId: "" };
|
|
183
|
+
if (prop === "flags") return noopFlags;
|
|
58
184
|
if (typeof prop !== "string") return void 0;
|
|
59
|
-
return () => NOOP_RESULTS[prop];
|
|
185
|
+
return NOOP_FUNCTIONS[prop] ?? (() => NOOP_RESULTS[prop]);
|
|
60
186
|
}
|
|
61
187
|
});
|
|
62
188
|
function useGuidely() {
|
|
63
|
-
return
|
|
189
|
+
return useContext2(GuidelyContext) ?? noopClient;
|
|
64
190
|
}
|
|
65
191
|
function useGuidelyReady() {
|
|
66
|
-
const client =
|
|
67
|
-
const [ready, setReady] =
|
|
68
|
-
|
|
192
|
+
const client = useContext2(GuidelyContext);
|
|
193
|
+
const [ready, setReady] = useState2(false);
|
|
194
|
+
useEffect2(() => {
|
|
69
195
|
if (!client) {
|
|
70
196
|
setReady(false);
|
|
71
197
|
return;
|
|
@@ -76,27 +202,27 @@ function useGuidelyReady() {
|
|
|
76
202
|
return ready;
|
|
77
203
|
}
|
|
78
204
|
function useGuidelyIdentify(userId, traits, account) {
|
|
79
|
-
const client =
|
|
205
|
+
const client = useContext2(GuidelyContext);
|
|
80
206
|
const key = JSON.stringify([userId ?? null, traits ?? null, account ?? null]);
|
|
81
|
-
|
|
207
|
+
useEffect2(() => {
|
|
82
208
|
if (!client || !userId) return;
|
|
83
209
|
void client.identify(userId, traits, account);
|
|
84
210
|
}, [client, key]);
|
|
85
211
|
}
|
|
86
212
|
function useGuidelyEvent(event, handler) {
|
|
87
|
-
const client =
|
|
88
|
-
const ref =
|
|
213
|
+
const client = useContext2(GuidelyContext);
|
|
214
|
+
const ref = useRef2(handler);
|
|
89
215
|
ref.current = handler;
|
|
90
|
-
|
|
216
|
+
useEffect2(() => {
|
|
91
217
|
if (!client) return;
|
|
92
218
|
const cb = ((...args) => ref.current(...args));
|
|
93
219
|
return client.on(event, cb);
|
|
94
220
|
}, [client, event]);
|
|
95
221
|
}
|
|
96
222
|
function useChecklistProgress(idOrKey) {
|
|
97
|
-
const client =
|
|
98
|
-
const [progress, setProgress] =
|
|
99
|
-
|
|
223
|
+
const client = useContext2(GuidelyContext);
|
|
224
|
+
const [progress, setProgress] = useState2({ completedTaskIds: [], completedAt: null, dismissedAt: null });
|
|
225
|
+
useEffect2(() => {
|
|
100
226
|
if (!client) return;
|
|
101
227
|
const update = () => setProgress(client.getChecklistProgress(idOrKey));
|
|
102
228
|
update();
|
|
@@ -106,9 +232,9 @@ function useChecklistProgress(idOrKey) {
|
|
|
106
232
|
return progress;
|
|
107
233
|
}
|
|
108
234
|
function useGuideState(idOrKey) {
|
|
109
|
-
const client =
|
|
110
|
-
const [state, setState] =
|
|
111
|
-
|
|
235
|
+
const client = useContext2(GuidelyContext);
|
|
236
|
+
const [state, setState] = useState2({ active: false, completed: false, stepId: null, stepIndex: -1, guide: null });
|
|
237
|
+
useEffect2(() => {
|
|
112
238
|
if (!client) return;
|
|
113
239
|
const matches = (g) => g.id === idOrKey || g.key === idOrKey;
|
|
114
240
|
const compute = () => {
|
|
@@ -124,9 +250,19 @@ function useGuideState(idOrKey) {
|
|
|
124
250
|
return state;
|
|
125
251
|
}
|
|
126
252
|
export {
|
|
253
|
+
Feature,
|
|
254
|
+
FeatureFlag,
|
|
255
|
+
FeatureValue,
|
|
256
|
+
FlagsProvider,
|
|
127
257
|
GuidelyProvider,
|
|
128
258
|
noopClient,
|
|
129
259
|
useChecklistProgress,
|
|
260
|
+
useFeatureValue,
|
|
261
|
+
useFlag,
|
|
262
|
+
useFlagDetails,
|
|
263
|
+
useFlags,
|
|
264
|
+
useFlagsClient,
|
|
265
|
+
useFlagsReady,
|
|
130
266
|
useGuideState,
|
|
131
267
|
useGuidely,
|
|
132
268
|
useGuidelyEvent,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.tsx"],"sourcesContent":["import { createGuidely, type ChecklistProgressState, type GuidelyClient, type GuidelyEvents, type GuidelyOptions, type GuidelyUser, type PublishedGuide } from \"@guidelytech/sdk-core\";\nimport { createContext, useContext, useEffect, useRef, useState, type ReactNode } from \"react\";\n\nexport type { GuidelyClient, GuidelyOptions, GuidelyEvents, GuidelyUser, ChecklistProgressState, PublishedGuide } from \"@guidelytech/sdk-core\";\n\nconst GuidelyContext = createContext<GuidelyClient | null>(null);\n\nexport interface GuidelyProviderProps extends Omit<GuidelyOptions, \"user\"> {\n /** Identify this user as soon as the client is ready; `undefined` resets the identity. */\n user?: GuidelyUser | null;\n children?: ReactNode;\n}\n\n/**\n * Creates one Guidely client for the subtree. The client is created inside an effect (never\n * during SSR) and destroyed on unmount, so React Strict Mode's double-invoke is harmless.\n */\nexport function GuidelyProvider({ children, user, ...options }: GuidelyProviderProps) {\n const [client, setClient] = useState<GuidelyClient | null>(null);\n const optionsRef = useRef(options);\n optionsRef.current = options;\n const { projectId, environment, apiUrl } = options;\n\n useEffect(() => {\n if (typeof window === \"undefined\" || !projectId) return;\n const c = createGuidely({ ...optionsRef.current, projectId, environment, apiUrl });\n setClient(c);\n return () => {\n c.destroy();\n setClient((cur) => (cur === c ? null : cur));\n };\n }, [projectId, environment, apiUrl]);\n\n const userKey = user ? JSON.stringify([user.id, user.traits ?? null, user.account ?? null]) : \"\";\n const hadUser = useRef(false);\n useEffect(() => {\n if (!client) return;\n if (user && user.id) {\n hadUser.current = true;\n void client.identify(user.id, user.traits, user.account);\n } else if (hadUser.current) {\n hadUser.current = false;\n client.reset();\n }\n }, [client, userKey]);\n\n return <GuidelyContext.Provider value={client}>{children}</GuidelyContext.Provider>;\n}\n\nconst NOOP_RESULTS: Record<string, unknown> = {\n init: Promise.resolve(),\n ready: Promise.resolve(),\n identify: Promise.resolve(),\n setAccount: Promise.resolve(),\n updateTraits: Promise.resolve(),\n refresh: Promise.resolve(),\n startGuide: false,\n getActiveGuide: null,\n getGuides: [],\n getChecklistProgress: { completedTaskIds: [], completedAt: null, dismissedAt: null },\n isGuideCompleted: false,\n on: () => {},\n getState: { ready: false, destroyed: false },\n getContext: null,\n getSessionId: \"\",\n isRecording: false,\n};\n\n/** A client that ignores every call; returned by `useGuidely()` on the server and before the provider mounts. */\nexport const noopClient: GuidelyClient = new Proxy({} as GuidelyClient, {\n get(_target, prop) {\n if (prop === \"options\") return { projectId: \"\" };\n if (typeof prop !== \"string\") return undefined;\n return () => NOOP_RESULTS[prop];\n },\n});\n\n/** The Guidely client, or a no-op client during SSR / before the provider has mounted. */\nexport function useGuidely(): GuidelyClient {\n return useContext(GuidelyContext) ?? noopClient;\n}\n\n/** True once the client has loaded its configuration. */\nexport function useGuidelyReady(): boolean {\n const client = useContext(GuidelyContext);\n const [ready, setReady] = useState(false);\n useEffect(() => {\n if (!client) {\n setReady(false);\n return;\n }\n if (client.getState().ready) setReady(true);\n return client.on(\"ready\", () => setReady(true));\n }, [client]);\n return ready;\n}\n\n/** Identifies the user whenever the arguments change. */\nexport function useGuidelyIdentify(userId: string | null | undefined, traits?: Record<string, unknown>, account?: GuidelyUser[\"account\"]): void {\n const client = useContext(GuidelyContext);\n const key = JSON.stringify([userId ?? null, traits ?? null, account ?? null]);\n useEffect(() => {\n if (!client || !userId) return;\n void client.identify(userId, traits, account);\n }, [client, key]);\n}\n\n/** Subscribes to a client event for the lifetime of the component. */\nexport function useGuidelyEvent<K extends keyof GuidelyEvents>(event: K, handler: GuidelyEvents[K]): void {\n const client = useContext(GuidelyContext);\n const ref = useRef(handler);\n ref.current = handler;\n useEffect(() => {\n if (!client) return;\n const cb = ((...args: unknown[]) => (ref.current as (...a: unknown[]) => void)(...args)) as GuidelyEvents[K];\n return client.on(event, cb);\n }, [client, event]);\n}\n\n/** Live checklist progress for a checklist guide (by id or key). */\nexport function useChecklistProgress(idOrKey: string): ChecklistProgressState {\n const client = useContext(GuidelyContext);\n const [progress, setProgress] = useState<ChecklistProgressState>({ completedTaskIds: [], completedAt: null, dismissedAt: null });\n useEffect(() => {\n if (!client) return;\n const update = () => setProgress(client.getChecklistProgress(idOrKey));\n update();\n const offs = [client.on(\"ready\", update), client.on(\"identify\", update), client.on(\"checklist:task\", update), client.on(\"checklist:complete\", update)];\n return () => offs.forEach((off) => off());\n }, [client, idOrKey]);\n return progress;\n}\n\nexport interface GuideState {\n /** The guide is currently showing. */\n active: boolean;\n completed: boolean;\n stepId: string | null;\n stepIndex: number;\n guide: PublishedGuide | null;\n}\n\n/** Live state of a guide (by id or key): active, completed, current step. */\nexport function useGuideState(idOrKey: string): GuideState {\n const client = useContext(GuidelyContext);\n const [state, setState] = useState<GuideState>({ active: false, completed: false, stepId: null, stepIndex: -1, guide: null });\n useEffect(() => {\n if (!client) return;\n const matches = (g: PublishedGuide) => g.id === idOrKey || g.key === idOrKey;\n const compute = () => {\n const guide = client.getGuides().find(matches) ?? null;\n const active = client.getActiveGuide();\n const s = client.getState().activeGuide;\n setState({ active: !!active && matches(active), completed: client.isGuideCompleted(idOrKey), stepId: active && matches(active) ? ((s as { stepId?: string | null } | null)?.stepId ?? null) : null, stepIndex: active && matches(active) ? ((s as { stepIndex?: number } | null)?.stepIndex ?? -1) : -1, guide });\n };\n compute();\n const offs = ([\"ready\", \"identify\", \"guide:start\", \"guide:step\", \"guide:complete\", \"guide:dismiss\", \"guide:skip\"] as const).map((e) => client.on(e, compute));\n return () => offs.forEach((off) => off());\n }, [client, idOrKey]);\n return state;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx","../src/flags.tsx"],"sourcesContent":["import { createStaticFlags, stableStringify, type Attributes, type FlagDetails, type FlagsBootstrap, type FlagsClient } from \"@guidelytech/flags\";\nimport { createGuidely, type ChecklistProgressState, type GuidelyClient, type GuidelyEvents, type GuidelyOptions, type GuidelyUser, type PublishedGuide } from \"@guidelytech/sdk-core\";\nimport { createContext, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport { FlagsContext, useBootstrap, type FlagsSource } from \"./flags\";\n\nexport type { GuidelyClient, GuidelyOptions, GuidelyEvents, GuidelyUser, ChecklistProgressState, PublishedGuide } from \"@guidelytech/sdk-core\";\nexport { useFlag, useFeatureValue, useFlagDetails, useFlags, useFlagsReady, useFlagsClient, Feature, FeatureFlag, FeatureValue, FlagsProvider } from \"./flags\";\nexport type { FeatureProps, FeatureValueProps, FlagsProviderProps } from \"./flags\";\nexport type { FlagsClient, FlagsClientOptions, FlagDetails, FlagsBootstrap, FlagsPayload, Attributes, JsonValue, EvaluationResult } from \"@guidelytech/flags\";\n\nconst GuidelyContext = createContext<GuidelyClient | null>(null);\n\nexport interface GuidelyProviderProps extends Omit<GuidelyOptions, \"user\"> {\n /** Identify this user as soon as the client is ready; `undefined` resets the identity. */\n user?: GuidelyUser | null;\n /**\n * Flags bootstrap from the server (`getFlagsBootstrap()` / `client.getPayload()`): flag hooks\n * render the same values on the server, during hydration and after.\n */\n flagsPayload?: FlagsBootstrap | null;\n /** Extra flag attributes (merged over the automatic identity, page and device attributes). */\n flagAttributes?: Attributes;\n children?: ReactNode;\n}\n\n/** The attributes the server knows about a user: what bootstrap snapshots evaluate with. */\nfunction userAttributes(user: GuidelyUser | null | undefined): Attributes {\n if (!user?.id) return {};\n return { ...(user.traits ?? {}), id: user.id, ...(user.account ? { account: { ...(user.account.traits ?? {}), id: user.account.id } } : {}) };\n}\n\n/**\n * Creates one Guidely client for the subtree. The client is created inside an effect (never\n * during SSR) and destroyed on unmount, so React Strict Mode's double-invoke is harmless.\n */\nexport function GuidelyProvider({ children, user, flagsPayload, flagAttributes, ...options }: GuidelyProviderProps) {\n const [client, setClient] = useState<GuidelyClient | null>(null);\n const optionsRef = useRef(options);\n optionsRef.current = options;\n const userRef = useRef(user);\n userRef.current = user;\n const flagsOpts = options.flags === false ? null : (options.flags ?? {});\n const payload = flagsPayload ?? flagsOpts?.payload ?? null;\n const payloadRef = useRef(payload);\n payloadRef.current = payload;\n const appAttributes = useMemo(() => ({ ...(flagsOpts?.attributes ?? {}), ...(flagAttributes ?? {}) }), [stableStringify(flagsOpts?.attributes ?? {}), stableStringify(flagAttributes ?? {})]);\n const appAttributesRef = useRef(appAttributes);\n appAttributesRef.current = appAttributes;\n const { projectId, environment, apiUrl } = options;\n\n useEffect(() => {\n if (typeof window === \"undefined\" || !projectId) return;\n const o = optionsRef.current;\n // The user is known up front so flags evaluate for them from the first render (no flicker).\n const c = createGuidely({ ...o, projectId, environment, apiUrl, user: userRef.current?.id ? userRef.current : undefined, flags: o.flags === false ? false : { ...(o.flags ?? {}), payload: payloadRef.current ?? undefined, attributes: appAttributesRef.current } });\n setClient(c);\n return () => {\n c.destroy();\n setClient((cur) => (cur === c ? null : cur));\n };\n }, [projectId, environment, apiUrl]);\n\n useEffect(() => {\n client?.flags.setAttributes(appAttributes);\n }, [client, appAttributes]);\n\n const userKey = user ? JSON.stringify([user.id, user.traits ?? null, user.account ?? null]) : \"\";\n const hadUser = useRef(false);\n useEffect(() => {\n if (!client) return;\n if (user && user.id) {\n hadUser.current = true;\n void client.identify(user.id, user.traits, user.account);\n } else if (hadUser.current) {\n hadUser.current = false;\n client.reset();\n }\n }, [client, userKey]);\n\n const bootstrap = useBootstrap(payload, { ...userAttributes(user), ...appAttributes });\n const flags = useMemo<FlagsSource>(() => ({ client: client?.flags ?? null, bootstrap }), [client, bootstrap]);\n return (\n <GuidelyContext.Provider value={client}>\n <FlagsContext.Provider value={flags}>{children}</FlagsContext.Provider>\n </GuidelyContext.Provider>\n );\n}\n\nconst NOOP_RESULTS: Record<string, unknown> = {\n init: Promise.resolve(),\n ready: Promise.resolve(),\n identify: Promise.resolve(),\n setAccount: Promise.resolve(),\n updateTraits: Promise.resolve(),\n refresh: Promise.resolve(),\n startGuide: false,\n getActiveGuide: null,\n getGuides: [],\n getChecklistProgress: { completedTaskIds: [], completedAt: null, dismissedAt: null },\n isGuideCompleted: false,\n on: () => {},\n getState: { ready: false, destroyed: false },\n getContext: null,\n getSessionId: \"\",\n isRecording: false,\n};\n\n/** Flags that serve every fallback; `useGuidely().flags` before the provider has a client. */\nconst noopFlags = new Proxy(createStaticFlags() as unknown as FlagsClient, {\n get(target, prop, receiver) {\n if (prop in target) return Reflect.get(target, prop, receiver);\n if (prop === \"ready\" || prop === \"refresh\" || prop === \"flush\") return () => Promise.resolve();\n if (prop === \"getPayload\") return () => null;\n if (prop === \"forUser\") return () => target;\n return typeof prop === \"string\" ? () => undefined : undefined;\n },\n});\n\nconst missing = <T,>(key: string, fallback: T): FlagDetails<T> => ({ key, value: fallback, reason: \"FLAG_NOT_FOUND\", inExperiment: false, usedFallback: true });\n\n/** Methods whose no-op answer depends on the arguments (flag getters return the fallback). */\nconst NOOP_FUNCTIONS: Record<string, (...args: any[]) => unknown> = {\n isFeatureEnabled: (_key: string, fallback = false) => fallback,\n getFeatureValue: (_key: string, fallback: unknown) => fallback,\n getFeatureDetails: (key: string, fallback: unknown) => missing(key, fallback),\n onFlagsChange: () => () => {},\n};\n\n/** A client that ignores every call; returned by `useGuidely()` on the server and before the provider mounts. */\nexport const noopClient: GuidelyClient = new Proxy({} as GuidelyClient, {\n get(_target, prop) {\n if (prop === \"options\") return { projectId: \"\" };\n if (prop === \"flags\") return noopFlags;\n if (typeof prop !== \"string\") return undefined;\n return NOOP_FUNCTIONS[prop] ?? (() => NOOP_RESULTS[prop]);\n },\n});\n\n/** The Guidely client, or a no-op client during SSR / before the provider has mounted. */\nexport function useGuidely(): GuidelyClient {\n return useContext(GuidelyContext) ?? noopClient;\n}\n\n/** True once the client has loaded its configuration. */\nexport function useGuidelyReady(): boolean {\n const client = useContext(GuidelyContext);\n const [ready, setReady] = useState(false);\n useEffect(() => {\n if (!client) {\n setReady(false);\n return;\n }\n if (client.getState().ready) setReady(true);\n return client.on(\"ready\", () => setReady(true));\n }, [client]);\n return ready;\n}\n\n/** Identifies the user whenever the arguments change. */\nexport function useGuidelyIdentify(userId: string | null | undefined, traits?: Record<string, unknown>, account?: GuidelyUser[\"account\"]): void {\n const client = useContext(GuidelyContext);\n const key = JSON.stringify([userId ?? null, traits ?? null, account ?? null]);\n useEffect(() => {\n if (!client || !userId) return;\n void client.identify(userId, traits, account);\n }, [client, key]);\n}\n\n/** Subscribes to a client event for the lifetime of the component. */\nexport function useGuidelyEvent<K extends keyof GuidelyEvents>(event: K, handler: GuidelyEvents[K]): void {\n const client = useContext(GuidelyContext);\n const ref = useRef(handler);\n ref.current = handler;\n useEffect(() => {\n if (!client) return;\n const cb = ((...args: unknown[]) => (ref.current as (...a: unknown[]) => void)(...args)) as GuidelyEvents[K];\n return client.on(event, cb);\n }, [client, event]);\n}\n\n/** Live checklist progress for a checklist guide (by id or key). */\nexport function useChecklistProgress(idOrKey: string): ChecklistProgressState {\n const client = useContext(GuidelyContext);\n const [progress, setProgress] = useState<ChecklistProgressState>({ completedTaskIds: [], completedAt: null, dismissedAt: null });\n useEffect(() => {\n if (!client) return;\n const update = () => setProgress(client.getChecklistProgress(idOrKey));\n update();\n const offs = [client.on(\"ready\", update), client.on(\"identify\", update), client.on(\"checklist:task\", update), client.on(\"checklist:complete\", update)];\n return () => offs.forEach((off) => off());\n }, [client, idOrKey]);\n return progress;\n}\n\nexport interface GuideState {\n /** The guide is currently showing. */\n active: boolean;\n completed: boolean;\n stepId: string | null;\n stepIndex: number;\n guide: PublishedGuide | null;\n}\n\n/** Live state of a guide (by id or key): active, completed, current step. */\nexport function useGuideState(idOrKey: string): GuideState {\n const client = useContext(GuidelyContext);\n const [state, setState] = useState<GuideState>({ active: false, completed: false, stepId: null, stepIndex: -1, guide: null });\n useEffect(() => {\n if (!client) return;\n const matches = (g: PublishedGuide) => g.id === idOrKey || g.key === idOrKey;\n const compute = () => {\n const guide = client.getGuides().find(matches) ?? null;\n const active = client.getActiveGuide();\n const s = client.getState().activeGuide;\n setState({ active: !!active && matches(active), completed: client.isGuideCompleted(idOrKey), stepId: active && matches(active) ? ((s as { stepId?: string | null } | null)?.stepId ?? null) : null, stepIndex: active && matches(active) ? ((s as { stepIndex?: number } | null)?.stepIndex ?? -1) : -1, guide });\n };\n compute();\n const offs = ([\"ready\", \"identify\", \"guide:start\", \"guide:step\", \"guide:complete\", \"guide:dismiss\", \"guide:skip\"] as const).map((e) => client.on(e, compute));\n return () => offs.forEach((off) => off());\n }, [client, idOrKey]);\n return state;\n}\n","import { createFlagsClient, createStaticFlags, jsonEquals, stableStringify, type Attributes, type FlagDetails, type FlagValue, type FlagsBootstrap, type FlagsClient, type FlagsClientOptions, type FlagsReader, type JsonValue } from \"@guidelytech/flags\";\nimport { createContext, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore, type ReactNode } from \"react\";\n\n/** What the flag hooks read: the live client once created, else a static snapshot of the bootstrap payload. */\nexport interface FlagsSource {\n client: FlagsClient | null;\n bootstrap: FlagsReader;\n}\n\nexport const FlagsContext = createContext<FlagsSource | null>(null);\n\nconst EMPTY = createStaticFlags();\n\nfunction useReader(): FlagsReader {\n const src = useContext(FlagsContext);\n return src?.client ?? src?.bootstrap ?? EMPTY;\n}\n\n/**\n * Subscribes to the flags with `useSyncExternalStore`. Values are compared deeply so object\n * flags keep their identity between renders. The server snapshot is the bootstrap payload, so\n * server-rendered HTML and hydration agree.\n */\nfunction useFlagsValue<T>(select: (reader: FlagsReader) => T): T {\n const reader = useReader();\n const cache = useRef<{ reader: FlagsReader; value: T } | null>(null);\n const get = () => {\n const value = select(reader);\n const c = cache.current;\n if (c && c.reader === reader && jsonEquals(c.value, value)) return c.value;\n cache.current = { reader, value };\n return value;\n };\n return useSyncExternalStore(reader.subscribe, get, get);\n}\n\n/** Is the boolean flag on? `fallback` (default `false`) until flags load, or when missing. */\nexport function useFlag(key: string, fallback = false): boolean {\n return useFlagsValue((r) => r.isEnabled(key, fallback));\n}\n\n/** A flag's value (string, number, JSON…); `fallback` when missing or of a different type. */\nexport function useFeatureValue<T extends JsonValue>(key: string, fallback: T): FlagValue<T> {\n return useFlagsValue((r) => r.getValue(key, fallback));\n}\n\n/** A flag's value plus why it was served (reason, rule, variation, experiment). */\nexport function useFlagDetails<T extends JsonValue>(key: string, fallback: T): FlagDetails<FlagValue<T>> {\n return useFlagsValue((r) => r.getDetails(key, fallback));\n}\n\n/** Every flag's value (records no exposures). */\nexport function useFlags(): Record<string, JsonValue> {\n return useFlagsValue((r) => r.getAll());\n}\n\n/** True once flags have loaded (or failed to and serve fallbacks); true from the start with a bootstrap payload. */\nexport function useFlagsReady(): boolean {\n return useFlagsValue((r) => r.isReady());\n}\n\n/** The flags client (`null` on the server and before the provider has created it). */\nexport function useFlagsClient(): FlagsClient | null {\n return useContext(FlagsContext)?.client ?? null;\n}\n\nexport interface FeatureProps {\n flag: string;\n children?: ReactNode;\n /** Rendered while the flag is off (default: nothing). */\n fallback?: ReactNode;\n}\n\n/** Renders `children` when the boolean flag is on, else `fallback`. */\nexport function Feature({ flag, children, fallback = null }: FeatureProps) {\n return <>{useFlag(flag) ? children : fallback}</>;\n}\n\n/** Alias of {@link Feature}. */\nexport const FeatureFlag = Feature;\n\nexport interface FeatureValueProps extends FeatureProps {\n /** Renders `children` when the flag's value equals this (deep equality). */\n value: JsonValue;\n}\n\n/** Renders `children` when the flag's value equals `value` (e.g. an experiment variation), else `fallback`. */\nexport function FeatureValue({ flag, value, children, fallback = null }: FeatureValueProps) {\n const current = useFeatureValue<JsonValue>(flag, null);\n return <>{jsonEquals(current, value) ? children : fallback}</>;\n}\n\n/** A static snapshot for SSR and hydration, rebuilt only when the payload or attributes change. */\nexport function useBootstrap(payload: FlagsBootstrap | null | undefined, attributes: Attributes): FlagsReader {\n const key = stableStringify(attributes);\n return useMemo(() => (payload ? createStaticFlags({ payload, attributes }) : EMPTY), [payload, key]);\n}\n\nexport interface FlagsProviderProps extends Omit<FlagsClientOptions, \"payload\"> {\n /** Bootstrap from the server (`getPayload()`): renders the same values on the server and in the browser. */\n payload?: FlagsBootstrap | null;\n /** Use an existing client instead of creating one. */\n client?: FlagsClient;\n children?: ReactNode;\n}\n\n/**\n * Feature flags only (no guides or analytics). Creates a flags client in an effect (never during\n * SSR) and destroys it on unmount; until then hooks read the `payload` snapshot. Changing\n * `attributes` re-evaluates without recreating the client.\n *\n * ```tsx\n * <FlagsProvider sdkKey=\"pk_prod_…\" attributes={{ id: user.id, plan: user.plan }} payload={bootstrap}>\n * ```\n */\nexport function FlagsProvider({ children, client: external, payload, ...options }: FlagsProviderProps) {\n const [created, setCreated] = useState<FlagsClient | null>(null);\n const optionsRef = useRef(options);\n optionsRef.current = options;\n const sdkKey = options.sdkKey ?? options.projectId;\n const { apiUrl, environment } = options;\n const payloadRef = useRef(payload);\n payloadRef.current = payload;\n\n useEffect(() => {\n if (external || !sdkKey || typeof window === \"undefined\") return;\n let c: FlagsClient;\n try {\n c = createFlagsClient({ ...optionsRef.current, sdkKey, payload: payloadRef.current ?? undefined });\n } catch (err) {\n optionsRef.current.onError?.(err instanceof Error ? err : new Error(String(err)));\n return;\n }\n setCreated(c);\n return () => {\n c.destroy();\n setCreated((cur) => (cur === c ? null : cur));\n };\n }, [external, sdkKey, apiUrl, environment]);\n\n const client = external ?? created;\n const attributes = options.attributes ?? {};\n const attrsKey = stableStringify(attributes);\n useEffect(() => {\n if (client && options.attributes) client.setAttributes(options.attributes);\n }, [client, attrsKey]);\n\n const bootstrap = useBootstrap(payload, attributes);\n const value = useMemo<FlagsSource>(() => ({ client, bootstrap }), [client, bootstrap]);\n return <FlagsContext.Provider value={value}>{children}</FlagsContext.Provider>;\n}\n"],"mappings":"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","names":["createStaticFlags","stableStringify","createContext","useContext","useEffect","useMemo","useRef","useState","jsx","createContext","useState","useRef","useMemo","stableStringify","useEffect","createStaticFlags","useContext"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@guidelytech/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "React provider and hooks for Guidely",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -20,8 +20,9 @@
|
|
|
20
20
|
"README.md"
|
|
21
21
|
],
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@guidelytech/
|
|
24
|
-
"@guidelytech/shared": "0.
|
|
23
|
+
"@guidelytech/flags": "0.7.0",
|
|
24
|
+
"@guidelytech/shared": "0.7.0",
|
|
25
|
+
"@guidelytech/sdk-core": "0.7.0"
|
|
25
26
|
},
|
|
26
27
|
"devDependencies": {
|
|
27
28
|
"tsup": "^8.5.1",
|