@sentientui/react 0.1.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.
@@ -0,0 +1,136 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+ import { SentientConfig, SentientClient } from '@sentientui/core';
4
+ export { deriveSessionSegment as detectSegment } from '@sentientui/core';
5
+
6
+ /** How to render adaptive slots during SSR when assignments are not preloaded. */
7
+ type SsrFallback = 'first' | 'none';
8
+ type AdaptiveProviderProps = {
9
+ apiKey: string;
10
+ context: SentientConfig['context'];
11
+ ingestUrl: string;
12
+ debug?: boolean;
13
+ /**
14
+ * SSR-preloaded assignments from `preloadAssignments()` / `loadAdaptiveAssignments()`.
15
+ * Passed through to `useAssignment` as synchronous initial state so crawlers and
16
+ * the first paint see real content (recommended for SEO).
17
+ */
18
+ initialAssignments?: Record<string, string>;
19
+ /**
20
+ * Bandit segment from SSR (`device:source`). Keeps cache, assign, and worker
21
+ * weights on one row — must match `loadAdaptiveAssignments` / session upsert.
22
+ */
23
+ sessionSegment?: string;
24
+ /**
25
+ * When no `initialAssignments` exist for a component, `'first'` renders
26
+ * `variantIds[0]` in server HTML (safe default for SEO). Use `'none'` only for
27
+ * decorative slots marked `clientOnly`.
28
+ * @default 'first'
29
+ */
30
+ ssrFallback?: SsrFallback;
31
+ /**
32
+ * Consent gate. When `false` the SDK is not initialised and no events are
33
+ * sent. Flip to `true` (e.g. after the user accepts the cookie banner) to
34
+ * initialise and begin tracking.
35
+ */
36
+ consent?: boolean;
37
+ /**
38
+ * Called once per component the first time a variant is resolved for that
39
+ * component in this session. Use to forward assignments to your own analytics
40
+ * (Mixpanel, PostHog, Segment, etc.) without having to wrap `useAssignment`.
41
+ */
42
+ onAssignment?: (componentId: string, variantId: string) => void;
43
+ children: ReactNode;
44
+ };
45
+ /**
46
+ * Initialises the Sentient core SDK in a useEffect (SSR-safe) and exposes the
47
+ * client via React context. Re-initialises when `consent` changes.
48
+ */
49
+ declare function AdaptiveProvider(props: AdaptiveProviderProps): JSX.Element;
50
+ /**
51
+ * Returns the SentientClient, or null until the provider has finished
52
+ * initialising on the client.
53
+ */
54
+ declare function useSentient(): SentientClient | null;
55
+ /** Internal: SSR-preloaded assignments for hydration-safe first render. */
56
+ declare function useInitialAssignments(): Record<string, string>;
57
+
58
+ type ScrollDepthGoal = {
59
+ type: 'scroll_depth';
60
+ threshold: number;
61
+ };
62
+ type ClickGoal = {
63
+ type: 'click';
64
+ selector?: string;
65
+ };
66
+ type FormSubmitGoal = {
67
+ type: 'form_submit';
68
+ };
69
+ type CompositeGoal = {
70
+ type: 'composite';
71
+ all: GoalConfig[];
72
+ };
73
+ type GoalConfig = ScrollDepthGoal | ClickGoal | FormSubmitGoal | CompositeGoal;
74
+ type AdaptiveProps = {
75
+ id: string;
76
+ variants: Record<string, ReactNode>;
77
+ goal: string | GoalConfig;
78
+ /**
79
+ * When true, renders nothing during SSR and before client hydration.
80
+ * Use when you cannot pass `initialAssignments` and prefer a blank slot over
81
+ * a hydration mismatch. Tradeoff: minor CLS on first paint.
82
+ */
83
+ clientOnly?: boolean;
84
+ };
85
+ declare function AdaptiveImpl(props: AdaptiveProps): JSX.Element | null;
86
+ /** Re-renders only when the chosen variant changes. */
87
+ declare const Adaptive: react.MemoExoticComponent<typeof AdaptiveImpl>;
88
+
89
+ declare global {
90
+ interface Window {
91
+ __sentient_overrides?: Record<string, string>;
92
+ }
93
+ }
94
+ type AssignmentState = {
95
+ variantId: string | null;
96
+ isLoading: boolean;
97
+ };
98
+ /**
99
+ * Returns a sticky variant assignment for a component.
100
+ *
101
+ * First render reads the local SDK cache; if empty, falls back to a
102
+ * deterministic default and asynchronously calls `/v1/assign`. The server
103
+ * picks the actual variant via ε-greedy and the result replaces the fallback
104
+ * on the next render. Subsequent paints read synchronously from cache —
105
+ * no flicker, no loading state after first paint.
106
+ */
107
+ declare function useAssignment(componentId: string, variantIds: string[]): AssignmentState;
108
+
109
+ /** Per-component weights store with isolated subscriptions. */
110
+ type VariantWeight = {
111
+ variantId: string;
112
+ pulls: number;
113
+ avgReward: number;
114
+ };
115
+ type ComponentWeights = {
116
+ componentId: string;
117
+ variants: VariantWeight[];
118
+ updatedAt: number;
119
+ };
120
+ type Listener = (weights: ComponentWeights) => void;
121
+ /**
122
+ * Subscribes a listener to a single component. Returns an unsubscribe function.
123
+ * Updates to other components never trigger this listener.
124
+ */
125
+ declare function subscribe(componentId: string, cb: Listener): () => void;
126
+ /**
127
+ * Replaces the weights for a component and notifies only that component's
128
+ * subscribers.
129
+ */
130
+ declare function update(componentId: string, weights: ComponentWeights): void;
131
+ /**
132
+ * Returns the latest known weights for a component, or null if none seen.
133
+ */
134
+ declare function getWeights(componentId: string): ComponentWeights | null;
135
+
136
+ export { Adaptive, type AdaptiveProps, AdaptiveProvider, type AdaptiveProviderProps, type AssignmentState, type ClickGoal, type ComponentWeights, type CompositeGoal, type FormSubmitGoal, type GoalConfig, type ScrollDepthGoal, type SsrFallback, type VariantWeight, getWeights, subscribe as subscribeWeights, update as updateWeights, useAssignment, useInitialAssignments, useSentient };
@@ -0,0 +1,136 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+ import { SentientConfig, SentientClient } from '@sentientui/core';
4
+ export { deriveSessionSegment as detectSegment } from '@sentientui/core';
5
+
6
+ /** How to render adaptive slots during SSR when assignments are not preloaded. */
7
+ type SsrFallback = 'first' | 'none';
8
+ type AdaptiveProviderProps = {
9
+ apiKey: string;
10
+ context: SentientConfig['context'];
11
+ ingestUrl: string;
12
+ debug?: boolean;
13
+ /**
14
+ * SSR-preloaded assignments from `preloadAssignments()` / `loadAdaptiveAssignments()`.
15
+ * Passed through to `useAssignment` as synchronous initial state so crawlers and
16
+ * the first paint see real content (recommended for SEO).
17
+ */
18
+ initialAssignments?: Record<string, string>;
19
+ /**
20
+ * Bandit segment from SSR (`device:source`). Keeps cache, assign, and worker
21
+ * weights on one row — must match `loadAdaptiveAssignments` / session upsert.
22
+ */
23
+ sessionSegment?: string;
24
+ /**
25
+ * When no `initialAssignments` exist for a component, `'first'` renders
26
+ * `variantIds[0]` in server HTML (safe default for SEO). Use `'none'` only for
27
+ * decorative slots marked `clientOnly`.
28
+ * @default 'first'
29
+ */
30
+ ssrFallback?: SsrFallback;
31
+ /**
32
+ * Consent gate. When `false` the SDK is not initialised and no events are
33
+ * sent. Flip to `true` (e.g. after the user accepts the cookie banner) to
34
+ * initialise and begin tracking.
35
+ */
36
+ consent?: boolean;
37
+ /**
38
+ * Called once per component the first time a variant is resolved for that
39
+ * component in this session. Use to forward assignments to your own analytics
40
+ * (Mixpanel, PostHog, Segment, etc.) without having to wrap `useAssignment`.
41
+ */
42
+ onAssignment?: (componentId: string, variantId: string) => void;
43
+ children: ReactNode;
44
+ };
45
+ /**
46
+ * Initialises the Sentient core SDK in a useEffect (SSR-safe) and exposes the
47
+ * client via React context. Re-initialises when `consent` changes.
48
+ */
49
+ declare function AdaptiveProvider(props: AdaptiveProviderProps): JSX.Element;
50
+ /**
51
+ * Returns the SentientClient, or null until the provider has finished
52
+ * initialising on the client.
53
+ */
54
+ declare function useSentient(): SentientClient | null;
55
+ /** Internal: SSR-preloaded assignments for hydration-safe first render. */
56
+ declare function useInitialAssignments(): Record<string, string>;
57
+
58
+ type ScrollDepthGoal = {
59
+ type: 'scroll_depth';
60
+ threshold: number;
61
+ };
62
+ type ClickGoal = {
63
+ type: 'click';
64
+ selector?: string;
65
+ };
66
+ type FormSubmitGoal = {
67
+ type: 'form_submit';
68
+ };
69
+ type CompositeGoal = {
70
+ type: 'composite';
71
+ all: GoalConfig[];
72
+ };
73
+ type GoalConfig = ScrollDepthGoal | ClickGoal | FormSubmitGoal | CompositeGoal;
74
+ type AdaptiveProps = {
75
+ id: string;
76
+ variants: Record<string, ReactNode>;
77
+ goal: string | GoalConfig;
78
+ /**
79
+ * When true, renders nothing during SSR and before client hydration.
80
+ * Use when you cannot pass `initialAssignments` and prefer a blank slot over
81
+ * a hydration mismatch. Tradeoff: minor CLS on first paint.
82
+ */
83
+ clientOnly?: boolean;
84
+ };
85
+ declare function AdaptiveImpl(props: AdaptiveProps): JSX.Element | null;
86
+ /** Re-renders only when the chosen variant changes. */
87
+ declare const Adaptive: react.MemoExoticComponent<typeof AdaptiveImpl>;
88
+
89
+ declare global {
90
+ interface Window {
91
+ __sentient_overrides?: Record<string, string>;
92
+ }
93
+ }
94
+ type AssignmentState = {
95
+ variantId: string | null;
96
+ isLoading: boolean;
97
+ };
98
+ /**
99
+ * Returns a sticky variant assignment for a component.
100
+ *
101
+ * First render reads the local SDK cache; if empty, falls back to a
102
+ * deterministic default and asynchronously calls `/v1/assign`. The server
103
+ * picks the actual variant via ε-greedy and the result replaces the fallback
104
+ * on the next render. Subsequent paints read synchronously from cache —
105
+ * no flicker, no loading state after first paint.
106
+ */
107
+ declare function useAssignment(componentId: string, variantIds: string[]): AssignmentState;
108
+
109
+ /** Per-component weights store with isolated subscriptions. */
110
+ type VariantWeight = {
111
+ variantId: string;
112
+ pulls: number;
113
+ avgReward: number;
114
+ };
115
+ type ComponentWeights = {
116
+ componentId: string;
117
+ variants: VariantWeight[];
118
+ updatedAt: number;
119
+ };
120
+ type Listener = (weights: ComponentWeights) => void;
121
+ /**
122
+ * Subscribes a listener to a single component. Returns an unsubscribe function.
123
+ * Updates to other components never trigger this listener.
124
+ */
125
+ declare function subscribe(componentId: string, cb: Listener): () => void;
126
+ /**
127
+ * Replaces the weights for a component and notifies only that component's
128
+ * subscribers.
129
+ */
130
+ declare function update(componentId: string, weights: ComponentWeights): void;
131
+ /**
132
+ * Returns the latest known weights for a component, or null if none seen.
133
+ */
134
+ declare function getWeights(componentId: string): ComponentWeights | null;
135
+
136
+ export { Adaptive, type AdaptiveProps, AdaptiveProvider, type AdaptiveProviderProps, type AssignmentState, type ClickGoal, type ComponentWeights, type CompositeGoal, type FormSubmitGoal, type GoalConfig, type ScrollDepthGoal, type SsrFallback, type VariantWeight, getWeights, subscribe as subscribeWeights, update as updateWeights, useAssignment, useInitialAssignments, useSentient };