@picked/client 0.0.1-dev.1785305085063 → 0.0.1-dev.1785908062293
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/.tsbuildinfo +1 -0
- package/dist/api-03c5jvVk.js +38 -0
- package/dist/api-CQxCVIrm.cjs +1 -0
- package/dist/cjs/form/index.js +1 -1
- package/dist/cjs/index.js +2 -2
- package/dist/cjs/plugins/dom-observer/index.js +1 -1
- package/dist/cjs/plugins/dynamic-experiences/index.js +1 -1
- package/dist/cjs/server/index.js +1 -1
- package/dist/docs/explanation/conditions-and-the-logic-engine.md +94 -0
- package/dist/docs/explanation/feature-flag-allocation.md +176 -0
- package/dist/docs/explanation/how-picked-works.md +124 -0
- package/dist/docs/explanation/how-pickedql-works.md +76 -0
- package/dist/docs/explanation/pages-and-flows.md +64 -0
- package/dist/docs/explanation/the-content-model.md +77 -0
- package/dist/docs/explanation/the-two-apis.md +68 -0
- package/dist/docs/explanation/why-server-side-rendering.md +76 -0
- package/dist/docs/explanation/workspaces-and-versions.md +71 -0
- package/dist/docs/how-to/add-a-step-field-or-action.md +43 -0
- package/dist/docs/{pickedql/examples.md → how-to/analytics/index.md} +53 -28
- package/dist/docs/how-to/archive-or-delete-a-workspace.md +46 -0
- package/dist/docs/how-to/authenticate-with-a-magic-link.md +40 -0
- package/dist/docs/how-to/authenticate-with-a-password.md +51 -0
- package/dist/docs/how-to/authenticate-with-an-api-key.md +51 -0
- package/dist/docs/how-to/authenticate-with-oauth.md +40 -0
- package/dist/docs/how-to/build-a-flow.md +83 -0
- package/dist/docs/how-to/connect-the-mcp-server.md +38 -0
- package/dist/docs/how-to/create-a-project.md +29 -0
- package/dist/docs/how-to/create-an-experience.md +42 -0
- package/dist/docs/how-to/create-and-revoke-an-api-key.md +37 -0
- package/dist/docs/how-to/debug-with-the-chrome-extension.md +57 -0
- package/dist/docs/how-to/define-a-page-layout.md +39 -0
- package/dist/docs/how-to/fill-and-publish-a-page.md +50 -0
- package/dist/docs/how-to/install-the-gtm-template.md +84 -0
- package/dist/docs/how-to/install-the-sdk.md +68 -0
- package/dist/docs/how-to/install-the-vite-plugin.md +56 -0
- package/dist/docs/how-to/invite-and-remove-members.md +34 -0
- package/dist/docs/how-to/preview-a-workspace.md +28 -0
- package/dist/docs/how-to/publish-a-workspace.md +30 -0
- package/dist/docs/how-to/read-a-feature-flag.md +101 -0
- package/dist/docs/how-to/register-a-component.md +55 -0
- package/dist/docs/how-to/register-an-action-handler.md +67 -0
- package/dist/docs/how-to/render-a-step-form.md +132 -0
- package/dist/docs/how-to/render-an-unpublished-preview.md +41 -0
- package/dist/docs/how-to/reuse-a-section.md +37 -0
- package/dist/docs/how-to/reuse-a-step-field-or-action.md +28 -0
- package/dist/docs/how-to/roll-back-a-published-version.md +26 -0
- package/dist/docs/how-to/run-an-ab-test.md +49 -0
- package/dist/docs/how-to/run-code-on-a-form-submission.md +125 -0
- package/dist/docs/how-to/server-render-a-page.md +81 -0
- package/dist/docs/how-to/set-a-content-security-policy.md +32 -0
- package/dist/docs/how-to/set-up-mfa.md +69 -0
- package/dist/docs/how-to/upload-and-use-an-asset.mdx +73 -0
- package/dist/docs/how-to/validate-a-field.md +52 -0
- package/dist/docs/how-to/write-a-condition.md +45 -0
- package/dist/docs/how-to/write-a-predicate.md +60 -0
- package/dist/docs/index.md +41 -59
- package/dist/docs/reference/dashboard/actions.mdx +53 -0
- package/dist/docs/reference/dashboard/api-keys.mdx +37 -0
- package/dist/docs/reference/dashboard/conditions.mdx +42 -0
- package/dist/docs/reference/dashboard/content/asset-library.mdx +63 -0
- package/dist/docs/reference/dashboard/content/content-entries.mdx +44 -0
- package/dist/docs/reference/dashboard/content/layouts.mdx +62 -0
- package/dist/docs/reference/dashboard/content/pages.mdx +35 -0
- package/dist/docs/reference/dashboard/content/sections.mdx +28 -0
- package/dist/docs/reference/dashboard/experiences.mdx +51 -0
- package/dist/docs/reference/dashboard/features.mdx +114 -0
- package/dist/docs/reference/dashboard/fields.mdx +100 -0
- package/dist/docs/reference/dashboard/flow-builder/canvas.mdx +58 -0
- package/dist/docs/reference/dashboard/flow-builder/condition-builder.md +57 -0
- package/dist/docs/reference/dashboard/flow-builder/keyboard-shortcuts.md +72 -0
- package/dist/docs/reference/dashboard/flow-builder/nodes.md +63 -0
- package/dist/docs/reference/dashboard/projects.mdx +44 -0
- package/dist/docs/reference/dashboard/reports.mdx +43 -0
- package/dist/docs/reference/dashboard/steps.mdx +37 -0
- package/dist/docs/reference/dashboard/team-management.md +29 -0
- package/dist/docs/reference/dashboard/workspace-versioning.mdx +30 -0
- package/dist/docs/reference/dashboard/workspaces.mdx +76 -0
- package/dist/docs/{delivery-api → reference/delivery-api}/experience-content.md +17 -5
- package/dist/docs/reference/delivery-api/index.md +45 -0
- package/dist/docs/reference/delivery-api/preview-caching-crawling.md +79 -0
- package/dist/docs/{delivery-api → reference/delivery-api}/project-config.md +15 -6
- package/dist/docs/reference/glossary.md +173 -0
- package/dist/docs/reference/management-api/authentication.md +74 -0
- package/dist/docs/{api → reference/management-api}/authorization-and-scopes.md +70 -47
- package/dist/docs/reference/management-api/error-handling.md +233 -0
- package/dist/docs/{api → reference/management-api}/pagination.md +36 -20
- package/dist/docs/reference/pickedql/data-sources.md +174 -0
- package/dist/docs/reference/pickedql/dimensions.md +87 -0
- package/dist/docs/{pickedql → reference/pickedql}/filtering.md +17 -6
- package/dist/docs/reference/pickedql/index.md +18 -0
- package/dist/docs/reference/pickedql/schema.md +172 -0
- package/dist/docs/reference/pickedql/virtual-functions.md +237 -0
- package/dist/docs/reference/sdk/actions.md +30 -0
- package/dist/docs/{sdk → reference/sdk}/conditions.md +15 -5
- package/dist/docs/reference/sdk/content-security-policy.md +21 -0
- package/dist/docs/reference/sdk/experiences.md +51 -0
- package/dist/docs/reference/sdk/features.md +233 -0
- package/dist/docs/reference/sdk/fields.md +209 -0
- package/dist/docs/reference/sdk/index.md +68 -0
- package/dist/docs/{sdk → reference/sdk}/plugins/create-experience.md +25 -34
- package/dist/docs/reference/sdk/plugins/dynamic-experiences.md +74 -0
- package/dist/docs/reference/sdk/plugins/index.md +29 -0
- package/dist/docs/{sdk → reference/sdk}/plugins/window-object.md +6 -0
- package/dist/docs/reference/sdk/predicates.md +43 -0
- package/dist/docs/reference/sdk/ssr/index.md +33 -0
- package/dist/docs/reference/sdk/ssr/rendering-and-hydration.md +103 -0
- package/dist/docs/reference/sdk/ssr/serialize.md +77 -0
- package/dist/docs/reference/sdk/ssr/slots-and-placements.md +59 -0
- package/dist/docs/reference/sdk/steps.md +87 -0
- package/dist/docs/reference/tools/chrome-extension.md +16 -0
- package/dist/docs/reference/tools/image-optimisation-service.md +104 -0
- package/dist/docs/reference/tools/mcp.md +88 -0
- package/dist/docs/reference/tools/vite-plugin.md +88 -0
- package/dist/docs/tutorials/first-api-call.md +228 -0
- package/dist/docs/tutorials/first-experience-in-the-dashboard.mdx +143 -0
- package/dist/docs/tutorials/first-experience.mdx +255 -0
- package/dist/docs/tutorials/first-server-rendered-page.mdx +186 -0
- package/dist/{dom-BwmTHeT7.js → dom-BqcToNL0.js} +1 -3
- package/dist/{dom-CDrHc_j9.cjs → dom-DlLH3FxV.cjs} +1 -1
- package/dist/esm/form/index.js +2 -4
- package/dist/esm/index.js +225 -186
- package/dist/esm/plugins/dom-observer/index.js +1 -1
- package/dist/esm/plugins/dynamic-experiences/index.js +3 -3
- package/dist/esm/preview/index.js +1 -1
- package/dist/esm/server/index.js +33 -31
- package/dist/{experience-instance-DOJShRk5.js → experience-instance-DGk11d8a.js} +3 -3
- package/dist/experience-instance-Dej3P1sE.cjs +1 -0
- package/dist/plugin-CHOVsx7Z.js +287 -0
- package/dist/plugin-DsaGXQHx.cjs +1 -0
- package/dist/{preview-channel-DW9J8t4B.js → preview-channel-CSr96XAo.js} +1 -1
- package/dist/{protocol-DSqOlW2r.js → protocol-C5KkkiZc.js} +1 -1
- package/dist/types/client.d.ts +7 -6
- package/dist/types/data-source/api.d.ts +60 -0
- package/dist/types/data-source/api.d.ts.map +1 -0
- package/dist/types/data-source/provider.d.ts +97 -0
- package/dist/types/data-source/provider.d.ts.map +1 -0
- package/dist/types/entities/action/action.d.ts +5 -4
- package/dist/types/entities/action/action.d.ts.map +1 -1
- package/dist/types/entities/component/component.d.ts +6 -5
- package/dist/types/entities/component/component.d.ts.map +1 -1
- package/dist/types/entities/condition/condition.d.ts +5 -5
- package/dist/types/entities/content/content.d.ts +4 -3
- package/dist/types/entities/experience/experience.d.ts +11 -10
- package/dist/types/entities/experience/experience.d.ts.map +1 -1
- package/dist/types/entities/experience-instance/experience-instance.d.ts +10 -9
- package/dist/types/entities/feature/feature.d.ts +19 -2
- package/dist/types/entities/feature/feature.d.ts.map +1 -1
- package/dist/types/entities/field/field.d.ts +7 -6
- package/dist/types/entities/framework/framework.d.ts +7 -6
- package/dist/types/entities/framework/framework.d.ts.map +1 -1
- package/dist/types/entities/history/history.d.ts +6 -6
- package/dist/types/entities/plugin/plugin.d.ts +3 -2
- package/dist/types/entities/plugin/plugin.d.ts.map +1 -1
- package/dist/types/entities/predicate/predicate.d.ts +4 -3
- package/dist/types/entities/predicate/predicate.d.ts.map +1 -1
- package/dist/types/entities/response/response-validation.d.ts +3 -2
- package/dist/types/entities/response/response.d.ts +12 -11
- package/dist/types/entities/session/session.d.ts +2 -1
- package/dist/types/entities/step/step.d.ts +6 -5
- package/dist/types/exports.d.ts +2 -1
- package/dist/types/exports.d.ts.map +1 -1
- package/dist/types/form/build-responses.d.ts +2 -1
- package/dist/types/form/create-field-evaluator.d.ts +4 -3
- package/dist/types/form/create-field-validation.d.ts +5 -4
- package/dist/types/form/create-form.d.ts +7 -6
- package/dist/types/form/create-submit-pipeline.d.ts +7 -6
- package/dist/types/form/get-step-fields.d.ts +3 -2
- package/dist/types/lifecycle/condition-selection.d.ts +14 -4
- package/dist/types/lifecycle/lifecycle.d.ts +4 -3
- package/dist/types/lifecycle/rules-logic.d.ts +4 -3
- package/dist/types/lifecycle/state-snapshot.d.ts +4 -3
- package/dist/types/picked.d.ts +79 -62
- package/dist/types/picked.d.ts.map +1 -1
- package/dist/types/ping.d.ts +1 -1
- package/dist/types/ping.d.ts.map +1 -1
- package/dist/types/plugins/create-experience/create-experience.d.ts +9 -8
- package/dist/types/plugins/create-experience/create-experience.d.ts.map +1 -1
- package/dist/types/plugins/create-experience/plugin.d.ts +3 -2
- package/dist/types/plugins/create-experience/plugin.d.ts.map +1 -1
- package/dist/types/plugins/create-experience/serialization.d.ts.map +1 -1
- package/dist/types/plugins/dom-observer/plugin.d.ts +1 -1
- package/dist/types/plugins/dynamic-experiences/hash.d.ts +40 -5
- package/dist/types/plugins/dynamic-experiences/hash.d.ts.map +1 -1
- package/dist/types/plugins/dynamic-experiences/index.d.ts +2 -0
- package/dist/types/plugins/dynamic-experiences/index.d.ts.map +1 -1
- package/dist/types/plugins/dynamic-experiences/plugin.d.ts +4 -36
- package/dist/types/plugins/dynamic-experiences/plugin.d.ts.map +1 -1
- package/dist/types/plugins/dynamic-experiences/types.d.ts +42 -11
- package/dist/types/plugins/dynamic-experiences/types.d.ts.map +1 -1
- package/dist/types/plugins/experience-browser-storage/plugin.d.ts +1 -1
- package/dist/types/plugins/experience-browser-storage/plugin.d.ts.map +1 -1
- package/dist/types/plugins/history-browser-storage/plugin.d.ts +1 -1
- package/dist/types/plugins/history-browser-storage/plugin.d.ts.map +1 -1
- package/dist/types/plugins/responses-browser-storage/plugin.d.ts +1 -1
- package/dist/types/plugins/responses-browser-storage/plugin.d.ts.map +1 -1
- package/dist/types/plugins/responses-indexeddb/plugin.d.ts +1 -1
- package/dist/types/plugins/single-page-app/plugin.d.ts +1 -1
- package/dist/types/plugins/single-page-app/plugin.d.ts.map +1 -1
- package/dist/types/plugins/web-components/plugin.d.ts +2 -1
- package/dist/types/plugins/window-object/plugin.d.ts +2 -2
- package/dist/types/preview-channel.d.ts +5 -1
- package/dist/types/preview-receiver/index.d.ts +18 -1
- package/dist/types/preview-receiver/protocol.d.ts +10 -1
- package/dist/types/server/index.d.ts +3 -3
- package/dist/types/server/serialize.d.ts +8 -2
- package/dist/types/server/serialize.d.ts.map +1 -1
- package/dist/types/utils/dom.d.ts +2 -1
- package/dist/types/utils/events.d.ts +6 -6
- package/dist/types/utils/events.d.ts.map +1 -1
- package/dist/types/utils/global-obj.d.ts +1 -1
- package/dist/types/utils/global-obj.d.ts.map +1 -1
- package/dist/types/utils/id.d.ts.map +1 -1
- package/dist/types/utils/logger.d.ts +2 -1
- package/dist/types/utils/logger.d.ts.map +1 -1
- package/dist/types/utils/node-tree/get-next-node-from-action.d.ts +2 -1
- package/dist/types/utils/node-tree/get-next-node-from-condition.d.ts +2 -1
- package/dist/types/utils/node-tree/get-next-node.d.ts +1 -1
- package/dist/types/utils/node-tree/get-next-node.d.ts.map +1 -1
- package/dist/types/utils/node-tree/get-origin-node.d.ts +1 -1
- package/dist/types/utils/node-tree/get-origin-node.d.ts.map +1 -1
- package/dist/types/utils/node-tree/min-max-steps-to-leaf.d.ts +1 -1
- package/dist/types/utils/node-tree/min-max-steps-to-leaf.d.ts.map +1 -1
- package/dist/types/utils/node-tree/min-max-steps-to-origin.d.ts +1 -1
- package/dist/types/utils/node-tree/min-max-steps-to-origin.d.ts.map +1 -1
- package/dist/types/utils/node-tree/next-reachable-step-nodes.d.ts +1 -1
- package/dist/types/utils/node-tree/next-reachable-step-nodes.d.ts.map +1 -1
- package/dist/types/utils/nodes.d.ts +1 -1
- package/dist/types/utils/picked-config.d.ts +2 -1
- package/dist/types/utils/rehydrate-scripts.d.ts +6 -0
- package/dist/types/utils/rehydrate-scripts.d.ts.map +1 -1
- package/dist/types/utils/rules-logic.d.ts +6 -2
- package/dist/types/utils/storage.d.ts +1 -1
- package/dist/types/utils/storage.d.ts.map +1 -1
- package/package.json +22 -23
- package/dist/api-CPL40b7A.js +0 -40
- package/dist/api-Dz5rgRgQ.cjs +0 -1
- package/dist/docs/actions.mdx +0 -78
- package/dist/docs/api/authentication.md +0 -376
- package/dist/docs/api/error-handling.md +0 -211
- package/dist/docs/api/index.md +0 -197
- package/dist/docs/api-keys.mdx +0 -40
- package/dist/docs/chrome-extension.md +0 -51
- package/dist/docs/conditions.mdx +0 -59
- package/dist/docs/content/asset-library.mdx +0 -93
- package/dist/docs/content/content-entries.mdx +0 -30
- package/dist/docs/content/layouts.mdx +0 -70
- package/dist/docs/content/pages.mdx +0 -67
- package/dist/docs/content/sections.mdx +0 -33
- package/dist/docs/delivery-api/index.md +0 -46
- package/dist/docs/delivery-api/preview-caching-crawling.md +0 -59
- package/dist/docs/experiences.mdx +0 -42
- package/dist/docs/features.mdx +0 -58
- package/dist/docs/fields.mdx +0 -79
- package/dist/docs/flow-builder/building-flows.md +0 -61
- package/dist/docs/flow-builder/condition-builder.md +0 -54
- package/dist/docs/flow-builder/keyboard-shortcuts.md +0 -66
- package/dist/docs/flow-builder/nodes.md +0 -43
- package/dist/docs/flow-builder/overview.mdx +0 -50
- package/dist/docs/gtm-template.md +0 -69
- package/dist/docs/guides/build-a-personalized-page.mdx +0 -143
- package/dist/docs/image-optimisation-service.md +0 -80
- package/dist/docs/mcp.md +0 -120
- package/dist/docs/pickedql/data-sources.md +0 -145
- package/dist/docs/pickedql/dimensions.md +0 -65
- package/dist/docs/pickedql/index.md +0 -36
- package/dist/docs/pickedql/schema.md +0 -156
- package/dist/docs/pickedql/virtual-functions.md +0 -204
- package/dist/docs/projects.mdx +0 -37
- package/dist/docs/reports.mdx +0 -18
- package/dist/docs/sdk/actions.md +0 -66
- package/dist/docs/sdk/content-security-policy.md +0 -32
- package/dist/docs/sdk/experiences.md +0 -46
- package/dist/docs/sdk/features.md +0 -212
- package/dist/docs/sdk/fields.md +0 -263
- package/dist/docs/sdk/index.md +0 -83
- package/dist/docs/sdk/plugins/dynamic-experiences.md +0 -58
- package/dist/docs/sdk/plugins/index.md +0 -9
- package/dist/docs/sdk/predicates.md +0 -112
- package/dist/docs/sdk/ssr/index.md +0 -62
- package/dist/docs/sdk/ssr/rendering-and-hydration.md +0 -141
- package/dist/docs/sdk/ssr/serialize.md +0 -86
- package/dist/docs/sdk/ssr/slots-and-placements.md +0 -35
- package/dist/docs/sdk/steps.md +0 -434
- package/dist/docs/steps.mdx +0 -44
- package/dist/docs/team-management.md +0 -40
- package/dist/docs/vite-plugin.md +0 -82
- package/dist/docs/workspace-versioning.mdx +0 -28
- package/dist/docs/workspaces.mdx +0 -102
- package/dist/experience-instance-DurC3pE-.cjs +0 -1
- package/dist/plugin-CFXwbXeM.js +0 -247
- package/dist/plugin-m4qekgtA.cjs +0 -1
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
layout: docs
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Features
|
|
6
|
-
|
|
7
|
-
Define feature flags with a `decide` function that resolves to a bucket value, access results through framework hooks, and invalidate cached decisions by bumping the version.
|
|
8
|
-
|
|
9
|
-
## Defining features
|
|
10
|
-
|
|
11
|
-
Define features when creating the Picked client by passing a `features` object. Each feature requires a unique identifier, a versioning key, a human-readable name, and a `decide` function:
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
import { createClient } from '@picked/client'
|
|
15
|
-
|
|
16
|
-
const client = createClient({
|
|
17
|
-
projectId: 'your-project-id',
|
|
18
|
-
features: {
|
|
19
|
-
'summer-sale': {
|
|
20
|
-
key: 'summer-sale-v1', // Version key - change to invalidate cache
|
|
21
|
-
name: 'Summer Sale Experiment', // Human-readable name for analytics
|
|
22
|
-
decide: async () => {
|
|
23
|
-
// Your decision logic here
|
|
24
|
-
const isEligible = await checkUserEligibility()
|
|
25
|
-
return isEligible // Returns boolean
|
|
26
|
-
},
|
|
27
|
-
storage: 'local', // Optional: 'local' (default) or 'session'
|
|
28
|
-
},
|
|
29
|
-
'homepage-variant': {
|
|
30
|
-
key: 'homepage-test-v2',
|
|
31
|
-
name: 'Homepage A/B Test',
|
|
32
|
-
decide: async () => {
|
|
33
|
-
// Return string for multi-variant tests
|
|
34
|
-
return Math.random() < 0.5 ? 'variant-a' : 'variant-b'
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
})
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Features can also be defined as factory functions for lazy initialization:
|
|
42
|
-
|
|
43
|
-
```ts
|
|
44
|
-
features: {
|
|
45
|
-
'my-feature': () => ({
|
|
46
|
-
key: 'my-feature-v1',
|
|
47
|
-
name: 'My Feature',
|
|
48
|
-
decide: async () => true,
|
|
49
|
-
}),
|
|
50
|
-
}
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
## How features work
|
|
54
|
-
|
|
55
|
-
When a feature is registered, the SDK follows this execution order:
|
|
56
|
-
|
|
57
|
-
1. **Registration**: Features are registered to the Picked client during initialization
|
|
58
|
-
2. **Cache Check**: The SDK checks browser storage (localStorage or sessionStorage) for a previously resolved value using the feature `id` and `key`
|
|
59
|
-
3. **Lazy Evaluation**: If no cached value exists, the `decide` function will be called the first time the feature is accessed
|
|
60
|
-
4. **Storage**: Once resolved, the bucket value is persisted to browser storage for consistency across page loads
|
|
61
|
-
5. **Event Emission**: A `feature_decide` event is fired on the event bus when a feature is resolved for the first time
|
|
62
|
-
|
|
63
|
-
## URL-based overrides
|
|
64
|
-
|
|
65
|
-
You can override feature decisions via URL search parameters for testing purposes:
|
|
66
|
-
|
|
67
|
-
```
|
|
68
|
-
https://example.com?picked-feature=my-feature:true
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Multiple overrides can be specified:
|
|
72
|
-
|
|
73
|
-
```
|
|
74
|
-
https://example.com?picked-feature=my-feature:true&picked-feature=homepage-variant:variant-a
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
The format is `?picked-feature=<feature-id>:<bucket-value>`.
|
|
78
|
-
|
|
79
|
-
This is useful for QA testing specific feature variants without modifying code. The override is persisted in session storage and will be cleared when the browser tab is closed.
|
|
80
|
-
|
|
81
|
-
## Accessing features
|
|
82
|
-
|
|
83
|
-
Once features are defined, you can access their resolved bucket values in your application code. The SDK provides framework-specific hooks and a framework-agnostic event bus for subscribing to feature decisions.
|
|
84
|
-
|
|
85
|
-
:::code-group
|
|
86
|
-
|
|
87
|
-
```ts [Vanilla JS]
|
|
88
|
-
import { createClient } from '@picked/client'
|
|
89
|
-
|
|
90
|
-
const client = createClient({
|
|
91
|
-
/* Create client options here */
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
client.eventBus.subscribe('feature_decide', ({ feature }) => {
|
|
95
|
-
if (feature.id === 'my-feature') {
|
|
96
|
-
console.log(feature) // { id: 'my-feature', bucket: 'control' }
|
|
97
|
-
}
|
|
98
|
-
})
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
```ts [Svelte]
|
|
102
|
-
<script lang="ts">
|
|
103
|
-
import { getFeature } from '@picked/svelte/hooks'
|
|
104
|
-
// Returns an Effector store containing the feature resolver
|
|
105
|
-
const myFeature = getFeature('my-feature')
|
|
106
|
-
</script>
|
|
107
|
-
<!-- $myFeature is a reactive Effector store (see Effector docs for details) -->
|
|
108
|
-
{#if $myFeature()}
|
|
109
|
-
<p>My feature is enabled</p>
|
|
110
|
-
{:else}
|
|
111
|
-
<p>My feature is disabled</p>
|
|
112
|
-
{/if}
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
```ts [React]
|
|
116
|
-
import { useFeature } from '@picked/react/hooks'
|
|
117
|
-
|
|
118
|
-
function MyComponent() {
|
|
119
|
-
// Returns the resolved bucket value for 'my-feature'
|
|
120
|
-
const myFeature = useFeature('my-feature')
|
|
121
|
-
|
|
122
|
-
return (
|
|
123
|
-
<div>
|
|
124
|
-
{myFeature === 'control' && <p>Control variant</p>}
|
|
125
|
-
{myFeature === 'variant-a' && <p>Variant A</p>}
|
|
126
|
-
</div>
|
|
127
|
-
)
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
:::
|
|
133
|
-
|
|
134
|
-
## Using features in experience conditions
|
|
135
|
-
|
|
136
|
-
Features can be used with experience conditions via JSON logic:
|
|
137
|
-
|
|
138
|
-
```ts
|
|
139
|
-
const myExperience = createExperience({
|
|
140
|
-
// ... other config
|
|
141
|
-
condition: {
|
|
142
|
-
and: [
|
|
143
|
-
{
|
|
144
|
-
'==': [
|
|
145
|
-
{
|
|
146
|
-
invoke: {
|
|
147
|
-
var: 'features.summer-sale', // Reference feature by ID
|
|
148
|
-
},
|
|
149
|
-
},
|
|
150
|
-
true, // Check if bucket equals true
|
|
151
|
-
],
|
|
152
|
-
},
|
|
153
|
-
],
|
|
154
|
-
},
|
|
155
|
-
})
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
## Listening to feature decisions
|
|
159
|
-
|
|
160
|
-
Subscribe to the `feature_decide` event to track when features are resolved:
|
|
161
|
-
|
|
162
|
-
```ts
|
|
163
|
-
client.eventBus.subscribe('feature_decide', ({ feature }) => {
|
|
164
|
-
console.log(`Feature "${feature.id}" resolved to bucket:`, feature.bucket)
|
|
165
|
-
// Example output: Feature "summer-sale" resolved to bucket: true
|
|
166
|
-
|
|
167
|
-
// Send to analytics
|
|
168
|
-
analytics.track('Feature Decision', {
|
|
169
|
-
featureId: feature.id,
|
|
170
|
-
bucket: feature.bucket,
|
|
171
|
-
})
|
|
172
|
-
})
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
## Versioning and cache invalidation
|
|
176
|
-
|
|
177
|
-
Feature decisions are cached in browser storage (localStorage or sessionStorage) using a key derived from the feature ID and version. This ensures visitors see a consistent experience across page loads.
|
|
178
|
-
|
|
179
|
-
### How versioning works
|
|
180
|
-
|
|
181
|
-
When you create a feature in the dashboard, it starts at version 1. The SDK uses the version to build the cache key — for example, a feature at version 3 uses the key `v3`. This version is also included in the allocation hash, so it directly affects which variant a visitor is assigned to.
|
|
182
|
-
|
|
183
|
-
### What happens when the version is incremented
|
|
184
|
-
|
|
185
|
-
When you increment a feature's version in the dashboard:
|
|
186
|
-
|
|
187
|
-
1. **Cache keys change.** The old cache entry (e.g., `v3`) no longer matches the new key (`v4`), so the SDK treats the feature as undecided.
|
|
188
|
-
2. **All visitors are re-allocated.** The allocation hash includes the version, so every visitor gets a new hash value and may be assigned to a different variant.
|
|
189
|
-
3. **The `decide` function runs again.** On the next page load, the SDK calls `decide()` fresh and caches the new result.
|
|
190
|
-
|
|
191
|
-
> **Warning:** Incrementing the version re-allocates all visitors, not just new ones. This is irreversible. Only increment when you intentionally want to reset all assignments — for example, after changing traffic allocation weights.
|
|
192
|
-
|
|
193
|
-
### SDK `key` vs dashboard version
|
|
194
|
-
|
|
195
|
-
If you define features statically in the SDK (not loaded from the dashboard), use the `key` field for manual versioning:
|
|
196
|
-
|
|
197
|
-
```ts
|
|
198
|
-
features: {
|
|
199
|
-
'summer-sale': {
|
|
200
|
-
key: 'summer-sale-v2', // Change to invalidate cache
|
|
201
|
-
// ...
|
|
202
|
-
},
|
|
203
|
-
}
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
For features managed through the dashboard, versioning is handled automatically — the dashboard appends the version number to the cache key used by the SDK.
|
|
207
|
-
|
|
208
|
-
## Best practices
|
|
209
|
-
|
|
210
|
-
- **Use `session` storage for temporary tests**: Set `storage: 'session'` for short-lived experiments that shouldn't persist across browser sessions
|
|
211
|
-
- **Keep `decide` functions fast**: The function blocks experience rendering, so avoid heavy computations or slow network calls
|
|
212
|
-
- **Return consistent types**: Don't mix boolean and string returns for the same feature - pick one type and stick with it
|
package/dist/docs/sdk/fields.md
DELETED
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
layout: docs
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Fields
|
|
6
|
-
|
|
7
|
-
Define fields in code with `createField()`, validate input with JSON Logic, and read submitted values through step context.
|
|
8
|
-
|
|
9
|
-
## Defining fields
|
|
10
|
-
|
|
11
|
-
Define fields using `createField()` from the `@picked/client/plugins/create-experience` package. Each field requires a unique identifier, name, type, label, and cardinality:
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
import { createField } from '@picked/client/plugins/create-experience'
|
|
15
|
-
|
|
16
|
-
// Required text input
|
|
17
|
-
export const emailField = createField({
|
|
18
|
-
id: 'email-address',
|
|
19
|
-
name: 'email-address',
|
|
20
|
-
type: 'text',
|
|
21
|
-
label: 'Email Address',
|
|
22
|
-
multiple: false,
|
|
23
|
-
required: true,
|
|
24
|
-
placeholder: 'you@example.com',
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
// Multi-select dropdown with static options
|
|
28
|
-
export const communicationMethods = createField({
|
|
29
|
-
id: 'communication-methods',
|
|
30
|
-
name: 'communication-methods',
|
|
31
|
-
type: 'text',
|
|
32
|
-
label: 'Preferred contact methods',
|
|
33
|
-
multiple: true,
|
|
34
|
-
required: true,
|
|
35
|
-
options: [
|
|
36
|
-
{
|
|
37
|
-
id: 'email',
|
|
38
|
-
label: 'Email',
|
|
39
|
-
value: 'email',
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
id: 'phone',
|
|
43
|
-
label: 'Phone',
|
|
44
|
-
value: 'phone',
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
id: 'sms',
|
|
48
|
-
label: 'SMS',
|
|
49
|
-
value: 'sms',
|
|
50
|
-
},
|
|
51
|
-
],
|
|
52
|
-
})
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
## How fields work
|
|
56
|
-
|
|
57
|
-
When a field is registered and used in an experience:
|
|
58
|
-
|
|
59
|
-
1. **Registration**: Fields are registered to the experience during step creation via `.addField()`
|
|
60
|
-
2. **Condition Evaluation**: If the field has a `condition`, it's evaluated against the current context to determine visibility
|
|
61
|
-
3. **Rendering**: Visible fields are rendered in the experience UI with their label, placeholder, and options
|
|
62
|
-
4. **User Input**: User enters or selects a value, triggering client-side validation if specified
|
|
63
|
-
5. **Storage**: Valid responses are stored in the experience state under `responses[field.name]`
|
|
64
|
-
6. **Reference**: Field values can be referenced in subsequent field conditions, step conditions, or experience logic via `{ var: 'responses.field-name' }`
|
|
65
|
-
|
|
66
|
-
## Field types
|
|
67
|
-
|
|
68
|
-
Fields support four primitive types, `text`, `number`, `boolean` and `object`:
|
|
69
|
-
|
|
70
|
-
```ts
|
|
71
|
-
// Single text input
|
|
72
|
-
const nameField = createField({
|
|
73
|
-
type: 'text',
|
|
74
|
-
multiple: false,
|
|
75
|
-
// ...
|
|
76
|
-
})
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
Provide an `options` array to allow multiple select:
|
|
80
|
-
|
|
81
|
-
```ts
|
|
82
|
-
const nameField = createField({
|
|
83
|
-
type: 'text',
|
|
84
|
-
multiple: true,
|
|
85
|
-
options: [
|
|
86
|
-
{
|
|
87
|
-
id: 'option-one',
|
|
88
|
-
label: 'Option One',
|
|
89
|
-
value: 'product-id-one',
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
id: 'option-two',
|
|
93
|
-
label: 'Option Two',
|
|
94
|
-
value: 'product-id-two',
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
id: 'option-three',
|
|
98
|
-
label: 'Option Three',
|
|
99
|
-
value: 'product-id-three',
|
|
100
|
-
},
|
|
101
|
-
],
|
|
102
|
-
})
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
## Conditions
|
|
106
|
-
|
|
107
|
-
Fields and field options are compatible with condition logic:
|
|
108
|
-
|
|
109
|
-
```ts
|
|
110
|
-
const conditionalField = createField({
|
|
111
|
-
id: 'conditional-field',
|
|
112
|
-
type: 'text',
|
|
113
|
-
condition: {
|
|
114
|
-
invoke: {
|
|
115
|
-
var: 'responses.has-answered-question',
|
|
116
|
-
},
|
|
117
|
-
},
|
|
118
|
-
options: [
|
|
119
|
-
{
|
|
120
|
-
id: 'conditional-option',
|
|
121
|
-
label: 'Conditional Label',
|
|
122
|
-
condition: {
|
|
123
|
-
invoke: {
|
|
124
|
-
var: 'responses.eligible-for-option',
|
|
125
|
-
},
|
|
126
|
-
},
|
|
127
|
-
},
|
|
128
|
-
],
|
|
129
|
-
})
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
## Field validation
|
|
133
|
-
|
|
134
|
-
Validate user input using JSON Logic rules. The `$input` variable contains the current field value:
|
|
135
|
-
|
|
136
|
-
```ts
|
|
137
|
-
const quantityField = createField({
|
|
138
|
-
id: 'quantity',
|
|
139
|
-
name: 'quantity',
|
|
140
|
-
type: 'number',
|
|
141
|
-
label: 'Quantity',
|
|
142
|
-
multiple: false,
|
|
143
|
-
required: true,
|
|
144
|
-
validation: {
|
|
145
|
-
catch: {
|
|
146
|
-
or: [
|
|
147
|
-
{
|
|
148
|
-
and: [
|
|
149
|
-
{
|
|
150
|
-
// Input value is above 0
|
|
151
|
-
'>': [
|
|
152
|
-
{
|
|
153
|
-
var: '$input',
|
|
154
|
-
},
|
|
155
|
-
0,
|
|
156
|
-
],
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
// Input value is equal or below 999
|
|
160
|
-
'<=': [
|
|
161
|
-
{
|
|
162
|
-
var: '$input',
|
|
163
|
-
},
|
|
164
|
-
999,
|
|
165
|
-
],
|
|
166
|
-
},
|
|
167
|
-
],
|
|
168
|
-
},
|
|
169
|
-
{
|
|
170
|
-
throw: 'Please enter a value between 1 and 999',
|
|
171
|
-
},
|
|
172
|
-
],
|
|
173
|
-
},
|
|
174
|
-
},
|
|
175
|
-
})
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
:::tip
|
|
179
|
-
The `catch`/`throw` pattern in JSON Logic validates that the condition evaluates to `true`. If it doesn't, the `throw` message is displayed to the user.
|
|
180
|
-
:::
|
|
181
|
-
|
|
182
|
-
## Field policies
|
|
183
|
-
|
|
184
|
-
Control how field data is tracked and stored using privacy policies:
|
|
185
|
-
|
|
186
|
-
```ts
|
|
187
|
-
const sensitiveField = createField({
|
|
188
|
-
id: 'ssn',
|
|
189
|
-
name: 'ssn',
|
|
190
|
-
type: 'text',
|
|
191
|
-
label: 'Social Security Number',
|
|
192
|
-
multiple: false,
|
|
193
|
-
required: true,
|
|
194
|
-
policies: {
|
|
195
|
-
doNotTrackValue: true, // Don't send value to analytics
|
|
196
|
-
doNotStoreValue: true, // Don't persist value to browser storage
|
|
197
|
-
},
|
|
198
|
-
})
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
**Privacy policies**:
|
|
202
|
-
|
|
203
|
-
- `doNotTrackValue`: Excludes field value from analytics events (only field ID is tracked)
|
|
204
|
-
- `doNotStoreValue`: Prevents field value from being persisted to browser storage
|
|
205
|
-
|
|
206
|
-
Use these policies for sensitive data like SSNs, credit cards, or passwords that should only exist client-side.
|
|
207
|
-
|
|
208
|
-
## Field metadata
|
|
209
|
-
|
|
210
|
-
Enhance user experience with additional descriptive text:
|
|
211
|
-
|
|
212
|
-
```ts
|
|
213
|
-
const passwordField = createField({
|
|
214
|
-
id: 'password',
|
|
215
|
-
name: 'password',
|
|
216
|
-
type: 'text',
|
|
217
|
-
label: 'Password',
|
|
218
|
-
multiple: false,
|
|
219
|
-
required: true,
|
|
220
|
-
placeholder: 'Enter a strong password',
|
|
221
|
-
description: 'Your password must be at least 8 characters',
|
|
222
|
-
helpText: 'Use a mix of letters, numbers, and symbols for better security',
|
|
223
|
-
})
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
**Metadata fields**:
|
|
227
|
-
|
|
228
|
-
- `placeholder`: Hint text displayed in empty input fields
|
|
229
|
-
- `description`: Brief explanation shown below the label
|
|
230
|
-
- `helpText`: Additional guidance or requirements displayed near the field
|
|
231
|
-
|
|
232
|
-
## Accessing field values
|
|
233
|
-
|
|
234
|
-
Field responses are stored in the experience state and can be accessed via the `responses` object:
|
|
235
|
-
|
|
236
|
-
:::code-group
|
|
237
|
-
|
|
238
|
-
```ts [In Conditions]
|
|
239
|
-
// Reference in subsequent field conditions
|
|
240
|
-
const sensitiveField = createField({
|
|
241
|
-
condition: {
|
|
242
|
-
'==': [
|
|
243
|
-
{
|
|
244
|
-
var: 'responses.field-name',
|
|
245
|
-
},
|
|
246
|
-
'expected-value',
|
|
247
|
-
],
|
|
248
|
-
},
|
|
249
|
-
})
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
:::
|
|
253
|
-
|
|
254
|
-
## Best practices
|
|
255
|
-
|
|
256
|
-
- **Use semantic IDs and names**: Name fields descriptively (e.g., `email-address` not `field1`) for easier debugging and analytics
|
|
257
|
-
- **Match type to data**: Use `number` for numeric values, not `text`, to enable proper validation and comparison
|
|
258
|
-
- **Set appropriate `required` flags**: Only mark fields as required when truly necessary to reduce form abandonment
|
|
259
|
-
- **Keep validation messages clear**: Error messages should tell users exactly how to fix the input
|
|
260
|
-
- **Use conditional fields for progressive disclosure**: Show fields only when relevant based on prior responses
|
|
261
|
-
- **Apply privacy policies to sensitive data**: Use `doNotTrackValue` and `doNotStoreValue` for PII, passwords, or financial data
|
|
262
|
-
- **Provide helpful metadata**: Add `placeholder` and `description` to guide users, especially for complex or formatted inputs
|
|
263
|
-
- **Keep option lists scannable**: For more than 5 options, consider providing search/filter functionality or breaking into multiple steps
|
package/dist/docs/sdk/index.md
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
layout: docs
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Picked SDK
|
|
6
|
-
|
|
7
|
-
The Picked SDK enables you to add dynamic, personalized experiences to your web applications with minimal code.
|
|
8
|
-
|
|
9
|
-
:::tip
|
|
10
|
-
The SDK is framework-agnostic and works with React, Svelte, Vue, and vanilla JavaScript.
|
|
11
|
-
:::
|
|
12
|
-
|
|
13
|
-
## Quick Start
|
|
14
|
-
|
|
15
|
-
:::code-group
|
|
16
|
-
|
|
17
|
-
```typescript [Browser]
|
|
18
|
-
import { createClient } from '@picked/client'
|
|
19
|
-
import { windowObjectPlugin } from '@picked/client/plugins/window-object'
|
|
20
|
-
import { singlePageAppPlugin } from '@picked/client/plugins/single-page-app'
|
|
21
|
-
|
|
22
|
-
const picked = createClient({
|
|
23
|
-
projectId: 'your-project-id',
|
|
24
|
-
plugins: [windowObjectPlugin(), singlePageAppPlugin()],
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
picked.init()
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
```ts [Server]
|
|
31
|
-
import { createClient } from '@picked/client'
|
|
32
|
-
import { serialize } from '@picked/client/server'
|
|
33
|
-
|
|
34
|
-
const client = createClient({ projectId: 'your-project-id' })
|
|
35
|
-
|
|
36
|
-
const snapshot = await serialize(client, {
|
|
37
|
-
projectConfig,
|
|
38
|
-
attributes: { location: { pathname: '/promo' } },
|
|
39
|
-
})
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
:::
|
|
43
|
-
|
|
44
|
-
The `@picked/client/server` entry holds the server-only helpers, such as `serialize()`, that produce an SSR snapshot. It is a separate entry point so browser bundles never include it. See [Server-Side Rendering](/sdk/ssr).
|
|
45
|
-
|
|
46
|
-
:::tip
|
|
47
|
-
If you’re running Picked in a browser environment, access the Picked client in the console with `window.Picked`
|
|
48
|
-
:::
|
|
49
|
-
|
|
50
|
-
## Precondition & Condition
|
|
51
|
-
|
|
52
|
-
| Category | Question | Description |
|
|
53
|
-
| ------------ | ---------------------- | --------------------------------------------------------------------------------------------- |
|
|
54
|
-
| Precondition | Should Picked start? | Use for environment checks, page filtering, or feature flags that completely disable the SDK. |
|
|
55
|
-
| Condition | Is this user eligible? | Use for user segmentation, A/B test enrollment, or targeting specific user groups. |
|
|
56
|
-
|
|
57
|
-
```ts
|
|
58
|
-
const picked = createClient({
|
|
59
|
-
precondition: {
|
|
60
|
-
and: [
|
|
61
|
-
{
|
|
62
|
-
or: [
|
|
63
|
-
{
|
|
64
|
-
invoke: {
|
|
65
|
-
var: 'features.aa-test',
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
true,
|
|
69
|
-
],
|
|
70
|
-
},
|
|
71
|
-
{ invoke: { var: 'predicates.shopify-is-product-page' } },
|
|
72
|
-
],
|
|
73
|
-
},
|
|
74
|
-
condition: {
|
|
75
|
-
invoke: {
|
|
76
|
-
var: 'features.convincely-enabled',
|
|
77
|
-
},
|
|
78
|
-
},
|
|
79
|
-
// rest of picked config
|
|
80
|
-
})
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
See [conditions](./conditions.md) for more detail
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
layout: docs
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Dynamic Experiences Plugin
|
|
6
|
-
|
|
7
|
-
A plugin that fetches your project configuration from the Picked API at runtime, letting you manage experiences, features, steps, fields, and conditions entirely from the [dashboard](/experiences).
|
|
8
|
-
|
|
9
|
-
## Setup Plugin
|
|
10
|
-
|
|
11
|
-
:::code-group
|
|
12
|
-
|
|
13
|
-
```ts [app.ts]
|
|
14
|
-
import { createClient } from '@picked/client'
|
|
15
|
-
import { dynamicExperiencesPlugin } from '@picked/client/plugins/dynamic-experiences'
|
|
16
|
-
|
|
17
|
-
const client = createClient({
|
|
18
|
-
projectId: 'your-project-id',
|
|
19
|
-
plugins: [dynamicExperiencesPlugin()],
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
client.start()
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
:::
|
|
26
|
-
|
|
27
|
-
:::tip
|
|
28
|
-
Unlike [createExperiencePlugin](./create-experience.md), you do not define experiences, steps, or fields in code. All configuration is managed from the [Picked dashboard](/experiences).
|
|
29
|
-
:::
|
|
30
|
-
|
|
31
|
-
## How It Works
|
|
32
|
-
|
|
33
|
-
When the client starts, the plugin resolves your project configuration using a three-tier strategy:
|
|
34
|
-
|
|
35
|
-
1. **Preview mode** — When you [enter preview mode from the dashboard](/workspaces#preview), the plugin fetches fresh config from the API. Feature decisions use session storage so they are not persisted beyond the current tab.
|
|
36
|
-
|
|
37
|
-
2. **Build-time config** — If `projectConfig` was passed as a plugin option, or the [Vite Plugin](/vite-plugin) injected config at build time, the plugin uses that config with no network request.
|
|
38
|
-
|
|
39
|
-
3. **Runtime fetch** — Otherwise, the plugin fetches config from the API when the client starts.
|
|
40
|
-
|
|
41
|
-
Once resolved, the plugin registers all features, conditions, fields, steps, and experiences with the client. Experiences then initialize according to their [conditions](/sdk/conditions) and [target selectors](/sdk/experiences).
|
|
42
|
-
|
|
43
|
-
:::note
|
|
44
|
-
The [Vite Plugin](/vite-plugin) eliminates the runtime API request in production by embedding your project config at build time. This is the recommended setup for Vite-based applications.
|
|
45
|
-
:::
|
|
46
|
-
|
|
47
|
-
## Feature Allocation
|
|
48
|
-
|
|
49
|
-
Each [feature](/sdk/features) in your project has an `enabled` state and a `weight` (0–100) that controls the percentage of traffic allocated to it. The plugin uses a deterministic hash of the user's session ID to produce a stable allocation value. A user whose value falls below the feature weight is allocated to that feature — the same user always gets the same result.
|
|
50
|
-
|
|
51
|
-
Feature decisions are cached in `localStorage` by default, or `sessionStorage` when in [preview mode](#preview-mode).
|
|
52
|
-
|
|
53
|
-
## Preview Mode
|
|
54
|
-
|
|
55
|
-
When you [enter preview mode from the dashboard](/workspaces#preview), the SDK receives a preview token and activates preview mode:
|
|
56
|
-
|
|
57
|
-
- The plugin fetches fresh config from the API using the token, bypassing any build-time or cached config
|
|
58
|
-
- Feature decisions use session storage, so closing the tab resets them
|