picked 0.0.101-next.2 → 0.0.101

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.
Files changed (175) hide show
  1. package/README.md +27 -12
  2. package/docs/explanation/conditions-and-the-logic-engine.md +94 -0
  3. package/docs/explanation/content-references.md +99 -0
  4. package/docs/explanation/feature-flag-allocation.md +218 -0
  5. package/docs/explanation/how-picked-works.md +124 -0
  6. package/docs/explanation/how-pickedql-works.md +76 -0
  7. package/docs/explanation/pages-and-flows.md +64 -0
  8. package/docs/explanation/the-content-model.md +87 -0
  9. package/docs/explanation/the-two-apis.md +68 -0
  10. package/docs/explanation/why-server-side-rendering.md +76 -0
  11. package/docs/explanation/workspaces-and-versions.md +71 -0
  12. package/docs/how-to/add-a-step-field-or-action.md +56 -0
  13. package/docs/how-to/analytics/index.md +324 -0
  14. package/docs/how-to/archive-or-delete-a-workspace.md +59 -0
  15. package/docs/how-to/authenticate-the-cli.md +101 -0
  16. package/docs/how-to/authenticate-with-a-magic-link.md +56 -0
  17. package/docs/how-to/authenticate-with-a-password.md +68 -0
  18. package/docs/how-to/authenticate-with-an-api-key.md +60 -0
  19. package/docs/how-to/authenticate-with-oauth.md +49 -0
  20. package/docs/how-to/build-a-flow.md +106 -0
  21. package/docs/how-to/call-an-external-api-from-a-workflow.md +116 -0
  22. package/docs/how-to/connect-the-mcp-server.md +46 -0
  23. package/docs/how-to/create-a-content-entry.md +58 -0
  24. package/docs/how-to/create-a-project.md +40 -0
  25. package/docs/how-to/create-an-experience.md +51 -0
  26. package/docs/how-to/create-and-revoke-an-api-key.md +54 -0
  27. package/docs/how-to/debug-with-the-chrome-extension.md +57 -0
  28. package/docs/how-to/define-a-page-layout.md +54 -0
  29. package/docs/how-to/fill-and-publish-a-page.md +82 -0
  30. package/docs/how-to/install-the-gtm-template.md +84 -0
  31. package/docs/how-to/install-the-sdk.md +93 -0
  32. package/docs/how-to/install-the-vite-plugin.md +69 -0
  33. package/docs/how-to/invite-and-remove-members.md +45 -0
  34. package/docs/how-to/point-one-entry-at-another.md +75 -0
  35. package/docs/how-to/preview-a-workspace.md +39 -0
  36. package/docs/how-to/publish-a-workspace.md +42 -0
  37. package/docs/how-to/read-a-feature-flag.md +113 -0
  38. package/docs/how-to/read-a-referenced-entry.md +109 -0
  39. package/docs/how-to/register-a-component.md +55 -0
  40. package/docs/how-to/register-an-action-handler.md +85 -0
  41. package/docs/how-to/register-an-api-that-uses-oauth2.md +107 -0
  42. package/docs/how-to/render-a-step-form.md +131 -0
  43. package/docs/how-to/render-an-unpublished-preview.md +41 -0
  44. package/docs/how-to/retry-a-failed-call-with-a-loop.md +81 -0
  45. package/docs/how-to/reuse-a-section.md +64 -0
  46. package/docs/how-to/reuse-a-step-field-or-action.md +39 -0
  47. package/docs/how-to/roll-back-a-published-version.md +39 -0
  48. package/docs/how-to/run-an-ab-test.md +59 -0
  49. package/docs/how-to/run-code-on-a-form-submission.md +125 -0
  50. package/docs/how-to/server-render-a-page.md +81 -0
  51. package/docs/how-to/set-a-content-security-policy.md +32 -0
  52. package/docs/how-to/set-up-mfa.md +126 -0
  53. package/docs/how-to/switch-workspaces.md +122 -0
  54. package/docs/how-to/upload-and-use-an-asset.mdx +87 -0
  55. package/docs/how-to/validate-a-field.md +52 -0
  56. package/docs/how-to/wait-for-an-action-response.md +182 -0
  57. package/docs/how-to/write-a-condition.md +57 -0
  58. package/docs/how-to/write-a-predicate.md +60 -0
  59. package/docs/index.md +59 -0
  60. package/docs/reference/dashboard/actions.mdx +65 -0
  61. package/docs/reference/dashboard/api-keys.mdx +47 -0
  62. package/docs/reference/dashboard/conditions.mdx +51 -0
  63. package/docs/reference/dashboard/content/asset-library.mdx +74 -0
  64. package/docs/reference/dashboard/content/blocks.mdx +66 -0
  65. package/docs/reference/dashboard/content/content-entries.mdx +109 -0
  66. package/docs/reference/dashboard/content/models.mdx +119 -0
  67. package/docs/reference/dashboard/content/pages.mdx +72 -0
  68. package/docs/reference/dashboard/experiences.mdx +61 -0
  69. package/docs/reference/dashboard/external-apis.md +182 -0
  70. package/docs/reference/dashboard/features.mdx +165 -0
  71. package/docs/reference/dashboard/fields.mdx +120 -0
  72. package/docs/reference/dashboard/flow-builder/canvas.mdx +58 -0
  73. package/docs/reference/dashboard/flow-builder/condition-builder.md +69 -0
  74. package/docs/reference/dashboard/flow-builder/keyboard-shortcuts.md +72 -0
  75. package/docs/reference/dashboard/flow-builder/nodes.md +74 -0
  76. package/docs/reference/dashboard/labels.md +321 -0
  77. package/docs/reference/dashboard/lead-search.md +235 -0
  78. package/docs/reference/dashboard/projects.mdx +53 -0
  79. package/docs/reference/dashboard/reports.mdx +53 -0
  80. package/docs/reference/dashboard/steps.mdx +47 -0
  81. package/docs/reference/dashboard/team-management.md +38 -0
  82. package/docs/reference/dashboard/workflow-runs.md +157 -0
  83. package/docs/reference/dashboard/workflow-templates.md +182 -0
  84. package/docs/reference/dashboard/workflow-test-runs.md +85 -0
  85. package/docs/reference/dashboard/workspace-versioning.mdx +42 -0
  86. package/docs/reference/dashboard/workspaces.mdx +91 -0
  87. package/docs/reference/delivery-api/experience-content.md +152 -0
  88. package/docs/reference/delivery-api/index.md +45 -0
  89. package/docs/reference/delivery-api/preview-caching-crawling.md +79 -0
  90. package/docs/reference/delivery-api/project-config.md +65 -0
  91. package/docs/reference/delivery-api/workspace-schema.md +107 -0
  92. package/docs/reference/glossary.md +201 -0
  93. package/docs/reference/management-api/authentication.md +87 -0
  94. package/docs/reference/management-api/authorization-and-scopes.md +291 -0
  95. package/docs/reference/management-api/error-handling.md +232 -0
  96. package/docs/reference/management-api/pagination.md +192 -0
  97. package/docs/reference/management-api/schema/action.md +261 -0
  98. package/docs/reference/management-api/schema/analytics-session.md +363 -0
  99. package/docs/reference/management-api/schema/analytics.md +73 -0
  100. package/docs/reference/management-api/schema/api-key.md +170 -0
  101. package/docs/reference/management-api/schema/auth.md +1177 -0
  102. package/docs/reference/management-api/schema/cms-fields.md +954 -0
  103. package/docs/reference/management-api/schema/cms-models.md +1155 -0
  104. package/docs/reference/management-api/schema/common.md +362 -0
  105. package/docs/reference/management-api/schema/condition.md +254 -0
  106. package/docs/reference/management-api/schema/design-system.md +199 -0
  107. package/docs/reference/management-api/schema/experience.md +1098 -0
  108. package/docs/reference/management-api/schema/external-api.md +637 -0
  109. package/docs/reference/management-api/schema/feature.md +350 -0
  110. package/docs/reference/management-api/schema/feedback.md +103 -0
  111. package/docs/reference/management-api/schema/field.md +400 -0
  112. package/docs/reference/management-api/schema/index.md +243 -0
  113. package/docs/reference/management-api/schema/integration.md +272 -0
  114. package/docs/reference/management-api/schema/label.md +349 -0
  115. package/docs/reference/management-api/schema/lead.md +340 -0
  116. package/docs/reference/management-api/schema/mcp-server.md +299 -0
  117. package/docs/reference/management-api/schema/metric.md +223 -0
  118. package/docs/reference/management-api/schema/operation.md +96 -0
  119. package/docs/reference/management-api/schema/organization.md +749 -0
  120. package/docs/reference/management-api/schema/project.md +607 -0
  121. package/docs/reference/management-api/schema/report.md +243 -0
  122. package/docs/reference/management-api/schema/saved-view.md +288 -0
  123. package/docs/reference/management-api/schema/shopify.md +795 -0
  124. package/docs/reference/management-api/schema/step.md +273 -0
  125. package/docs/reference/management-api/schema/tenant-branding.md +185 -0
  126. package/docs/reference/management-api/schema/workbench.md +246 -0
  127. package/docs/reference/management-api/schema/workflow-run.md +263 -0
  128. package/docs/reference/management-api/schema/workflow.md +1110 -0
  129. package/docs/reference/management-api/schema/workspace-version.md +823 -0
  130. package/docs/reference/management-api/schema/workspace.md +917 -0
  131. package/docs/reference/pickedql/data-sources.md +174 -0
  132. package/docs/reference/pickedql/dimensions.md +103 -0
  133. package/docs/reference/pickedql/filtering.md +64 -0
  134. package/docs/reference/pickedql/index.md +18 -0
  135. package/docs/reference/pickedql/schema.md +172 -0
  136. package/docs/reference/pickedql/virtual-functions.md +248 -0
  137. package/docs/reference/sdk/actions.md +154 -0
  138. package/docs/reference/sdk/analytics-events.md +453 -0
  139. package/docs/reference/sdk/conditions.md +147 -0
  140. package/docs/reference/sdk/content-security-policy.md +21 -0
  141. package/docs/reference/sdk/content.md +253 -0
  142. package/docs/reference/sdk/experiences.md +51 -0
  143. package/docs/reference/sdk/features.md +256 -0
  144. package/docs/reference/sdk/fields.md +255 -0
  145. package/docs/reference/sdk/index.md +68 -0
  146. package/docs/reference/sdk/plugins/create-experience.md +123 -0
  147. package/docs/reference/sdk/plugins/dynamic-experiences.md +74 -0
  148. package/docs/reference/sdk/plugins/fingerprintjs.md +39 -0
  149. package/docs/reference/sdk/plugins/hotjar.md +60 -0
  150. package/docs/reference/sdk/plugins/index.md +33 -0
  151. package/docs/reference/sdk/plugins/sentry.md +51 -0
  152. package/docs/reference/sdk/plugins/shopify.md +109 -0
  153. package/docs/reference/sdk/plugins/window-object.md +25 -0
  154. package/docs/reference/sdk/predicates.md +43 -0
  155. package/docs/reference/sdk/react.md +61 -0
  156. package/docs/reference/sdk/ssr/index.md +33 -0
  157. package/docs/reference/sdk/ssr/rendering-and-hydration.md +103 -0
  158. package/docs/reference/sdk/ssr/serialize.md +80 -0
  159. package/docs/reference/sdk/ssr/slots-and-placements.md +113 -0
  160. package/docs/reference/sdk/steps.md +86 -0
  161. package/docs/reference/sdk/svelte.md +74 -0
  162. package/docs/reference/sdk/type-generation.md +265 -0
  163. package/docs/reference/tools/admin-api-client.md +89 -0
  164. package/docs/reference/tools/chrome-extension.md +16 -0
  165. package/docs/reference/tools/cli.md +319 -0
  166. package/docs/reference/tools/delivery-api-client.md +60 -0
  167. package/docs/reference/tools/image-optimisation-service.md +104 -0
  168. package/docs/reference/tools/mcp-run.md +121 -0
  169. package/docs/reference/tools/mcp.md +391 -0
  170. package/docs/reference/tools/vite-plugin.md +163 -0
  171. package/docs/tutorials/first-api-call.md +253 -0
  172. package/docs/tutorials/first-experience-in-the-dashboard.mdx +160 -0
  173. package/docs/tutorials/first-experience.mdx +254 -0
  174. package/docs/tutorials/first-server-rendered-page.mdx +186 -0
  175. package/package.json +8 -7
@@ -0,0 +1,87 @@
1
+ ---
2
+ type: how-to
3
+ layout: docs
4
+ ---
5
+
6
+ import { Screenshot } from '../../../components/Screenshot'
7
+
8
+ # How to upload and use an asset
9
+
10
+ This guide shows you how to put a file in the asset library and point at it from your
11
+ content.
12
+
13
+ ## 1. Add the field to a layout
14
+
15
+ Two field types point at the library:
16
+
17
+ - An **Asset** field takes an image, a video, or a document.
18
+ - An **HTML** field takes a `.html` file.
19
+
20
+ Add one of them to a page layout or a step layout.
21
+
22
+ ## 2. Choose a file
23
+
24
+ 1. Open the content entry.
25
+ 2. Click **Choose file** on the asset field. On a field that holds a value already, click
26
+ **Replace**.
27
+ 3. Open the **Upload** tab to add a new file.
28
+ 4. Open the **Library** tab to use a file that is there already.
29
+ 5. Choose your asset.
30
+
31
+ <Screenshot
32
+ route="/{orgSlug}/{projectId}/design-systems/new"
33
+ wait='button:has-text("Upload file")'
34
+ click='button:has-text("Upload file")'
35
+ selector="[role=dialog]"
36
+ alt="The asset picker modal on the Picked dashboard, with the Library tab, its search box, its type filter, and its Sort menu"
37
+ renderWidth={1072}
38
+ renderHeight={790}
39
+ />
40
+
41
+ <Screenshot
42
+ route="/{orgSlug}/{projectId}/design-systems/new"
43
+ wait='button:has-text("Upload file")'
44
+ click='button:has-text("Upload file")'
45
+ selector="[role=dialog]"
46
+ alt="The asset picker modal on the Picked dashboard, with the Library tab, its search box, its type filter, and its Sort menu"
47
+ renderWidth={1072}
48
+ renderHeight={790}
49
+ />
50
+
51
+ The detail panel on the right shows the kind, the dimensions, the size, and the upload
52
+ date.
53
+
54
+ ## 3. Find an asset in a large library
55
+
56
+ The **Library** tab has three controls, and the server applies each one across the whole
57
+ library:
58
+
59
+ - **Search by name** narrows the list by file name while you type.
60
+ - The type filter narrows the list to one media type. **All types** is the default.
61
+ - **Sort** orders the list by **Name**, **Date created**, or **Date updated**.
62
+
63
+ Click **Load more** at the bottom to read the next page of results.
64
+
65
+ :::tip
66
+ Each row has an **Open in new tab** control. Use it to check an asset again before you
67
+ choose it. Your choice in the picker stays as it is.
68
+ :::
69
+
70
+ ## API and MCP
71
+
72
+ You can also do this task with the [Management API](/reference/management-api/schema), the [MCP server](/reference/tools/mcp), or code that you send to [`picked_run`](/reference/tools/mcp-run).
73
+
74
+ | Task | GraphQL | MCP tool | Run |
75
+ | --- | --- | --- | --- |
76
+ | Add the field to a layout | [`contentModelUpdate`](/reference/management-api/schema/cms-models#contentmodelupdate) | [`update_content_model`](/reference/tools/mcp#update_content_model) | `tools.update_content_model({ content_model_id, schema })` |
77
+ | Upload a file | [`assetUploadInit`](/reference/management-api/schema/cms-models#assetuploadinit), [`assetCommit`](/reference/management-api/schema/cms-models#assetcommit) | [`init_asset_upload`](/reference/tools/mcp#init_asset_upload), [`commit_asset_upload`](/reference/tools/mcp#commit_asset_upload) | `tools.init_asset_upload({ project_id, file_name, content_type })`, `tools.commit_asset_upload({ project_id, asset_id, version_id, file_name, storage_path })` |
78
+ | Find an asset in the library | [`assets`](/reference/management-api/schema/cms-models#assets) | [`list_assets`](/reference/tools/mcp#list_assets) | `tools.list_assets({ project_id })` |
79
+ | Choose the asset in an entry | [`contentEntryUpdate`](/reference/management-api/schema/cms-models#contententryupdate) | [`update_content_entry`](/reference/tools/mcp#update_content_entry) | `tools.update_content_entry({ content_entry_id, data })` |
80
+
81
+ Between the two calls, send the file in a `PUT` request to the URL that the first call gives.
82
+ The `list_assets` tool has no search, no type filter and no sort.
83
+
84
+ ## Related
85
+
86
+ - [Asset library](/reference/dashboard/content/asset-library) — the limits, the file
87
+ types, and how Picked serves an uploaded file.
@@ -0,0 +1,52 @@
1
+ ---
2
+ type: how-to
3
+ layout: docs
4
+ ---
5
+
6
+ # How to validate a field
7
+
8
+ This guide shows you how to check what a visitor enters. Write the rule in JSON Logic. The
9
+ `$input` variable holds the current value of the field.
10
+
11
+ ## Steps
12
+
13
+ Add a `validation` rule to `createField()`:
14
+
15
+ ```ts
16
+ import { createField } from '@picked/client/plugins/create-experience'
17
+
18
+ const quantityField = createField({
19
+ id: 'quantity',
20
+ name: 'quantity',
21
+ type: 'number',
22
+ label: 'Quantity',
23
+ multiple: false,
24
+ required: true,
25
+ validation: {
26
+ catch: {
27
+ or: [
28
+ {
29
+ and: [
30
+ { '>': [{ var: '$input' }, 0] },
31
+ { '<=': [{ var: '$input' }, 999] },
32
+ ],
33
+ },
34
+ { throw: 'Please enter a value between 1 and 999' },
35
+ ],
36
+ },
37
+ },
38
+ })
39
+ ```
40
+
41
+ :::tip
42
+ The `catch` and `throw` pattern checks that the condition gives `true`. When it does not,
43
+ the SDK shows the `throw` message to your visitor.
44
+ :::
45
+
46
+ The SDK runs the rule on blur and on submit.
47
+
48
+ ## Related
49
+
50
+ - [SDK fields](/reference/sdk/fields) — every field option.
51
+ - [About conditions and the logic engine](/explanation/conditions-and-the-logic-engine) —
52
+ the rule format.
@@ -0,0 +1,182 @@
1
+ ---
2
+ type: how-to
3
+ layout: docs
4
+ ---
5
+
6
+ # How to wait for the response of an action
7
+
8
+ This guide shows you how to run an action from your application and show its response. You
9
+ need an action in your project first, with a key and a workflow that the action starts. See
10
+ [Actions](/reference/dashboard/actions).
11
+
12
+ The response is the value that the action returns. For an action that starts a workflow in
13
+ Picked, the response is the payload of the **Action response** node in the workflow.
14
+
15
+ ## 1. Generate the types of your project
16
+
17
+ Run type generation. The generated types name the actions that start a workflow. For those
18
+ keys, the types of `useAction` and `getAction` include `run`. At runtime, the value includes
19
+ `run` for each key. See [Type generation](/reference/sdk/type-generation).
20
+
21
+ ## 2. Bind the action to a component
22
+
23
+ Call `useAction` in React, or `getAction` in Svelte. Neither runs the action. The action runs
24
+ only when you call `run`. The action receives the arguments of `run` in `args`.
25
+
26
+ All the components that use the same key and the same experience share one run state. When
27
+ one of them calls `run`, all of them show that run.
28
+
29
+ :::code-group
30
+
31
+ ```tsx [React]
32
+ import { useAction } from '@picked/react/hooks'
33
+
34
+ function CallbackButton() {
35
+ const callback = useAction('request-callback')
36
+
37
+ return (
38
+ <button onClick={() => void callback.run()} disabled={callback.status === 'running'}>
39
+ Get a call back
40
+ </button>
41
+ )
42
+ }
43
+ ```
44
+
45
+ ```svelte [Svelte]
46
+ <script lang="ts">
47
+ import { getAction } from '@picked/svelte/hooks'
48
+
49
+ const callback = getAction('request-callback')
50
+ </script>
51
+
52
+ <button onclick={() => $callback.run()} disabled={$callback.status === 'running'}>
53
+ Get a call back
54
+ </button>
55
+ ```
56
+
57
+ :::
58
+
59
+ ## 3. Show the response
60
+
61
+ Read `status`, `response` and `error` for the last run. Compare `response` with the values
62
+ that your workflow sends.
63
+
64
+ :::code-group
65
+
66
+ ```tsx [React]
67
+ import { useAction } from '@picked/react/hooks'
68
+
69
+ // Reads the status that the workflow sends in its response.
70
+ function answerStatus(response: unknown): unknown {
71
+ return typeof response === 'object' && response !== null && 'status' in response
72
+ ? response.status
73
+ : undefined
74
+ }
75
+
76
+ function CallbackButton() {
77
+ const callback = useAction('request-callback')
78
+
79
+ if (callback.status === 'failed') return <p>We could not send your request.</p>
80
+ if (callback.status === 'succeeded') {
81
+ if (answerStatus(callback.response) === 'closed') {
82
+ return <p>We call back on weekdays, 8 am to 5 pm.</p>
83
+ }
84
+ return <p>Thank you. We will call you soon.</p>
85
+ }
86
+
87
+ return (
88
+ <button onClick={() => void callback.run()} disabled={callback.status === 'running'}>
89
+ Get a call back
90
+ </button>
91
+ )
92
+ }
93
+ ```
94
+
95
+ ```svelte [Svelte]
96
+ <script lang="ts">
97
+ import { getAction } from '@picked/svelte/hooks'
98
+
99
+ const callback = getAction('request-callback')
100
+
101
+ // Reads the status that the workflow sends in its response.
102
+ function answerStatus(response: unknown): unknown {
103
+ return typeof response === 'object' && response !== null && 'status' in response
104
+ ? response.status
105
+ : undefined
106
+ }
107
+ </script>
108
+
109
+ {#if $callback.status === 'failed'}
110
+ <p>We could not send your request.</p>
111
+ {:else if $callback.status === 'succeeded' && answerStatus($callback.response) === 'closed'}
112
+ <p>We call back on weekdays, 8 am to 5 pm.</p>
113
+ {:else if $callback.status === 'succeeded'}
114
+ <p>Thank you. We will call you soon.</p>
115
+ {:else}
116
+ <button onclick={() => $callback.run()} disabled={$callback.status === 'running'}>
117
+ Get a call back
118
+ </button>
119
+ {/if}
120
+ ```
121
+
122
+ :::
123
+
124
+ `run` does not reject. It resolves to `{ status: 'succeeded', response }` or to
125
+ `{ status: 'failed', error }`.
126
+
127
+ ## 4. Run the action outside a component
128
+
129
+ Call `client.actions.run` with the action key. It resolves to the response, and it rejects
130
+ when the action fails.
131
+
132
+ The client registers the actions of your project when it loads the configuration of your
133
+ project. For this, the client must have `dynamicExperiencesPlugin`, and you must start the
134
+ client. Until the client is ready, `run` rejects with `Action '<key>' is not registered`. A
135
+ handler that your application registers in `createClient({ actions })` is available
136
+ immediately.
137
+
138
+ ```ts
139
+ import { createClient } from 'picked'
140
+ import { dynamicExperiencesPlugin } from '@picked/client/plugins/dynamic-experiences'
141
+
142
+ const picked = createClient({
143
+ projectId: 'your-project-id',
144
+ plugins: [dynamicExperiencesPlugin()],
145
+ })
146
+
147
+ picked.start()
148
+
149
+ // Waits until the client is ready.
150
+ async function whenReady(): Promise<void> {
151
+ if (picked.readyStore.getState()) return
152
+
153
+ await new Promise<void>((resolve) => {
154
+ const subscription = picked.readyStore.updates.watch((ready) => {
155
+ if (!ready) return
156
+ subscription.unsubscribe()
157
+ resolve()
158
+ })
159
+ })
160
+ }
161
+
162
+ async function requestCallback(): Promise<void> {
163
+ await whenReady()
164
+
165
+ try {
166
+ const response = await picked.actions.run('request-callback', { timeoutMs: 15_000 })
167
+ console.info('Callback response', response)
168
+ } catch (error) {
169
+ console.warn('Callback request failed', error)
170
+ }
171
+ }
172
+ ```
173
+
174
+ Set `timeoutMs` to stop the wait sooner. Set `signal` to stop the wait from your own code.
175
+
176
+ ## Related
177
+
178
+ - [SDK actions](/reference/sdk/actions) — every outcome, error and limit.
179
+ - [How to register an action handler](/how-to/register-an-action-handler) — return a
180
+ response from your own handler.
181
+ - [How to call an external API from a workflow](/how-to/call-an-external-api-from-a-workflow)
182
+ — a workflow that sends a response.
@@ -0,0 +1,57 @@
1
+ ---
2
+ type: how-to
3
+ layout: docs
4
+ ---
5
+
6
+ # How to write a condition
7
+
8
+ This guide shows you how to build a rule in the visual condition builder. The builder
9
+ appears on a condition node, on an experience condition, on an initialize-open condition,
10
+ and on a field option.
11
+
12
+ ## Steps
13
+
14
+ 1. Choose the node or the field that takes the condition.
15
+ 2. Find the **Logic** section in the inspector.
16
+ 3. Choose a data source: **Responses**, **Actions**, **Feature flags**, **Conditions**,
17
+ or **Window Location**.
18
+ 4. Choose an operator. The choices include equals, not equals, greater than, and
19
+ contains.
20
+ 5. Enter a value.
21
+
22
+ ## Join more than one rule
23
+
24
+ 1. Create an AND group or an OR group.
25
+ 2. Add your rules inside it.
26
+
27
+ With **AND** every rule must match. With **OR** one rule must match. Put a group inside
28
+ another group to build a larger rule.
29
+
30
+ ## Example
31
+
32
+ To show a step only to a visitor who is on one page and who accepted marketing:
33
+
34
+ 1. Create an AND group.
35
+ 2. Add a rule: **Window Location → pathname** equals `/pricing`.
36
+ 3. Add a rule: **Responses → `marketing_opt_in`** equals `true`.
37
+
38
+ The group matches only when both rules are true.
39
+
40
+ ## API and MCP
41
+
42
+ You can also do this task with the [Management API](/reference/management-api/schema), the [MCP server](/reference/tools/mcp), or code that you send to [`picked_run`](/reference/tools/mcp-run).
43
+
44
+ | Task | GraphQL | MCP tool | Run |
45
+ | --- | --- | --- | --- |
46
+ | Write the rule of a condition node | [`conditionUpdate`](/reference/management-api/schema/condition#conditionupdate), [`experienceFlowUpdate`](/reference/management-api/schema/experience#experienceflowupdate) | [`update_experience_flow`](/reference/tools/mcp#update_experience_flow) | `tools.update_experience_flow({ experience_id, workspace_id, update_conditions })` |
47
+ | Write the experience condition or the initialize-open condition | [`experienceUpdate`](/reference/management-api/schema/experience#experienceupdate), [`experienceFlowUpdate`](/reference/management-api/schema/experience#experienceflowupdate) | [`update_experience_flow`](/reference/tools/mcp#update_experience_flow) | `tools.update_experience_flow({ experience_id, workspace_id, condition, initialize_open })` |
48
+ | Write the condition of a field option | [`fieldUpdate`](/reference/management-api/schema/field#fieldupdate), [`experienceFlowUpdate`](/reference/management-api/schema/experience#experienceflowupdate) | [`update_experience_flow`](/reference/tools/mcp#update_experience_flow) | `tools.update_experience_flow({ experience_id, workspace_id, update_fields })` |
49
+
50
+ The API and the MCP server take each rule as a JSON Logic expression.
51
+
52
+ ## Related
53
+
54
+ - [About conditions and the logic engine](/explanation/conditions-and-the-logic-engine) —
55
+ what a rule can read.
56
+ - [Condition builder](/reference/dashboard/flow-builder/condition-builder) — the rule
57
+ structure.
@@ -0,0 +1,60 @@
1
+ ---
2
+ type: how-to
3
+ layout: docs
4
+ ---
5
+
6
+ # How to write a predicate
7
+
8
+ This guide shows you how to let a condition read data that only your application holds,
9
+ such as a cart total or an account level.
10
+
11
+ ## 1. Define the predicate
12
+
13
+ Pass a `predicates` object to `createClient()`:
14
+
15
+ ```ts
16
+ import { createClient } from 'picked'
17
+
18
+ const client = createClient({
19
+ projectId: 'your-project-id',
20
+ predicates: {
21
+ 'is-example-page': ({ location }) => location?.pathname === '/example',
22
+ 'get-account-tier': async () => {
23
+ const data = await fetch('/api/get-account-tier').then((r) => r.json())
24
+ return data.result
25
+ },
26
+ },
27
+ })
28
+ ```
29
+
30
+ A predicate returns a boolean, a string, an array of strings, or `undefined`. It can also
31
+ return a promise that resolves to one of those.
32
+
33
+ ## 2. Invoke it from a condition
34
+
35
+ ```ts
36
+ condition: {
37
+ '==': [
38
+ { invoke: { var: 'predicates.is-example-page' } },
39
+ true,
40
+ ],
41
+ }
42
+ ```
43
+
44
+ :::tip
45
+ A predicate also works inside `validation` logic.
46
+ :::
47
+
48
+ ## Keep it pure and fast
49
+
50
+ - The same snapshot must always give the same result.
51
+ - Check that a response or a field is there before you read its value. Return `undefined`
52
+ when the data is not available, and do not throw.
53
+ - The SDK can invoke a predicate many times, so keep the logic small.
54
+ - Do not change the snapshot. It is frozen, and a change to it throws in strict mode.
55
+
56
+ ## Related
57
+
58
+ - [Predicates](/reference/sdk/predicates) — the state snapshot shape.
59
+ - [About conditions and the logic engine](/explanation/conditions-and-the-logic-engine) —
60
+ why predicates exist.
package/docs/index.md ADDED
@@ -0,0 +1,59 @@
1
+ ---
2
+ type: map
3
+ layout: docs
4
+ ---
5
+
6
+ # Picked documentation
7
+
8
+ Picked lets you build personalized UI flows in a visual editor. The SDK then serves them
9
+ to the visitors on your site.
10
+
11
+ There are two paths to follow. Choose the one that matches your work.
12
+
13
+ ## Work in the dashboard
14
+
15
+ Build experiences, write content, and publish.
16
+
17
+ Start with [build your first experience](/tutorials/first-experience-in-the-dashboard).
18
+ It takes you from an empty project to a survey on your own site, and it needs no
19
+ development tools.
20
+
21
+ One thing must happen first: a developer adds the Picked SDK to your site one time. After
22
+ that, the dashboard is all you need.
23
+
24
+ Then:
25
+
26
+ - **[Build](/how-to/create-an-experience)** — experiences, flows, conditions, and A/B
27
+ tests.
28
+ - **[Content](/how-to/define-a-page-layout)** — Models, Blocks, entries, pages, and assets.
29
+ - **[Publish](/how-to/publish-a-workspace)** — preview, publish, and roll back.
30
+ - **[Administer and measure](/how-to/invite-and-remove-members)** — members, API keys,
31
+ analytics, and the tools that connect Picked to Google Tag Manager and to an AI tool.
32
+ - **[Dashboard reference](/reference/dashboard/projects)** — every dashboard screen and
33
+ every option, plus the [glossary](/reference/glossary).
34
+ - **[How Picked works](/explanation/how-picked-works)** — what happens when you publish.
35
+
36
+ ## Integrate with code
37
+
38
+ Add Picked to a site or an application. Your code then renders the experiences that the
39
+ dashboard describes.
40
+
41
+ Start with [add Picked to your application](/tutorials/first-experience). It goes from an
42
+ empty project to a survey that runs in React or in Svelte.
43
+
44
+ Read the dashboard documents above also. Everything your code renders is described
45
+ there, so the two paths link to each other rather than repeat.
46
+
47
+ Then:
48
+
49
+ - **[Integrate the SDK](/how-to/install-the-sdk)** — install, register a component, read
50
+ a feature flag.
51
+ - **[Build a step form](/how-to/render-a-step-form)** — render fields, act on a
52
+ submission, validate input.
53
+ - **[Server-side rendering](/how-to/server-render-a-page)** — a page that a search engine
54
+ can read.
55
+ - **[Authenticate](/how-to/authenticate-with-a-password)** — the management API.
56
+ - **[SDK reference](/reference/sdk)**, **[Delivery API](/reference/delivery-api)**,
57
+ **[PickedQL](/reference/pickedql)**.
58
+ - **[Why it works this way](/explanation/why-server-side-rendering)** — the design
59
+ behind the SDK.
@@ -0,0 +1,65 @@
1
+ ---
2
+ type: reference
3
+ layout: docs
4
+ ---
5
+
6
+ import { Screenshot } from '../../../../components/Screenshot'
7
+
8
+ # Actions
9
+
10
+ An action is a side effect that starts when the flow reaches it. Use an action to
11
+ track an event, to send data to an external service, or to call a webhook.
12
+
13
+ <Screenshot
14
+ route="/{orgSlug}/{projectId}/workspaces/{workspaceId}/actions"
15
+ alt="The actions list for a workspace on the Picked dashboard"
16
+ />
17
+
18
+ ## Set up an action
19
+
20
+ **Name**: The name that the dashboard shows. Your visitors do not see it.
21
+
22
+ **Key**: The identifier that your application uses for this action. Your visitors do
23
+ not see it.
24
+
25
+ ## Register in your application
26
+
27
+ A published action that starts a workflow needs no code in your application. The SDK
28
+ sends the request to Picked, and the workflow runs there.
29
+
30
+ To run your own code, pass a handler under the action key in `createClient()`. That handler
31
+ replaces the workflow for this key. See
32
+ [How to register an action handler](/how-to/register-an-action-handler) for the code, and
33
+ [SDK actions](/reference/sdk/actions) for what the handler receives and returns.
34
+
35
+ ## Use actions in flows
36
+
37
+ In the flow builder, drag an action from the library onto the canvas. Connect it to
38
+ the point in the flow where you want it to start.
39
+
40
+ An action runs when the flow reaches its node. It does not interrupt your visitor. By
41
+ default the flow continues to the next connected node.
42
+
43
+ An action node can carry a **success** branch and a **failure** branch. Which one the flow
44
+ takes depends on whether your handler throws, and a returned `false` is a success. See
45
+ [How an action decides which way to go](/explanation/how-picked-works#how-an-action-decides-which-way-to-go).
46
+
47
+ ## Reuse actions
48
+
49
+ An action belongs to the project. Use the same action in more than one experience flow.
50
+ A change to the options of an action applies at every place that uses it.
51
+
52
+ ## API and MCP
53
+
54
+ You can also do this task with the [Management API](/reference/management-api/schema), the [MCP server](/reference/tools/mcp), or code that you send to [`picked_run`](/reference/tools/mcp-run).
55
+
56
+ | Task | GraphQL | MCP tool | Run |
57
+ | --- | --- | --- | --- |
58
+ | Create an action | [`actionCreate`](/reference/management-api/schema/action#actioncreate), [`experienceFlowUpdate`](/reference/management-api/schema/experience#experienceflowupdate) | [`update_experience_flow`](/reference/tools/mcp#update_experience_flow) | `tools.update_experience_flow({ experience_id, workspace_id, create_actions, create_nodes })` |
59
+ | Add an action to a flow | [`experienceFlowUpdate`](/reference/management-api/schema/experience#experienceflowupdate) | [`update_experience_flow`](/reference/tools/mcp#update_experience_flow) | `tools.update_experience_flow({ experience_id, workspace_id, create_nodes, create_edges })` |
60
+
61
+ ## Related
62
+
63
+ - [How to add a step, a field, an action, or a condition](/how-to/add-a-step-field-or-action)
64
+ - [How to register an action handler](/how-to/register-an-action-handler)
65
+ - [SDK actions](/reference/sdk/actions) — what the handler receives and returns.
@@ -0,0 +1,47 @@
1
+ ---
2
+ type: reference
3
+ layout: docs
4
+ ---
5
+
6
+ import { Screenshot } from '../../../../components/Screenshot'
7
+
8
+ # API keys
9
+
10
+ An API key lets your code reach the Picked API. Use one where your own code calls the API,
11
+ such as a server-side integration. It does not sign the
12
+ [CLI](/reference/tools/cli) in.
13
+
14
+ <Screenshot
15
+ route="/{orgSlug}/api-keys"
16
+ alt="The API keys list for an organization on the Picked dashboard"
17
+ />
18
+
19
+ ## Use an API key
20
+
21
+ Put your API key in the `x-api-key` header of each request to the
22
+ [Picked API](/tutorials/first-api-call).
23
+
24
+ ```
25
+ x-api-key: your-api-key
26
+ ```
27
+
28
+ ## Scopes
29
+
30
+ An API key carries scopes, and the scopes limit what the key can reach. Choose the
31
+ scopes that your integration needs when you create the key. A key can do only the
32
+ operations that its scopes permit.
33
+
34
+ ## API and MCP
35
+
36
+ You can also do this task with the [Management API](/reference/management-api/schema), the [MCP server](/reference/tools/mcp), or code that you send to [`picked_run`](/reference/tools/mcp-run).
37
+
38
+ | Task | GraphQL | MCP tool | Run |
39
+ | --- | --- | --- | --- |
40
+ | List the API keys | [`apiKeys`](/reference/management-api/schema/api-key#apikeys) | None | None |
41
+ | Create a key with its scopes | [`apiKeyCreate`](/reference/management-api/schema/api-key#apikeycreate) | None | None |
42
+
43
+ ## Related
44
+
45
+ - [How to create and revoke an API key](/how-to/create-and-revoke-an-api-key)
46
+ - [How to authenticate with an API key](/how-to/authenticate-with-an-api-key) — the API
47
+ side.
@@ -0,0 +1,51 @@
1
+ ---
2
+ type: reference
3
+ layout: docs
4
+ ---
5
+
6
+ import { Screenshot } from '../../../../components/Screenshot'
7
+
8
+ # Conditions
9
+
10
+ A condition evaluates a rule and splits the flow into two paths. One path is for a
11
+ true result, the other for a false result.
12
+
13
+ <Screenshot
14
+ route="/{orgSlug}/{projectId}/workspaces/{workspaceId}/conditions"
15
+ alt="The conditions list for a workspace on the Picked dashboard"
16
+ />
17
+
18
+ ## Set up a condition
19
+
20
+ **Name**: The name that the dashboard shows. Your visitors do not see it.
21
+
22
+ **Key**: The identifier for your application. You set it once and you cannot change
23
+ it. Your visitors do not see it.
24
+
25
+ ## Branches
26
+
27
+ In the flow builder, a condition node has two output handles. The green handle, for a
28
+ true result, leads to the path for a match. The red handle, for a false result, leads
29
+ to the other path.
30
+
31
+ You can chain conditions. Connect the output of one condition to the input of another
32
+ to build a decision tree.
33
+
34
+ ## API and MCP
35
+
36
+ You can also do this task with the [Management API](/reference/management-api/schema), the [MCP server](/reference/tools/mcp), or code that you send to [`picked_run`](/reference/tools/mcp-run).
37
+
38
+ | Task | GraphQL | MCP tool | Run |
39
+ | --- | --- | --- | --- |
40
+ | Create a condition | [`conditionCreate`](/reference/management-api/schema/condition#conditioncreate), [`experienceFlowUpdate`](/reference/management-api/schema/experience#experienceflowupdate) | [`update_experience_flow`](/reference/tools/mcp#update_experience_flow) | `tools.update_experience_flow({ experience_id, workspace_id, create_conditions, create_nodes })` |
41
+ | Connect the true path and the false path | [`experienceFlowUpdate`](/reference/management-api/schema/experience#experienceflowupdate) | [`update_experience_flow`](/reference/tools/mcp#update_experience_flow) | `tools.update_experience_flow({ experience_id, workspace_id, create_edges })` |
42
+
43
+ ## Related
44
+
45
+ - [How to add a step, a field, an action, or a condition](/how-to/add-a-step-field-or-action)
46
+
47
+ - [About conditions and the logic engine](/explanation/conditions-and-the-logic-engine) —
48
+ what a rule can read.
49
+ - [How to write a condition](/how-to/write-a-condition)
50
+ - [Condition builder](/reference/dashboard/flow-builder/condition-builder) — the data
51
+ sources and the rule structure.