@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,112 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
layout: docs
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Predicates
|
|
6
|
-
|
|
7
|
-
Predicates enable reusable condition logic based on current application state. Each predicate is a pure function that receives a state snapshot containing responses, fields, browser context, and optional arguments.
|
|
8
|
-
|
|
9
|
-
## Defining Predicates
|
|
10
|
-
|
|
11
|
-
Define predicates when creating the Picked client by passing a `predicates` object. Each predicate requires a unique identifier and a function that receives a state snapshot:
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
import { createClient } from '@picked/client'
|
|
15
|
-
|
|
16
|
-
const client = createClient({
|
|
17
|
-
projectId: 'your-project-id',
|
|
18
|
-
predicates: {
|
|
19
|
-
'is-example-page': ({ location }) => {
|
|
20
|
-
return location?.pathname === '/example'
|
|
21
|
-
},
|
|
22
|
-
'get-account-tier': async () => {
|
|
23
|
-
const data = await fetch('/api/get-account-tier').then((r) => r.json())
|
|
24
|
-
return data.result // returns "trial"
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
})
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## How Predicates Work
|
|
31
|
-
|
|
32
|
-
When a predicate is registered and used in conditions, the SDK follows this execution flow:
|
|
33
|
-
|
|
34
|
-
1. **Registration**: Predicates are registered to the Picked client during initialization
|
|
35
|
-
2. **State Snapshot Creation**: When invoked, predicates receive a frozen state snapshot containing current responses, fields, and browser context
|
|
36
|
-
3. **Condition Evaluation**: Experience conditions invoke predicates with a fresh snapshot whenever called
|
|
37
|
-
4. **Return Flexibility**: Predicates can return boolean, string, string array, undefined, or promises that resolve to these types
|
|
38
|
-
|
|
39
|
-
## Using Predicates in Conditions
|
|
40
|
-
|
|
41
|
-
Predicates are most commonly used within condition logic via the `invoke` operator:
|
|
42
|
-
|
|
43
|
-
```ts
|
|
44
|
-
const myExperience = createExperience({
|
|
45
|
-
// ... other config
|
|
46
|
-
condition: {
|
|
47
|
-
and: [
|
|
48
|
-
{
|
|
49
|
-
'==': [
|
|
50
|
-
{
|
|
51
|
-
invoke: {
|
|
52
|
-
var: 'predicates.is-example-page', // Reference predicate that calls user endpoint
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
true, // Check if return value is true
|
|
56
|
-
],
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
'==': [
|
|
60
|
-
{
|
|
61
|
-
invoke: {
|
|
62
|
-
var: 'predicates.account-tier',
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
'/trial', // If string matches, evaluate to true
|
|
66
|
-
],
|
|
67
|
-
},
|
|
68
|
-
],
|
|
69
|
-
},
|
|
70
|
-
})
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
:::tip
|
|
74
|
-
Predicates can also be used in `validation` logic
|
|
75
|
-
:::
|
|
76
|
-
|
|
77
|
-
## Using the State Snapshot
|
|
78
|
-
|
|
79
|
-
Each predicate receives a `StateSnapshot` object with the following properties:
|
|
80
|
-
|
|
81
|
-
```ts
|
|
82
|
-
interface StateSnapshot {
|
|
83
|
-
client: Picked // The Picked client instance
|
|
84
|
-
responses?: Array<{
|
|
85
|
-
// All user responses
|
|
86
|
-
fieldId: string
|
|
87
|
-
value: FieldValue | undefined
|
|
88
|
-
}>
|
|
89
|
-
args?: unknown[]
|
|
90
|
-
fields?: Field[] // All registered fields
|
|
91
|
-
location?: Location // Browser location (URL, pathname, search, etc.)
|
|
92
|
-
document?: Document // Browser document object
|
|
93
|
-
sessionStorage?: Storage // Browser sessionStorage API
|
|
94
|
-
localStorage?: Storage // Browser localStorage API
|
|
95
|
-
}
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
:::warning
|
|
99
|
-
In server-side rendering or non-browser environments, `location`, `document`, `sessionStorage`,
|
|
100
|
-
and `localStorage` will be `undefined`.
|
|
101
|
-
:::
|
|
102
|
-
|
|
103
|
-
## Best Practices
|
|
104
|
-
|
|
105
|
-
- **Keep predicates pure**: Predicates should be deterministic and side-effect free. Given the same snapshot, they should always return the same result
|
|
106
|
-
- **Handle missing data gracefully**: Always check if responses or fields exist before accessing their values. Return `undefined` when data is unavailable rather than throwing errors
|
|
107
|
-
- **Avoid heavy computations**: Predicates may be invoked frequently. Keep logic lightweight and fast
|
|
108
|
-
- **Use async sparingly**: While async predicates are supported, they can delay experience rendering. Prefer synchronous logic when possible
|
|
109
|
-
- **Return consistent types**: Don't mix return types (e.g., sometimes boolean, sometimes string) for the same predicate
|
|
110
|
-
- **Use meaningful names**: Predicate IDs should clearly describe what they evaluate (e.g., `is-premium-user`, `has-items-in-cart`)
|
|
111
|
-
- **Consider caching expensive operations**: If a predicate needs to perform expensive operations, consider caching the result in `localStorage` or `sessionStorage` within the predicate logic
|
|
112
|
-
- **Don't mutate the snapshot**: The state snapshot is frozen. Any attempt to modify it will throw an error in strict mode
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
layout: docs
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Server-Side Rendering
|
|
6
|
-
|
|
7
|
-
Render Picked Pages on your server for SEO, then hydrate them on the client. This page shows the end-to-end shape; the following pages cover each piece.
|
|
8
|
-
|
|
9
|
-
## Why server-side rendering
|
|
10
|
-
|
|
11
|
-
Pages are SEO-critical, so their content must be in the HTML your server returns. Crawlers and social unfurls read that HTML directly and do not wait for client-side JavaScript. Rendering a Page on the server puts its content in the initial response, then the client takes over.
|
|
12
|
-
|
|
13
|
-
## The flow
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
projectConfig (Delivery API)
|
|
17
|
-
-> serialize(client, params) on the server -> PickedSnapshot
|
|
18
|
-
-> embed snapshot in HTML
|
|
19
|
-
-> client seeds from snapshot -> renders the same markup -> hydrates
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
1. Fetch your published `projectConfig` from the [Delivery API](/delivery-api).
|
|
23
|
-
2. Call `serialize()` on the server. It evaluates which experiences match the URL, fetches their content, and returns a plain-JSON `PickedSnapshot`. See [Server Snapshot](/sdk/ssr/serialize).
|
|
24
|
-
3. Embed the snapshot in your HTML payload.
|
|
25
|
-
4. On the client, seed a Picked client from the snapshot so the first paint matches the server markup, then hydrate. See [Rendering & Hydration](/sdk/ssr/rendering-and-hydration).
|
|
26
|
-
|
|
27
|
-
Because the snapshot carries the exact config the server selected with and the memoized condition results, the client's first render reuses the server's decisions instead of re-evaluating them.
|
|
28
|
-
|
|
29
|
-
## React vs Svelte at a glance
|
|
30
|
-
|
|
31
|
-
:::code-group
|
|
32
|
-
|
|
33
|
-
```tsx [React]
|
|
34
|
-
import { PickedProvider, ExperienceSlot } from '@picked/react'
|
|
35
|
-
|
|
36
|
-
<PickedProvider options={options} snapshot={snapshot}>
|
|
37
|
-
<ExperienceSlot name="page" />
|
|
38
|
-
</PickedProvider>
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
```svelte [Svelte]
|
|
42
|
-
<script lang="ts">
|
|
43
|
-
import { ExperienceSlot, setPickedContext } from '@picked/svelte'
|
|
44
|
-
|
|
45
|
-
setPickedContext({ options, snapshot })
|
|
46
|
-
</script>
|
|
47
|
-
|
|
48
|
-
<ExperienceSlot name="page" />
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
:::
|
|
52
|
-
|
|
53
|
-
## The server entry point
|
|
54
|
-
|
|
55
|
-
The server helpers live in a dedicated entry so browser bundles never pull them in:
|
|
56
|
-
|
|
57
|
-
```ts
|
|
58
|
-
import { serialize, registerProjectConfig } from '@picked/client/server'
|
|
59
|
-
import type { PickedSnapshot } from '@picked/client/server'
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
Continue to [Server Snapshot](/sdk/ssr/serialize) for the `serialize()` reference, [Rendering & Hydration](/sdk/ssr/rendering-and-hydration) for wiring React and Svelte, and [Slots & Placements](/sdk/ssr/slots-and-placements) for how a slot selects experiences. New to the SDK? Start with [Installation](/sdk).
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
layout: docs
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Rendering & Hydration
|
|
6
|
-
|
|
7
|
-
Seed a Picked client from the server snapshot, render your slots, and hydrate. React and Svelte below.
|
|
8
|
-
|
|
9
|
-
## React: PickedProvider
|
|
10
|
-
|
|
11
|
-
`PickedProvider` supplies a client to descendant components. Its props are a union of two construction modes:
|
|
12
|
-
|
|
13
|
-
| Props | Mode | Description |
|
|
14
|
-
| --- | --- | --- |
|
|
15
|
-
| `{ options, snapshot? }` | Create | The provider calls `createClient(options)` and hydrates it from the snapshot. |
|
|
16
|
-
| `{ client, snapshot? }` | Adopt | The provider uses an existing client, such as an app-wide global, and optionally seeds it from the snapshot. |
|
|
17
|
-
|
|
18
|
-
The provider seeds synchronously, so the server render and the client's first paint produce the same markup. In the browser it calls `client.start()` from an effect; `start()` is idempotent, so an already-started client is left untouched.
|
|
19
|
-
|
|
20
|
-
```tsx
|
|
21
|
-
import { PickedProvider, ExperienceSlot } from '@picked/react'
|
|
22
|
-
|
|
23
|
-
<PickedProvider options={options} snapshot={snapshot}>
|
|
24
|
-
<ExperienceSlot name="page" />
|
|
25
|
-
</PickedProvider>
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Svelte: setPickedContext
|
|
29
|
-
|
|
30
|
-
`setPickedContext` is the Svelte-idiomatic equivalent. Call it once at the top of a component's `<script>`. It takes the same two modes, `{ options, snapshot? }` or `{ client, snapshot? }`, and returns the client.
|
|
31
|
-
|
|
32
|
-
```svelte
|
|
33
|
-
<script lang="ts">
|
|
34
|
-
import { ExperienceSlot, setPickedContext } from '@picked/svelte'
|
|
35
|
-
|
|
36
|
-
setPickedContext({ options, snapshot })
|
|
37
|
-
</script>
|
|
38
|
-
|
|
39
|
-
<ExperienceSlot name="page" />
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## Placing the slot
|
|
43
|
-
|
|
44
|
-
Drop `<ExperienceSlot name="page" />` where the Page should render. The slot renders every experience that targets it and whose condition is active. See [Slots & Placements](/sdk/ssr/slots-and-placements) for how a slot selects and orders experiences.
|
|
45
|
-
|
|
46
|
-
## Rendering the page component
|
|
47
|
-
|
|
48
|
-
The SDK does not map content to components. You own the component a Page renders and register it under the name the Page uses, which is the same name the dashboard Page Layout maps to. The component reads the resolved entry data through the content hook: `useStepContent()` in React and `getStepContent()` in Svelte.
|
|
49
|
-
|
|
50
|
-
:::code-group
|
|
51
|
-
|
|
52
|
-
```tsx [React]
|
|
53
|
-
import { useStepContent } from '@picked/react/hooks'
|
|
54
|
-
|
|
55
|
-
export function CMSPage() {
|
|
56
|
-
const content = useStepContent()
|
|
57
|
-
if (!content) {
|
|
58
|
-
return <p>Loading page content…</p>
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const title = typeof content.title === 'string' ? content.title : ''
|
|
62
|
-
return (
|
|
63
|
-
<article>
|
|
64
|
-
<h1>{title}</h1>
|
|
65
|
-
</article>
|
|
66
|
-
)
|
|
67
|
-
}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
```svelte [Svelte]
|
|
71
|
-
<script lang="ts">
|
|
72
|
-
import { getStepContent } from '@picked/svelte/hooks'
|
|
73
|
-
|
|
74
|
-
const content = getStepContent()
|
|
75
|
-
</script>
|
|
76
|
-
|
|
77
|
-
{#if $content}
|
|
78
|
-
<article>
|
|
79
|
-
<h1>{typeof $content.title === 'string' ? $content.title : ''}</h1>
|
|
80
|
-
</article>
|
|
81
|
-
{:else}
|
|
82
|
-
<p>Loading page content…</p>
|
|
83
|
-
{/if}
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
:::
|
|
87
|
-
|
|
88
|
-
`useStepContent()` returns the entry's `data` object directly, or `null` while no content is registered. `getStepContent()` returns a store you read with `$content`.
|
|
89
|
-
|
|
90
|
-
## Full example
|
|
91
|
-
|
|
92
|
-
This is the verified page-slot wiring. The page client fetches the project config and renders whichever Page experience targets `.picked-slot-page` and matches the current URL.
|
|
93
|
-
|
|
94
|
-
:::code-group
|
|
95
|
-
|
|
96
|
-
```tsx [React]
|
|
97
|
-
import type { CreateClientOptions } from '@picked/client'
|
|
98
|
-
import type { PickedSnapshot } from '@picked/client/server'
|
|
99
|
-
import { dynamicExperiencesPlugin } from '@picked/client/plugins/dynamic-experiences'
|
|
100
|
-
import { adaptReactComponent, ExperienceSlot, PickedProvider } from '@picked/react'
|
|
101
|
-
import { reactFrameworkPlugin } from '@picked/react/plugins/framework'
|
|
102
|
-
import { CMSPage } from './CMSPage'
|
|
103
|
-
|
|
104
|
-
const options = {
|
|
105
|
-
projectId: 'sdk-cvly-x',
|
|
106
|
-
components: { CMSPage: adaptReactComponent(CMSPage) },
|
|
107
|
-
plugins: [reactFrameworkPlugin({ components: {} }), dynamicExperiencesPlugin()],
|
|
108
|
-
} satisfies CreateClientOptions
|
|
109
|
-
|
|
110
|
-
export function PageSlot({ snapshot }: { snapshot?: PickedSnapshot }) {
|
|
111
|
-
return (
|
|
112
|
-
<PickedProvider options={options} snapshot={snapshot}>
|
|
113
|
-
<ExperienceSlot name="page" />
|
|
114
|
-
</PickedProvider>
|
|
115
|
-
)
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
```svelte [Svelte]
|
|
120
|
-
<script lang="ts">
|
|
121
|
-
import type { CreateClientOptions } from '@picked/client'
|
|
122
|
-
import { dynamicExperiencesPlugin } from '@picked/client/plugins/dynamic-experiences'
|
|
123
|
-
import { adaptSvelteComponent, ExperienceSlot, setPickedContext } from '@picked/svelte'
|
|
124
|
-
import { svelteFrameworkPlugin } from '@picked/svelte/plugins/framework'
|
|
125
|
-
import CMSPage from './CMSPage.svelte'
|
|
126
|
-
|
|
127
|
-
const options = {
|
|
128
|
-
projectId: 'sdk-cvly-x',
|
|
129
|
-
components: { CMSPage: adaptSvelteComponent(CMSPage) },
|
|
130
|
-
plugins: [svelteFrameworkPlugin({ components: {} }), dynamicExperiencesPlugin()],
|
|
131
|
-
} satisfies CreateClientOptions
|
|
132
|
-
|
|
133
|
-
setPickedContext({ options })
|
|
134
|
-
</script>
|
|
135
|
-
|
|
136
|
-
<ExperienceSlot name="page" />
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
:::
|
|
140
|
-
|
|
141
|
-
For the end-to-end version with the server snapshot, see [Build a Personalized Page](/guides/build-a-personalized-page). For the snapshot reference, see [Server Snapshot](/sdk/ssr/serialize). For how experiences register, see [SDK Experiences](/sdk/experiences).
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
layout: docs
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Server Snapshot
|
|
6
|
-
|
|
7
|
-
`serialize()` evaluates which experiences match a URL and fetches their content on the server, returning a plain-JSON snapshot you pass to the client.
|
|
8
|
-
|
|
9
|
-
## serialize(client, params)
|
|
10
|
-
|
|
11
|
-
```ts
|
|
12
|
-
import { createClient } from '@picked/client'
|
|
13
|
-
import { serialize } from '@picked/client/server'
|
|
14
|
-
|
|
15
|
-
const client = createClient(options)
|
|
16
|
-
|
|
17
|
-
const snapshot = await serialize(client, {
|
|
18
|
-
projectConfig,
|
|
19
|
-
attributes: { location: { pathname: '/promo' } },
|
|
20
|
-
})
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
`serialize()` registers the project config on the client synchronously, evaluates each experience's condition against `attributes.location`, fetches content for the experiences whose steps reference layout content, dedupes the content blobs by id, and returns a `PickedSnapshot`. It expects a per-request client; concurrent calls on a single client are not supported.
|
|
24
|
-
|
|
25
|
-
```ts
|
|
26
|
-
serialize(client: Picked, params: SerializeParams): Promise<PickedSnapshot>
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
## Parameters
|
|
30
|
-
|
|
31
|
-
| Parameter | Type | Default | Description |
|
|
32
|
-
| --- | --- | --- | --- |
|
|
33
|
-
| `projectConfig` | `ProjectConfig` | required | The published or preview config to register and select against. |
|
|
34
|
-
| `attributes.location` | `Partial<SerializeLocation>` | none | URL fields injected into the selection context, such as `pathname`. |
|
|
35
|
-
| `getContent` | `SerializeGetContent` | runtime API | A custom content fetcher used in place of the runtime API. |
|
|
36
|
-
| `previewToken` | `string` | none | Forwarded to the content fetch so preview content resolves during preview SSR. |
|
|
37
|
-
| `timeoutMs` | `number` | `10000` | Per-content-fetch timeout. On timeout the blob is skipped and the render proceeds. |
|
|
38
|
-
|
|
39
|
-
`SerializeLocation` carries the plain URL fields `href`, `pathname`, `search`, `hostname`, `origin`, `protocol`, `port`, `host`, and `hash`. Pass only the ones your conditions read.
|
|
40
|
-
|
|
41
|
-
## The snapshot
|
|
42
|
-
|
|
43
|
-
```ts
|
|
44
|
-
interface PickedSnapshot {
|
|
45
|
-
versionId: string | null
|
|
46
|
-
projectConfig: ProjectConfig
|
|
47
|
-
content: ContentBlob[]
|
|
48
|
-
conditionResults: Record<string, boolean>
|
|
49
|
-
}
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
| Field | Description |
|
|
53
|
-
| --- | --- |
|
|
54
|
-
| `versionId` | The project version the snapshot was selected against, or `null` when unknown (for example on preview). |
|
|
55
|
-
| `projectConfig` | The config the server selected with. It travels so the client renders against the exact same config. |
|
|
56
|
-
| `content` | The deduped content blobs for the selected experiences. |
|
|
57
|
-
| `conditionResults` | The memoized condition results, keyed by rule hash, so the client reuses the server's selection. |
|
|
58
|
-
|
|
59
|
-
The snapshot is plain JSON. Serialize it into your HTML response with `JSON.stringify` and read it back on the client.
|
|
60
|
-
|
|
61
|
-
## Passing the snapshot to the client
|
|
62
|
-
|
|
63
|
-
Embed the snapshot in your HTML payload, then hand it to the provider (React) or context (Svelte):
|
|
64
|
-
|
|
65
|
-
```ts
|
|
66
|
-
const html = `
|
|
67
|
-
<div id="root">${appHtml}</div>
|
|
68
|
-
<script>window.__PICKED__ = ${JSON.stringify(snapshot)}</script>
|
|
69
|
-
`
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
On the client, read `window.__PICKED__` and pass it as the `snapshot` prop. See [Rendering & Hydration](/sdk/ssr/rendering-and-hydration).
|
|
73
|
-
|
|
74
|
-
## Preview rendering
|
|
75
|
-
|
|
76
|
-
Pass `previewToken` so unpublished content resolves during preview SSR. The server has no access to the request's query string, so the token cannot be recovered any other way:
|
|
77
|
-
|
|
78
|
-
```ts
|
|
79
|
-
const snapshot = await serialize(client, {
|
|
80
|
-
projectConfig,
|
|
81
|
-
attributes: { location: { pathname: '/promo' } },
|
|
82
|
-
previewToken,
|
|
83
|
-
})
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
Use the same token when you fetch `projectConfig` from the [Delivery API](/delivery-api), so the config and the content come from the same preview surface.
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
layout: docs
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Slots & Placements
|
|
6
|
-
|
|
7
|
-
A slot is a named mount point. `<ExperienceSlot name="page" />` renders every experience that targets that slot and whose condition matches.
|
|
8
|
-
|
|
9
|
-
## What a slot is
|
|
10
|
-
|
|
11
|
-
A slot's `name` maps to the `.picked-slot-<name>` selector. `<ExperienceSlot name="page" />` renders every experience whose target selector is `.picked-slot-page` and whose condition is active. The slot reads each experience's active state from the seeded snapshot, so it renders synchronously during server-side rendering and the hydration first paint.
|
|
12
|
-
|
|
13
|
-
```tsx
|
|
14
|
-
<ExperienceSlot name="page" />
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Targeting an experience to a slot
|
|
18
|
-
|
|
19
|
-
Set the experience's target selector to `.picked-slot-<name>`. An experience targeting `.picked-slot-page` renders into `<ExperienceSlot name="page" />`. The slot name and the selector suffix must match.
|
|
20
|
-
|
|
21
|
-
## Placement order
|
|
22
|
-
|
|
23
|
-
When several experiences target the same slot, they render in placement precedence:
|
|
24
|
-
|
|
25
|
-
```
|
|
26
|
-
replace -> before -> prepend -> append -> after
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
`replace` wins. If an active experience uses the `replace` placement, it renders alone and replaces every other match in the slot. Otherwise every active experience renders, in placement order.
|
|
30
|
-
|
|
31
|
-
## Multiple experiences in one slot
|
|
32
|
-
|
|
33
|
-
The slot collects each experience that targets its selector, drops any whose condition is not active, and sorts the rest by placement. If a `replace` experience is among the active ones, only that experience renders. With no active `replace`, the slot renders all active experiences in `before, prepend, append, after` order.
|
|
34
|
-
|
|
35
|
-
This lets one Page take over a slot with `replace`, while other slots can stack several experiences by using the non-`replace` placements. Conditions decide which experiences are active; see [Conditions](/conditions).
|