@sentientui/core 0.11.0 → 0.11.2

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/README.md CHANGED
@@ -42,11 +42,15 @@ client.goal('trial_started', { plan: 'pro' });
42
42
  | Option | Type | Description |
43
43
  |--------|------|-------------|
44
44
  | `apiKey` | `string` | Public API key (`pk_…`) from the SentientUI dashboard. |
45
- | `context` | `'landing' \| 'ecommerce' \| 'saas' \| 'marketplace'` | Type of product. Used for segment weighting and analytics grouping. |
46
- | `consent` | `boolean` *(default `true`)* | When `false`, returns a no-op client (no cookies, no events). |
47
- | `initialAssignments` | `Record<string, string>` | SSR-preloaded assignments. Seeds the cache so `assign()` returns immediately for listed components. |
45
+ | `context` | `'landing' \| 'ecommerce' \| 'saas' \| 'marketplace'` | Local label only — echoed in `debug` logs, never sent to the server. Analytics grouping comes from the project's context type configured in the dashboard. |
46
+ | `consent` | `boolean` *(default `true`)* | When `false`, returns a no-op client (no cookies, no events). **The default is `true`** — for GDPR-style opt-in, pass `false` until your banner is accepted (see `preConsentBehavior`). |
47
+ | `preConsentBehavior` | `'defaults' \| 'statistical_winner'` | What to render while `consent` is `false`: site defaults, or the read-only statistical winner via `/v1/winner` (no session, no events). |
48
+ | `respectDoNotTrack` | `boolean` *(default `true`)* | Honors the browser DNT signal — overrides `consent: true` and blocks `grantConsent()`. |
49
+ | `initialAssignments` | `Record<string, string>` | SSR-preloaded assignments. Seeds the cache so `assign()` returns without a network call for listed code variants. (Managed-text components still fetch once when the seed carries no content.) |
48
50
  | `sessionSegment` | `string` | Segment from SSR (`device:source`). Must match the value used in `preloadAssignments`. |
51
+ | `ssrSessionId` | `string` | Session ID minted during SSR (from `readSessionCookie`) so server and client share one session. |
49
52
  | `userId` | `string` | Optional cross-session identity. Persists portraits across sessions for the same user. |
53
+ | `country` | `string` | ISO 3166-1 alpha-2 country code, if you already know it server-side. |
50
54
  | `debug` | `boolean` | Logs events to the console and exposes `window.__sentient`. |
51
55
  | `localMode` | `'auto' \| boolean` | Keyless local engine. `'auto'` (default) enables it only under the `development` export condition; production builds without a key short-circuit to defaults with one `console.error`. |
52
56
  | `initialSlots` | `Record<string, string \| Record<string, string>>` | SSR-preloaded slot results (from `preloadDecisions`/`loadAdaptiveDecision`). |
@@ -72,7 +76,7 @@ Queues an event for batched ingest. Events flush every 5 s and on `visibilitycha
72
76
 
73
77
  Fires a named goal for the current session. Used for cross-component conversions (e.g. `'trial_started'`, `'purchase_completed'`) where you cannot scope the reward to a single `<Adaptive>`.
74
78
 
75
- - `weight` (0–1, default `1.0`) — partial reward value. Use values < 1 for funnel steps that precede the final conversion. The bandit learns from each step immediately.
79
+ - `weight` (0–1, default `1.0`) — partial reward value. Use values < 1 for funnel steps that precede the final conversion. Step weights are summed (capped at 1.0 per session) and credited when the visit is finalized, about 30 minutes after the visitor goes inactive — not instantly.
76
80
  - `stepIndex` (default `0`) — position in the funnel for analytics grouping.
77
81
 
78
82
  > **Which goal method?** `goal()` is **session-level** — it POSTs to `/v1/goals` with no component/variant, so it appears in funnel charts but **not** the per-variant CVR breakdown. For variant experiments, prefer **`componentGoal()`** (below) or the declarative `<Adaptive goal={…}>` prop, both of which attribute the conversion to the served variant.
@@ -92,7 +96,7 @@ No-ops (with a `debug` warning) if the component has not been assigned yet — r
92
96
 
93
97
  ### `client.identify(userId)`
94
98
 
95
- Attaches a stable user ID to the session. Portraits and cluster assignment carry forward across future sessions for the same `userId`.
99
+ Attaches a stable user ID to the session. On the link, the server copies the highest-reliability portrait from the user's other sessions onto this one, so portraits and cluster assignment carry forward across devices for the same `userId`.
96
100
 
97
101
  ### `client.getAssignment(componentId, segment)`
98
102
 
@@ -100,11 +104,11 @@ Synchronously returns the cached assignment, or `null` if not yet assigned. Use
100
104
 
101
105
  ### `client.getGraph()`
102
106
 
103
- Returns the current `GraphSnapshot` (page nodes captured by the optional graph scanner — see `@sentientui/core/graph`).
107
+ Returns the current `GraphSnapshot` (page nodes captured by the optional graph scanner — see "Optional: graph mode" below). Permanently returns an empty snapshot on the lean client; graph mode must be enabled at `init` time.
104
108
 
105
109
  ### `client.destroy()`
106
110
 
107
- Flushes the event queue and clears session state. Call on page unload if you need a synchronous teardown (the SDK already handles `visibilitychange` automatically).
111
+ Flushes the event queue and **deletes the visitor identity** — the 365-day `_snt_uid` cookie and all local storage. This is a consent-revocation/forget-me teardown, not a page-unload cleanup: calling it on every unload makes each visit a brand-new visitor and defeats "Visit 1 learns, Visit 2 converts". For unload, do nothing — the SDK already flushes on `visibilitychange`/`beforeunload` automatically.
108
112
 
109
113
  ## SSR helpers
110
114
 
@@ -192,20 +196,24 @@ physically contain none of it. Production without a key short-circuits to defaul
192
196
 
193
197
  ## Optional: graph mode
194
198
 
195
- `@sentientui/core/graph` is a separate, tree-shakable entry that activates the DOM scanner and graph sync (component-to-component edges + 2-hop reward propagation). Import it once, on the client, after `init()`:
199
+ `@sentientui/core/graph` is a separate, tree-shakable entry containing the graph-capable client (DOM scanner + graph sync: component-to-component edges + 2-hop reward propagation). A bare `import('@sentientui/core/graph')` has **no effect** — the entry exports its own `init`, which you must call with `graph: true` **instead of** the lean `init`:
196
200
 
197
201
  ```ts
198
- import('@sentientui/core/graph');
202
+ import { init } from '@sentientui/core/graph';
203
+
204
+ const client = init({ apiKey: 'pk_…', context: 'saas', graph: true });
199
205
  ```
200
206
 
201
- The lean bundle stays under 8 KB gzip; graph adds roughly another 8 KB.
207
+ A client created by the lean `init` can never activate graph mode later (`getGraph()` stays empty). The lean bundle is ~8 KB gzip (CI budget: 10 KB); graph adds roughly another 8 KB.
202
208
 
203
209
  > **Using `@sentientui/react`?** Don't import this entry yourself — pass the
204
210
  > `enableGraph` prop to `AdaptiveProvider` / `AdaptiveRoot` instead. The provider
205
211
  > wires the graph-capable `init()` into its single client for you; calling `init`
206
212
  > from this entry alongside the provider would create a second client.
207
213
 
208
- ## Local overrides (development)
214
+ ## Local overrides (development — `@sentientui/react` only)
215
+
216
+ Dev overrides are implemented by the **React SDK**, not this package — `client.assign()` here does not read them. With `@sentientui/react`:
209
217
 
210
218
  ```
211
219
  # URL parameter (stackable)
@@ -215,7 +223,7 @@ https://yourapp.com?sentient_variant=hero_cta:variant_a
215
223
  window.__sentient_overrides = { hero_cta: 'variant_a' };
216
224
  ```
217
225
 
218
- Overrides bypass the bandit entirely — no events recorded.
226
+ While a variant is forced, the React components record nothing — no exposure, no goals, no micro-signals — so the bandit's weights are untouched.
219
227
 
220
228
  ## Docs
221
229
 
package/dist/index.d.cts CHANGED
@@ -187,8 +187,10 @@ type SentientConfig = {
187
187
  debug?: boolean;
188
188
  /**
189
189
  * Pre-seeded assignments from `preloadAssignments()` (SSR).
190
- * Seeds the local cache so `assign()` never makes a network call for listed components,
191
- * guaranteeing server and client render the same variant on first paint.
190
+ * Seeds the local cache so `assign()` returns without a network call for
191
+ * listed code variants, guaranteeing server and client render the same
192
+ * variant on first paint. Managed-text components (assign with no
193
+ * variantIds) still fetch once when the seed carries no content.
192
194
  */
193
195
  initialAssignments?: Record<string, string>;
194
196
  /**
package/dist/index.d.ts CHANGED
@@ -187,8 +187,10 @@ type SentientConfig = {
187
187
  debug?: boolean;
188
188
  /**
189
189
  * Pre-seeded assignments from `preloadAssignments()` (SSR).
190
- * Seeds the local cache so `assign()` never makes a network call for listed components,
191
- * guaranteeing server and client render the same variant on first paint.
190
+ * Seeds the local cache so `assign()` returns without a network call for
191
+ * listed code variants, guaranteeing server and client render the same
192
+ * variant on first paint. Managed-text components (assign with no
193
+ * variantIds) still fetch once when the seed carries no content.
192
194
  */
193
195
  initialAssignments?: Record<string, string>;
194
196
  /**
package/llms.txt CHANGED
@@ -9,7 +9,7 @@
9
9
 
10
10
  ## Install (agent quickstart)
11
11
 
12
- - React app: `npx sentientui init` — detects the framework (Next App/Pages, Vite, Remix, CRA),
12
+ - React app: `npx @sentientui/cli init` — detects the framework (Next App/Pages, Vite, Remix, CRA),
13
13
  installs @sentientui/react, wraps the app with the provider, writes .env.local, scaffolds an
14
14
  example. Works with NO API key (keyless local mode: deterministic simulated decisions).
15
15
  Verify by opening the app with `?sentient_persona=buyer` vs `?sentient_persona=deal_seeker`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentientui/core",
3
- "version": "0.11.0",
3
+ "version": "0.11.2",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",