@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.
- package/dist/index.d.cts +136 -0
- package/dist/index.d.ts +136 -0
- package/dist/index.js +454 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +420 -0
- package/dist/index.mjs.map +1 -0
- package/dist/next/adaptive-root-client.d.ts +50 -0
- package/dist/next/adaptive-root-client.js +82 -0
- package/dist/next/adaptive-root-client.js.map +1 -0
- package/dist/next/adaptive-root.d.ts +94 -0
- package/dist/next/adaptive-root.js +105 -0
- package/dist/next/adaptive-root.js.map +1 -0
- package/dist/server.d.cts +35 -0
- package/dist/server.d.ts +35 -0
- package/dist/server.js +52 -0
- package/dist/server.js.map +1 -0
- package/dist/server.mjs +28 -0
- package/dist/server.mjs.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { SentientConfig, ServerAssignments } from '@sentientui/core';
|
|
3
|
+
|
|
4
|
+
/** How to render adaptive slots during SSR when assignments are not preloaded. */
|
|
5
|
+
type SsrFallback = 'first' | 'none';
|
|
6
|
+
type AdaptiveProviderProps = {
|
|
7
|
+
apiKey: string;
|
|
8
|
+
context: SentientConfig['context'];
|
|
9
|
+
ingestUrl: string;
|
|
10
|
+
debug?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* SSR-preloaded assignments from `preloadAssignments()` / `loadAdaptiveAssignments()`.
|
|
13
|
+
* Passed through to `useAssignment` as synchronous initial state so crawlers and
|
|
14
|
+
* the first paint see real content (recommended for SEO).
|
|
15
|
+
*/
|
|
16
|
+
initialAssignments?: Record<string, string>;
|
|
17
|
+
/**
|
|
18
|
+
* Bandit segment from SSR (`device:source`). Keeps cache, assign, and worker
|
|
19
|
+
* weights on one row — must match `loadAdaptiveAssignments` / session upsert.
|
|
20
|
+
*/
|
|
21
|
+
sessionSegment?: string;
|
|
22
|
+
/**
|
|
23
|
+
* When no `initialAssignments` exist for a component, `'first'` renders
|
|
24
|
+
* `variantIds[0]` in server HTML (safe default for SEO). Use `'none'` only for
|
|
25
|
+
* decorative slots marked `clientOnly`.
|
|
26
|
+
* @default 'first'
|
|
27
|
+
*/
|
|
28
|
+
ssrFallback?: SsrFallback;
|
|
29
|
+
/**
|
|
30
|
+
* Consent gate. When `false` the SDK is not initialised and no events are
|
|
31
|
+
* sent. Flip to `true` (e.g. after the user accepts the cookie banner) to
|
|
32
|
+
* initialise and begin tracking.
|
|
33
|
+
*/
|
|
34
|
+
consent?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Called once per component the first time a variant is resolved for that
|
|
37
|
+
* component in this session. Use to forward assignments to your own analytics
|
|
38
|
+
* (Mixpanel, PostHog, Segment, etc.) without having to wrap `useAssignment`.
|
|
39
|
+
*/
|
|
40
|
+
onAssignment?: (componentId: string, variantId: string) => void;
|
|
41
|
+
children: ReactNode;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
type PreloadComponent = {
|
|
45
|
+
id: string;
|
|
46
|
+
variantIds: string[];
|
|
47
|
+
};
|
|
48
|
+
type AdaptiveRootProps = Omit<AdaptiveProviderProps, 'initialAssignments'> & {
|
|
49
|
+
/** Slots to resolve on the server before HTML is sent (SEO-safe). */
|
|
50
|
+
components: PreloadComponent[];
|
|
51
|
+
/** Server-only key for `/v1/sessions` and `/v1/assign` (usually the same `pk_` as `apiKey`). */
|
|
52
|
+
serverApiKey: string;
|
|
53
|
+
/** API base URL without trailing slash, e.g. `https://api.example.com/v1`. */
|
|
54
|
+
apiBaseUrl: string;
|
|
55
|
+
/**
|
|
56
|
+
* App origin for SSR preload requests (must be in the project's `allowed_origins`).
|
|
57
|
+
* @default `http://localhost:3001` in development
|
|
58
|
+
*/
|
|
59
|
+
appOrigin?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Optional preloaded map; when set, `components` is not fetched (useful for tests
|
|
62
|
+
* or custom loaders). Normally omit and let `loadAdaptiveAssignments` run.
|
|
63
|
+
*/
|
|
64
|
+
initialAssignments?: ServerAssignments;
|
|
65
|
+
children: ReactNode;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Server Component wrapper: loads assignments, then renders `AdaptiveProvider`
|
|
69
|
+
* with `initialAssignments` so crawlers and hydration see real variant content.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```tsx
|
|
73
|
+
* // app/layout.tsx
|
|
74
|
+
* import { AdaptiveRoot } from '@sentientui/react/next';
|
|
75
|
+
*
|
|
76
|
+
* export default function Layout({ children }) {
|
|
77
|
+
* return (
|
|
78
|
+
* <AdaptiveRoot
|
|
79
|
+
* components={[{ id: 'hero_cta', variantIds: ['default', 'accent'] }]}
|
|
80
|
+
* serverApiKey={process.env.SENTIENT_API_KEY!}
|
|
81
|
+
* apiBaseUrl={process.env.SENTIENT_API_URL!}
|
|
82
|
+
* apiKey={process.env.NEXT_PUBLIC_SENTIENT_API_KEY!}
|
|
83
|
+
* ingestUrl={process.env.NEXT_PUBLIC_SENTIENT_INGEST_URL!}
|
|
84
|
+
* context="saas"
|
|
85
|
+
* >
|
|
86
|
+
* {children}
|
|
87
|
+
* </AdaptiveRoot>
|
|
88
|
+
* );
|
|
89
|
+
* }
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
declare function AdaptiveRoot(props: AdaptiveRootProps): Promise<JSX.Element>;
|
|
93
|
+
|
|
94
|
+
export { AdaptiveRoot, type AdaptiveRootProps, type PreloadComponent };
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defProps = Object.defineProperties;
|
|
3
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __spreadValues = (a, b) => {
|
|
9
|
+
for (var prop in b || (b = {}))
|
|
10
|
+
if (__hasOwnProp.call(b, prop))
|
|
11
|
+
__defNormalProp(a, prop, b[prop]);
|
|
12
|
+
if (__getOwnPropSymbols)
|
|
13
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
+
if (__propIsEnum.call(b, prop))
|
|
15
|
+
__defNormalProp(a, prop, b[prop]);
|
|
16
|
+
}
|
|
17
|
+
return a;
|
|
18
|
+
};
|
|
19
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
+
var __objRest = (source, exclude) => {
|
|
21
|
+
var target = {};
|
|
22
|
+
for (var prop in source)
|
|
23
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
24
|
+
target[prop] = source[prop];
|
|
25
|
+
if (source != null && __getOwnPropSymbols)
|
|
26
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
27
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
28
|
+
target[prop] = source[prop];
|
|
29
|
+
}
|
|
30
|
+
return target;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// src/next/adaptive-root.tsx
|
|
34
|
+
import { deriveSessionSegment } from "@sentientui/core";
|
|
35
|
+
import { cookies, headers } from "next/headers";
|
|
36
|
+
|
|
37
|
+
// src/server.ts
|
|
38
|
+
import {
|
|
39
|
+
preloadAssignments,
|
|
40
|
+
readSessionCookie
|
|
41
|
+
} from "@sentientui/core";
|
|
42
|
+
function defaultSessionId() {
|
|
43
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
44
|
+
return crypto.randomUUID();
|
|
45
|
+
}
|
|
46
|
+
return `snt-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
47
|
+
}
|
|
48
|
+
async function loadAdaptiveAssignments(components, options) {
|
|
49
|
+
var _a, _b, _c;
|
|
50
|
+
const sessionId = (_c = (_b = readSessionCookie(options.cookies)) != null ? _b : (_a = options.createSessionId) == null ? void 0 : _a.call(options)) != null ? _c : defaultSessionId();
|
|
51
|
+
return preloadAssignments(components, sessionId, {
|
|
52
|
+
apiKey: options.apiKey,
|
|
53
|
+
baseUrl: options.baseUrl,
|
|
54
|
+
origin: options.origin,
|
|
55
|
+
userAgent: options.userAgent,
|
|
56
|
+
referer: options.referer
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// src/next/adaptive-root.tsx
|
|
61
|
+
import { AdaptiveRootClient } from "./adaptive-root-client.js";
|
|
62
|
+
import { jsx } from "react/jsx-runtime";
|
|
63
|
+
async function AdaptiveRoot(props) {
|
|
64
|
+
var _b, _c;
|
|
65
|
+
const _a = props, {
|
|
66
|
+
components,
|
|
67
|
+
serverApiKey,
|
|
68
|
+
apiBaseUrl,
|
|
69
|
+
appOrigin,
|
|
70
|
+
initialAssignments: initialAssignmentsOverride,
|
|
71
|
+
children
|
|
72
|
+
} = _a, providerProps = __objRest(_a, [
|
|
73
|
+
"components",
|
|
74
|
+
"serverApiKey",
|
|
75
|
+
"apiBaseUrl",
|
|
76
|
+
"appOrigin",
|
|
77
|
+
"initialAssignments",
|
|
78
|
+
"children"
|
|
79
|
+
]);
|
|
80
|
+
const headerStore = await headers();
|
|
81
|
+
const resolvedOrigin = appOrigin != null ? appOrigin : "http://localhost:3001";
|
|
82
|
+
const userAgent = (_b = headerStore.get("user-agent")) != null ? _b : void 0;
|
|
83
|
+
const referer = (_c = headerStore.get("referer")) != null ? _c : void 0;
|
|
84
|
+
const sessionSegment = deriveSessionSegment({ userAgent, referer, appOrigin: resolvedOrigin });
|
|
85
|
+
const initialAssignments = initialAssignmentsOverride != null ? initialAssignmentsOverride : await loadAdaptiveAssignments(components, {
|
|
86
|
+
cookies: await cookies(),
|
|
87
|
+
apiKey: serverApiKey,
|
|
88
|
+
baseUrl: apiBaseUrl,
|
|
89
|
+
origin: resolvedOrigin,
|
|
90
|
+
userAgent,
|
|
91
|
+
referer
|
|
92
|
+
});
|
|
93
|
+
return /* @__PURE__ */ jsx(
|
|
94
|
+
AdaptiveRootClient,
|
|
95
|
+
__spreadProps(__spreadValues({}, providerProps), {
|
|
96
|
+
initialAssignments,
|
|
97
|
+
sessionSegment,
|
|
98
|
+
children
|
|
99
|
+
})
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
export {
|
|
103
|
+
AdaptiveRoot
|
|
104
|
+
};
|
|
105
|
+
//# sourceMappingURL=adaptive-root.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/next/adaptive-root.tsx","../../src/server.ts"],"sourcesContent":["import { deriveSessionSegment } from '@sentientui/core';\nimport { cookies, headers } from 'next/headers';\nimport type { ReactNode } from 'react';\nimport type { AdaptiveProviderProps } from '../provider.js';\nimport { loadAdaptiveAssignments, type ServerAssignments } from '../server.js';\nimport { AdaptiveRootClient } from './adaptive-root-client.js';\n\nexport type PreloadComponent = { id: string; variantIds: string[] };\n\nexport type AdaptiveRootProps = Omit<AdaptiveProviderProps, 'initialAssignments'> & {\n /** Slots to resolve on the server before HTML is sent (SEO-safe). */\n components: PreloadComponent[];\n /** Server-only key for `/v1/sessions` and `/v1/assign` (usually the same `pk_` as `apiKey`). */\n serverApiKey: string;\n /** API base URL without trailing slash, e.g. `https://api.example.com/v1`. */\n apiBaseUrl: string;\n /**\n * App origin for SSR preload requests (must be in the project's `allowed_origins`).\n * @default `http://localhost:3001` in development\n */\n appOrigin?: string;\n /**\n * Optional preloaded map; when set, `components` is not fetched (useful for tests\n * or custom loaders). Normally omit and let `loadAdaptiveAssignments` run.\n */\n initialAssignments?: ServerAssignments;\n children: ReactNode;\n};\n\n/**\n * Server Component wrapper: loads assignments, then renders `AdaptiveProvider`\n * with `initialAssignments` so crawlers and hydration see real variant content.\n *\n * @example\n * ```tsx\n * // app/layout.tsx\n * import { AdaptiveRoot } from '@sentientui/react/next';\n *\n * export default function Layout({ children }) {\n * return (\n * <AdaptiveRoot\n * components={[{ id: 'hero_cta', variantIds: ['default', 'accent'] }]}\n * serverApiKey={process.env.SENTIENT_API_KEY!}\n * apiBaseUrl={process.env.SENTIENT_API_URL!}\n * apiKey={process.env.NEXT_PUBLIC_SENTIENT_API_KEY!}\n * ingestUrl={process.env.NEXT_PUBLIC_SENTIENT_INGEST_URL!}\n * context=\"saas\"\n * >\n * {children}\n * </AdaptiveRoot>\n * );\n * }\n * ```\n */\nexport async function AdaptiveRoot(props: AdaptiveRootProps): Promise<JSX.Element> {\n const {\n components,\n serverApiKey,\n apiBaseUrl,\n appOrigin,\n initialAssignments: initialAssignmentsOverride,\n children,\n ...providerProps\n } = props;\n\n const headerStore = await headers();\n const resolvedOrigin = appOrigin ?? 'http://localhost:3001';\n const userAgent = headerStore.get('user-agent') ?? undefined;\n const referer = headerStore.get('referer') ?? undefined;\n const sessionSegment = deriveSessionSegment({ userAgent, referer, appOrigin: resolvedOrigin });\n const initialAssignments =\n initialAssignmentsOverride ??\n (await loadAdaptiveAssignments(components, {\n cookies: await cookies(),\n apiKey: serverApiKey,\n baseUrl: apiBaseUrl,\n origin: resolvedOrigin,\n userAgent,\n referer,\n }));\n\n return (\n <AdaptiveRootClient\n {...providerProps}\n initialAssignments={initialAssignments}\n sessionSegment={sessionSegment}\n >\n {children}\n </AdaptiveRootClient>\n );\n}\n","/**\n * Server-only helpers for Next.js / SSR. No React or DOM APIs.\n */\nimport {\n preloadAssignments,\n readSessionCookie,\n type ServerAssignConfig,\n type ServerAssignments,\n} from '@sentientui/core';\n\nexport { preloadAssignments, readSessionCookie };\nexport type { ServerAssignConfig, ServerAssignments };\n\nexport type LoadAdaptiveAssignmentsOptions = {\n /** Next.js `cookies()` return value, or any object with `get(name)`. */\n cookies: { get(name: string): { value: string } | undefined };\n apiKey: string;\n baseUrl: string;\n /** Used when `_snt_uid` is absent (e.g. first visit, many crawlers). */\n createSessionId?: () => string;\n /** Must match a value in the project's `allowed_origins` (e.g. `http://localhost:3001`). */\n origin?: string;\n /** From Next.js `headers().get('user-agent')` — aligns SSR segment with the client. */\n userAgent?: string;\n /** From Next.js `headers().get('referer')`. */\n referer?: string;\n};\n\nfunction defaultSessionId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n return `snt-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;\n}\n\n/**\n * Fetches bandit assignments on the server for SEO-safe HTML.\n * Pass the result as `initialAssignments` on `<AdaptiveProvider>`.\n */\nexport async function loadAdaptiveAssignments(\n components: Array<{ id: string; variantIds: string[] }>,\n options: LoadAdaptiveAssignmentsOptions,\n): Promise<ServerAssignments> {\n const sessionId =\n readSessionCookie(options.cookies) ??\n options.createSessionId?.() ??\n defaultSessionId();\n\n return preloadAssignments(components, sessionId, {\n apiKey: options.apiKey,\n baseUrl: options.baseUrl,\n origin: options.origin,\n userAgent: options.userAgent,\n referer: options.referer,\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,4BAA4B;AACrC,SAAS,SAAS,eAAe;;;ACEjC;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAoBP,SAAS,mBAA2B;AAClC,MAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAAY;AAC5E,WAAO,OAAO,WAAW;AAAA,EAC3B;AACA,SAAO,OAAO,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC;AACrE;AAMA,eAAsB,wBACpB,YACA,SAC4B;AA1C9B;AA2CE,QAAM,aACJ,6BAAkB,QAAQ,OAAO,MAAjC,aACA,aAAQ,oBAAR,qCADA,YAEA,iBAAiB;AAEnB,SAAO,mBAAmB,YAAY,WAAW;AAAA,IAC/C,QAAQ,QAAQ;AAAA,IAChB,SAAS,QAAQ;AAAA,IACjB,QAAQ,QAAQ;AAAA,IAChB,WAAW,QAAQ;AAAA,IACnB,SAAS,QAAQ;AAAA,EACnB,CAAC;AACH;;;ADlDA,SAAS,0BAA0B;AA6E/B;AA5BJ,eAAsB,aAAa,OAAgD;AAtDnF;AAuDE,QAQI,YAPF;AAAA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,oBAAoB;AAAA,IACpB;AAAA,EA7DJ,IA+DM,IADC,0BACD,IADC;AAAA,IANH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAIF,QAAM,cAAc,MAAM,QAAQ;AAClC,QAAM,iBAAiB,gCAAa;AACpC,QAAM,aAAY,iBAAY,IAAI,YAAY,MAA5B,YAAiC;AACnD,QAAM,WAAU,iBAAY,IAAI,SAAS,MAAzB,YAA8B;AAC9C,QAAM,iBAAiB,qBAAqB,EAAE,WAAW,SAAS,WAAW,eAAe,CAAC;AAC7F,QAAM,qBACJ,kEACC,MAAM,wBAAwB,YAAY;AAAA,IACzC,SAAS,MAAM,QAAQ;AAAA,IACvB,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,EACF,CAAC;AAEH,SACE;AAAA,IAAC;AAAA,qCACK,gBADL;AAAA,MAEC;AAAA,MACA;AAAA,MAEC;AAAA;AAAA,EACH;AAEJ;","names":[]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ServerAssignments } from '@sentientui/core';
|
|
2
|
+
export { ServerAssignConfig, ServerAssignments, preloadAssignments, readSessionCookie } from '@sentientui/core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Server-only helpers for Next.js / SSR. No React or DOM APIs.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
type LoadAdaptiveAssignmentsOptions = {
|
|
9
|
+
/** Next.js `cookies()` return value, or any object with `get(name)`. */
|
|
10
|
+
cookies: {
|
|
11
|
+
get(name: string): {
|
|
12
|
+
value: string;
|
|
13
|
+
} | undefined;
|
|
14
|
+
};
|
|
15
|
+
apiKey: string;
|
|
16
|
+
baseUrl: string;
|
|
17
|
+
/** Used when `_snt_uid` is absent (e.g. first visit, many crawlers). */
|
|
18
|
+
createSessionId?: () => string;
|
|
19
|
+
/** Must match a value in the project's `allowed_origins` (e.g. `http://localhost:3001`). */
|
|
20
|
+
origin?: string;
|
|
21
|
+
/** From Next.js `headers().get('user-agent')` — aligns SSR segment with the client. */
|
|
22
|
+
userAgent?: string;
|
|
23
|
+
/** From Next.js `headers().get('referer')`. */
|
|
24
|
+
referer?: string;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Fetches bandit assignments on the server for SEO-safe HTML.
|
|
28
|
+
* Pass the result as `initialAssignments` on `<AdaptiveProvider>`.
|
|
29
|
+
*/
|
|
30
|
+
declare function loadAdaptiveAssignments(components: Array<{
|
|
31
|
+
id: string;
|
|
32
|
+
variantIds: string[];
|
|
33
|
+
}>, options: LoadAdaptiveAssignmentsOptions): Promise<ServerAssignments>;
|
|
34
|
+
|
|
35
|
+
export { type LoadAdaptiveAssignmentsOptions, loadAdaptiveAssignments };
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ServerAssignments } from '@sentientui/core';
|
|
2
|
+
export { ServerAssignConfig, ServerAssignments, preloadAssignments, readSessionCookie } from '@sentientui/core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Server-only helpers for Next.js / SSR. No React or DOM APIs.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
type LoadAdaptiveAssignmentsOptions = {
|
|
9
|
+
/** Next.js `cookies()` return value, or any object with `get(name)`. */
|
|
10
|
+
cookies: {
|
|
11
|
+
get(name: string): {
|
|
12
|
+
value: string;
|
|
13
|
+
} | undefined;
|
|
14
|
+
};
|
|
15
|
+
apiKey: string;
|
|
16
|
+
baseUrl: string;
|
|
17
|
+
/** Used when `_snt_uid` is absent (e.g. first visit, many crawlers). */
|
|
18
|
+
createSessionId?: () => string;
|
|
19
|
+
/** Must match a value in the project's `allowed_origins` (e.g. `http://localhost:3001`). */
|
|
20
|
+
origin?: string;
|
|
21
|
+
/** From Next.js `headers().get('user-agent')` — aligns SSR segment with the client. */
|
|
22
|
+
userAgent?: string;
|
|
23
|
+
/** From Next.js `headers().get('referer')`. */
|
|
24
|
+
referer?: string;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Fetches bandit assignments on the server for SEO-safe HTML.
|
|
28
|
+
* Pass the result as `initialAssignments` on `<AdaptiveProvider>`.
|
|
29
|
+
*/
|
|
30
|
+
declare function loadAdaptiveAssignments(components: Array<{
|
|
31
|
+
id: string;
|
|
32
|
+
variantIds: string[];
|
|
33
|
+
}>, options: LoadAdaptiveAssignmentsOptions): Promise<ServerAssignments>;
|
|
34
|
+
|
|
35
|
+
export { type LoadAdaptiveAssignmentsOptions, loadAdaptiveAssignments };
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/server.ts
|
|
21
|
+
var server_exports = {};
|
|
22
|
+
__export(server_exports, {
|
|
23
|
+
loadAdaptiveAssignments: () => loadAdaptiveAssignments,
|
|
24
|
+
preloadAssignments: () => import_core.preloadAssignments,
|
|
25
|
+
readSessionCookie: () => import_core.readSessionCookie
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(server_exports);
|
|
28
|
+
var import_core = require("@sentientui/core");
|
|
29
|
+
function defaultSessionId() {
|
|
30
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
31
|
+
return crypto.randomUUID();
|
|
32
|
+
}
|
|
33
|
+
return `snt-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
34
|
+
}
|
|
35
|
+
async function loadAdaptiveAssignments(components, options) {
|
|
36
|
+
var _a, _b, _c;
|
|
37
|
+
const sessionId = (_c = (_b = (0, import_core.readSessionCookie)(options.cookies)) != null ? _b : (_a = options.createSessionId) == null ? void 0 : _a.call(options)) != null ? _c : defaultSessionId();
|
|
38
|
+
return (0, import_core.preloadAssignments)(components, sessionId, {
|
|
39
|
+
apiKey: options.apiKey,
|
|
40
|
+
baseUrl: options.baseUrl,
|
|
41
|
+
origin: options.origin,
|
|
42
|
+
userAgent: options.userAgent,
|
|
43
|
+
referer: options.referer
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
47
|
+
0 && (module.exports = {
|
|
48
|
+
loadAdaptiveAssignments,
|
|
49
|
+
preloadAssignments,
|
|
50
|
+
readSessionCookie
|
|
51
|
+
});
|
|
52
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server.ts"],"sourcesContent":["/**\n * Server-only helpers for Next.js / SSR. No React or DOM APIs.\n */\nimport {\n preloadAssignments,\n readSessionCookie,\n type ServerAssignConfig,\n type ServerAssignments,\n} from '@sentientui/core';\n\nexport { preloadAssignments, readSessionCookie };\nexport type { ServerAssignConfig, ServerAssignments };\n\nexport type LoadAdaptiveAssignmentsOptions = {\n /** Next.js `cookies()` return value, or any object with `get(name)`. */\n cookies: { get(name: string): { value: string } | undefined };\n apiKey: string;\n baseUrl: string;\n /** Used when `_snt_uid` is absent (e.g. first visit, many crawlers). */\n createSessionId?: () => string;\n /** Must match a value in the project's `allowed_origins` (e.g. `http://localhost:3001`). */\n origin?: string;\n /** From Next.js `headers().get('user-agent')` — aligns SSR segment with the client. */\n userAgent?: string;\n /** From Next.js `headers().get('referer')`. */\n referer?: string;\n};\n\nfunction defaultSessionId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n return `snt-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;\n}\n\n/**\n * Fetches bandit assignments on the server for SEO-safe HTML.\n * Pass the result as `initialAssignments` on `<AdaptiveProvider>`.\n */\nexport async function loadAdaptiveAssignments(\n components: Array<{ id: string; variantIds: string[] }>,\n options: LoadAdaptiveAssignmentsOptions,\n): Promise<ServerAssignments> {\n const sessionId =\n readSessionCookie(options.cookies) ??\n options.createSessionId?.() ??\n defaultSessionId();\n\n return preloadAssignments(components, sessionId, {\n apiKey: options.apiKey,\n baseUrl: options.baseUrl,\n origin: options.origin,\n userAgent: options.userAgent,\n referer: options.referer,\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAKO;AAoBP,SAAS,mBAA2B;AAClC,MAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAAY;AAC5E,WAAO,OAAO,WAAW;AAAA,EAC3B;AACA,SAAO,OAAO,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC;AACrE;AAMA,eAAsB,wBACpB,YACA,SAC4B;AA1C9B;AA2CE,QAAM,aACJ,8CAAkB,QAAQ,OAAO,MAAjC,aACA,aAAQ,oBAAR,qCADA,YAEA,iBAAiB;AAEnB,aAAO,gCAAmB,YAAY,WAAW;AAAA,IAC/C,QAAQ,QAAQ;AAAA,IAChB,SAAS,QAAQ;AAAA,IACjB,QAAQ,QAAQ;AAAA,IAChB,WAAW,QAAQ;AAAA,IACnB,SAAS,QAAQ;AAAA,EACnB,CAAC;AACH;","names":[]}
|
package/dist/server.mjs
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// src/server.ts
|
|
2
|
+
import {
|
|
3
|
+
preloadAssignments,
|
|
4
|
+
readSessionCookie
|
|
5
|
+
} from "@sentientui/core";
|
|
6
|
+
function defaultSessionId() {
|
|
7
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
8
|
+
return crypto.randomUUID();
|
|
9
|
+
}
|
|
10
|
+
return `snt-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
11
|
+
}
|
|
12
|
+
async function loadAdaptiveAssignments(components, options) {
|
|
13
|
+
var _a, _b, _c;
|
|
14
|
+
const sessionId = (_c = (_b = readSessionCookie(options.cookies)) != null ? _b : (_a = options.createSessionId) == null ? void 0 : _a.call(options)) != null ? _c : defaultSessionId();
|
|
15
|
+
return preloadAssignments(components, sessionId, {
|
|
16
|
+
apiKey: options.apiKey,
|
|
17
|
+
baseUrl: options.baseUrl,
|
|
18
|
+
origin: options.origin,
|
|
19
|
+
userAgent: options.userAgent,
|
|
20
|
+
referer: options.referer
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
loadAdaptiveAssignments,
|
|
25
|
+
preloadAssignments,
|
|
26
|
+
readSessionCookie
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=server.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server.ts"],"sourcesContent":["/**\n * Server-only helpers for Next.js / SSR. No React or DOM APIs.\n */\nimport {\n preloadAssignments,\n readSessionCookie,\n type ServerAssignConfig,\n type ServerAssignments,\n} from '@sentientui/core';\n\nexport { preloadAssignments, readSessionCookie };\nexport type { ServerAssignConfig, ServerAssignments };\n\nexport type LoadAdaptiveAssignmentsOptions = {\n /** Next.js `cookies()` return value, or any object with `get(name)`. */\n cookies: { get(name: string): { value: string } | undefined };\n apiKey: string;\n baseUrl: string;\n /** Used when `_snt_uid` is absent (e.g. first visit, many crawlers). */\n createSessionId?: () => string;\n /** Must match a value in the project's `allowed_origins` (e.g. `http://localhost:3001`). */\n origin?: string;\n /** From Next.js `headers().get('user-agent')` — aligns SSR segment with the client. */\n userAgent?: string;\n /** From Next.js `headers().get('referer')`. */\n referer?: string;\n};\n\nfunction defaultSessionId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n return `snt-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;\n}\n\n/**\n * Fetches bandit assignments on the server for SEO-safe HTML.\n * Pass the result as `initialAssignments` on `<AdaptiveProvider>`.\n */\nexport async function loadAdaptiveAssignments(\n components: Array<{ id: string; variantIds: string[] }>,\n options: LoadAdaptiveAssignmentsOptions,\n): Promise<ServerAssignments> {\n const sessionId =\n readSessionCookie(options.cookies) ??\n options.createSessionId?.() ??\n defaultSessionId();\n\n return preloadAssignments(components, sessionId, {\n apiKey: options.apiKey,\n baseUrl: options.baseUrl,\n origin: options.origin,\n userAgent: options.userAgent,\n referer: options.referer,\n });\n}\n"],"mappings":";AAGA;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAoBP,SAAS,mBAA2B;AAClC,MAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAAY;AAC5E,WAAO,OAAO,WAAW;AAAA,EAC3B;AACA,SAAO,OAAO,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC;AACrE;AAMA,eAAsB,wBACpB,YACA,SAC4B;AA1C9B;AA2CE,QAAM,aACJ,6BAAkB,QAAQ,OAAO,MAAjC,aACA,aAAQ,oBAAR,qCADA,YAEA,iBAAiB;AAEnB,SAAO,mBAAmB,YAAY,WAAW;AAAA,IAC/C,QAAQ,QAAQ;AAAA,IAChB,SAAS,QAAQ;AAAA,IACjB,QAAQ,QAAQ;AAAA,IAChB,WAAW,QAAQ;AAAA,IACnB,SAAS,QAAQ;AAAA,EACnB,CAAC;AACH;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sentientui/react",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.mjs",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.mjs",
|
|
13
|
+
"require": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./server": {
|
|
16
|
+
"types": "./dist/server.d.ts",
|
|
17
|
+
"import": "./dist/server.mjs",
|
|
18
|
+
"require": "./dist/server.js"
|
|
19
|
+
},
|
|
20
|
+
"./next": {
|
|
21
|
+
"types": "./dist/next/adaptive-root.d.ts",
|
|
22
|
+
"import": "./dist/next/adaptive-root.js",
|
|
23
|
+
"default": "./dist/next/adaptive-root.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist"
|
|
28
|
+
],
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@sentientui/core": "0.1.0"
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"react": ">=18.0.0",
|
|
34
|
+
"next": ">=14.0.0"
|
|
35
|
+
},
|
|
36
|
+
"peerDependenciesMeta": {
|
|
37
|
+
"next": {
|
|
38
|
+
"optional": true
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@testing-library/react": "^16.1.0",
|
|
43
|
+
"@types/react": "^18.3.12",
|
|
44
|
+
"jsdom": "^25.0.1",
|
|
45
|
+
"react": "^18.3.1",
|
|
46
|
+
"react-dom": "^18.3.1",
|
|
47
|
+
"tsup": "^8.3.5",
|
|
48
|
+
"tsx": "^4.19.2",
|
|
49
|
+
"typescript": "^5.7.2",
|
|
50
|
+
"vitest": "^2.1.8"
|
|
51
|
+
},
|
|
52
|
+
"scripts": {
|
|
53
|
+
"build": "tsup",
|
|
54
|
+
"test": "vitest run",
|
|
55
|
+
"typecheck": "tsc --noEmit -p tsconfig.typecheck.json",
|
|
56
|
+
"size-check": "tsx scripts/size-check.ts",
|
|
57
|
+
"lint": "eslint src"
|
|
58
|
+
}
|
|
59
|
+
}
|