@picked/client 0.0.1-dev.1785826066660 → 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 -1
- package/dist/{api-d0qKmzPH.js → api-03c5jvVk.js} +1 -1
- package/dist/{api-Djuh2gfe.cjs → api-CQxCVIrm.cjs} +1 -1
- package/dist/cjs/index.js +2 -2
- 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} +19 -6
- 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/{flow-builder/building-flows.md → how-to/build-a-flow.md} +13 -9
- 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/{gtm-template.md → how-to/install-the-gtm-template.md} +9 -3
- 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 -70
- package/dist/docs/reference/dashboard/actions.mdx +53 -0
- package/dist/docs/{api-keys.mdx → reference/dashboard/api-keys.mdx} +7 -15
- package/dist/docs/reference/dashboard/conditions.mdx +42 -0
- package/dist/docs/reference/dashboard/content/asset-library.mdx +63 -0
- package/dist/docs/{content → reference/dashboard/content}/content-entries.mdx +11 -3
- package/dist/docs/{content → reference/dashboard/content}/layouts.mdx +11 -35
- package/dist/docs/reference/dashboard/content/pages.mdx +35 -0
- package/dist/docs/reference/dashboard/content/sections.mdx +28 -0
- package/dist/docs/{experiences.mdx → reference/dashboard/experiences.mdx} +9 -16
- package/dist/docs/{features.mdx → reference/dashboard/features.mdx} +26 -41
- package/dist/docs/{fields.mdx → reference/dashboard/fields.mdx} +26 -20
- package/dist/docs/{flow-builder/overview.mdx → reference/dashboard/flow-builder/canvas.mdx} +8 -13
- package/dist/docs/{flow-builder → reference/dashboard/flow-builder}/condition-builder.md +5 -13
- package/dist/docs/{flow-builder → reference/dashboard/flow-builder}/keyboard-shortcuts.md +7 -1
- package/dist/docs/{flow-builder → reference/dashboard/flow-builder}/nodes.md +10 -3
- 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/{team-management.md → reference/dashboard/team-management.md} +5 -22
- package/dist/docs/{workspace-versioning.mdx → reference/dashboard/workspace-versioning.mdx} +6 -10
- package/dist/docs/reference/dashboard/workspaces.mdx +76 -0
- package/dist/docs/{delivery-api → reference/delivery-api}/experience-content.md +11 -4
- package/dist/docs/reference/delivery-api/index.md +45 -0
- package/dist/docs/{delivery-api → reference/delivery-api}/preview-caching-crawling.md +12 -5
- package/dist/docs/{delivery-api → reference/delivery-api}/project-config.md +11 -4
- 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 +10 -3
- package/dist/docs/{api → reference/management-api}/error-handling.md +9 -3
- package/dist/docs/{api → reference/management-api}/pagination.md +6 -0
- package/dist/docs/{pickedql → reference/pickedql}/data-sources.md +16 -9
- package/dist/docs/{pickedql → reference/pickedql}/dimensions.md +7 -0
- package/dist/docs/{pickedql → reference/pickedql}/filtering.md +7 -0
- package/dist/docs/reference/pickedql/index.md +18 -0
- package/dist/docs/{pickedql → reference/pickedql}/schema.md +13 -6
- package/dist/docs/{pickedql → reference/pickedql}/virtual-functions.md +7 -0
- package/dist/docs/reference/sdk/actions.md +30 -0
- package/dist/docs/{sdk → reference/sdk}/conditions.md +8 -1
- package/dist/docs/reference/sdk/content-security-policy.md +21 -0
- package/dist/docs/reference/sdk/experiences.md +51 -0
- package/dist/docs/{sdk → reference/sdk}/features.md +30 -117
- package/dist/docs/{sdk → reference/sdk}/fields.md +10 -88
- package/dist/docs/reference/sdk/index.md +68 -0
- package/dist/docs/{sdk → reference/sdk}/plugins/create-experience.md +10 -22
- 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/{sdk → reference/sdk}/ssr/rendering-and-hydration.md +4 -63
- package/dist/docs/{sdk → reference/sdk}/ssr/serialize.md +6 -33
- package/dist/docs/{sdk → reference/sdk}/ssr/slots-and-placements.md +7 -1
- package/dist/docs/reference/sdk/steps.md +87 -0
- package/dist/docs/reference/tools/chrome-extension.md +16 -0
- package/dist/docs/{image-optimisation-service.md → reference/tools/image-optimisation-service.md} +8 -0
- package/dist/docs/{mcp.md → reference/tools/mcp.md} +5 -45
- package/dist/docs/{vite-plugin.md → reference/tools/vite-plugin.md} +34 -35
- package/dist/docs/{api/index.md → tutorials/first-api-call.md} +27 -15
- 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/esm/index.js +290 -319
- package/dist/esm/plugins/dynamic-experiences/index.js +3 -3
- package/dist/esm/server/index.js +22 -22
- package/dist/plugin-CHOVsx7Z.js +287 -0
- package/dist/plugin-DsaGXQHx.cjs +1 -0
- 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/feature/feature.d.ts +16 -0
- package/dist/types/entities/feature/feature.d.ts.map +1 -1
- package/dist/types/exports.d.ts +0 -2
- package/dist/types/exports.d.ts.map +1 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/picked.d.ts +15 -0
- package/dist/types/picked.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 +2 -34
- package/dist/types/plugins/dynamic-experiences/plugin.d.ts.map +1 -1
- package/dist/types/plugins/dynamic-experiences/types.d.ts +34 -16
- package/dist/types/plugins/dynamic-experiences/types.d.ts.map +1 -1
- package/dist/types/server/serialize.d.ts +7 -6
- package/dist/types/server/serialize.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/docs/actions.mdx +0 -98
- package/dist/docs/api/authentication.md +0 -403
- package/dist/docs/chrome-extension.md +0 -68
- package/dist/docs/conditions.mdx +0 -72
- package/dist/docs/content/asset-library.mdx +0 -124
- package/dist/docs/content/pages.mdx +0 -82
- package/dist/docs/content/sections.mdx +0 -44
- package/dist/docs/delivery-api/index.md +0 -53
- package/dist/docs/guides/build-a-personalized-page.mdx +0 -161
- package/dist/docs/pickedql/index.md +0 -54
- package/dist/docs/projects.mdx +0 -44
- package/dist/docs/reports.mdx +0 -20
- package/dist/docs/sdk/actions.md +0 -82
- package/dist/docs/sdk/content-security-policy.md +0 -33
- package/dist/docs/sdk/experiences.md +0 -64
- package/dist/docs/sdk/feature-allocation.md +0 -161
- package/dist/docs/sdk/index.md +0 -98
- package/dist/docs/sdk/plugins/dynamic-experiences.md +0 -84
- package/dist/docs/sdk/plugins/index.md +0 -9
- package/dist/docs/sdk/predicates.md +0 -128
- package/dist/docs/sdk/ssr/index.md +0 -79
- package/dist/docs/sdk/steps.md +0 -479
- package/dist/docs/steps.mdx +0 -53
- package/dist/docs/workspaces.mdx +0 -133
- package/dist/plugin-BVAFWjpT.js +0 -252
- package/dist/plugin-BcCn2llk.cjs +0 -1
- package/dist/types/entities/content/reference.d.ts +0 -101
- package/dist/types/entities/content/reference.d.ts.map +0 -1
|
@@ -1,403 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
layout: docs
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Authentication
|
|
6
|
-
|
|
7
|
-
The Picked API supports four ways to authenticate. They are a session from an email
|
|
8
|
-
address and a password, an OAuth provider, a magic link, and an API key. This guide
|
|
9
|
-
covers each one. It also covers how to control a session and how to use multi-factor
|
|
10
|
-
authentication (MFA).
|
|
11
|
-
|
|
12
|
-
## Sign in with an email address and a password
|
|
13
|
-
|
|
14
|
-
The `sessionCreate` mutation authenticates a user from an email address and a
|
|
15
|
-
password. It returns a session.
|
|
16
|
-
|
|
17
|
-
```graphql
|
|
18
|
-
mutation {
|
|
19
|
-
sessionCreate(input: {
|
|
20
|
-
email: "user@example.com"
|
|
21
|
-
password: "secure-password"
|
|
22
|
-
}) {
|
|
23
|
-
session {
|
|
24
|
-
accessToken
|
|
25
|
-
refreshToken
|
|
26
|
-
expiresAt
|
|
27
|
-
user {
|
|
28
|
-
id
|
|
29
|
-
email
|
|
30
|
-
}
|
|
31
|
-
aal
|
|
32
|
-
}
|
|
33
|
-
requiresMfa
|
|
34
|
-
mfaFactors {
|
|
35
|
-
id
|
|
36
|
-
factorType
|
|
37
|
-
status
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
When the user has MFA on, the response sets `requiresMfa` to `true` and returns the
|
|
44
|
-
`mfaFactors` of that user. The caller must then complete an MFA challenge before it
|
|
45
|
-
receives a full session. See [MFA](#multi-factor-authentication-mfa) below.
|
|
46
|
-
|
|
47
|
-
When MFA is off, the response holds a `session` with an `accessToken`, a
|
|
48
|
-
`refreshToken`, and an `expiresAt` timestamp.
|
|
49
|
-
|
|
50
|
-
## Create an account
|
|
51
|
-
|
|
52
|
-
The `accountCreate` mutation creates a new account:
|
|
53
|
-
|
|
54
|
-
```graphql
|
|
55
|
-
mutation {
|
|
56
|
-
accountCreate(input: {
|
|
57
|
-
email: "newuser@example.com"
|
|
58
|
-
password: "secure-password"
|
|
59
|
-
metadata: { firstName: "Jane", lastName: "Doe" }
|
|
60
|
-
}) {
|
|
61
|
-
user {
|
|
62
|
-
id
|
|
63
|
-
email
|
|
64
|
-
}
|
|
65
|
-
session {
|
|
66
|
-
accessToken
|
|
67
|
-
refreshToken
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
The `metadata` field is optional. It takes any JSON, and you can hold profile
|
|
74
|
-
information in it. When the account needs email verification, the session in the
|
|
75
|
-
response is `null` until the user verifies the email address.
|
|
76
|
-
|
|
77
|
-
## Verify an email address
|
|
78
|
-
|
|
79
|
-
After you create the account, the user receives a verification email with a token.
|
|
80
|
-
The `accountVerifyEmail` mutation completes the verification:
|
|
81
|
-
|
|
82
|
-
```graphql
|
|
83
|
-
mutation {
|
|
84
|
-
accountVerifyEmail(input: {
|
|
85
|
-
email: "newuser@example.com"
|
|
86
|
-
token: "verification-token-from-email"
|
|
87
|
-
}) {
|
|
88
|
-
session {
|
|
89
|
-
accessToken
|
|
90
|
-
refreshToken
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
To send the verification email again:
|
|
97
|
-
|
|
98
|
-
```graphql
|
|
99
|
-
mutation {
|
|
100
|
-
accountResendVerification(input: {
|
|
101
|
-
email: "newuser@example.com"
|
|
102
|
-
}) {
|
|
103
|
-
success
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
## The OAuth flow with Google
|
|
109
|
-
|
|
110
|
-
The API supports Google as an OAuth provider. The flow has two steps.
|
|
111
|
-
|
|
112
|
-
### Step 1: get the authorization URL
|
|
113
|
-
|
|
114
|
-
```graphql
|
|
115
|
-
mutation {
|
|
116
|
-
oauthAuthorize(input: {
|
|
117
|
-
provider: GOOGLE
|
|
118
|
-
redirectUrl: "https://app.example.com/auth/callback"
|
|
119
|
-
scopes: ["openid", "email", "profile"]
|
|
120
|
-
}) {
|
|
121
|
-
url
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
The caller sends the user to the `url` in the response. The user authenticates with
|
|
127
|
-
Google. Google then sends the user back to a URL on the same dashboard deployment,
|
|
128
|
-
with a `code` parameter. The caller exchanges that code for a session.
|
|
129
|
-
|
|
130
|
-
### Step 2: exchange the code for a session
|
|
131
|
-
|
|
132
|
-
```graphql
|
|
133
|
-
mutation {
|
|
134
|
-
oauthCallback(input: {
|
|
135
|
-
provider: GOOGLE
|
|
136
|
-
code: "auth-code-from-google"
|
|
137
|
-
}) {
|
|
138
|
-
session {
|
|
139
|
-
accessToken
|
|
140
|
-
refreshToken
|
|
141
|
-
expiresAt
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
## Magic links
|
|
148
|
-
|
|
149
|
-
A magic link authenticates a user through an email address, with no password.
|
|
150
|
-
|
|
151
|
-
### Send a magic link
|
|
152
|
-
|
|
153
|
-
```graphql
|
|
154
|
-
mutation {
|
|
155
|
-
magicLinkSend(input: {
|
|
156
|
-
email: "user@example.com"
|
|
157
|
-
redirectUrl: "https://app.example.com/auth/verify"
|
|
158
|
-
}) {
|
|
159
|
-
success
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
The user receives an email with a link, and the link holds a token.
|
|
165
|
-
|
|
166
|
-
### Verify the magic link
|
|
167
|
-
|
|
168
|
-
```graphql
|
|
169
|
-
mutation {
|
|
170
|
-
magicLinkVerify(input: {
|
|
171
|
-
email: "user@example.com"
|
|
172
|
-
token: "token-from-magic-link"
|
|
173
|
-
}) {
|
|
174
|
-
session {
|
|
175
|
-
accessToken
|
|
176
|
-
refreshToken
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
## Passwords
|
|
183
|
-
|
|
184
|
-
### Reset a password
|
|
185
|
-
|
|
186
|
-
Send an email to reset the password:
|
|
187
|
-
|
|
188
|
-
```graphql
|
|
189
|
-
mutation {
|
|
190
|
-
passwordResetSend(input: {
|
|
191
|
-
email: "user@example.com"
|
|
192
|
-
redirectUrl: "https://app.example.com/reset-password"
|
|
193
|
-
}) {
|
|
194
|
-
success
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
Complete the reset with the token from that email:
|
|
200
|
-
|
|
201
|
-
```graphql
|
|
202
|
-
mutation {
|
|
203
|
-
passwordReset(input: {
|
|
204
|
-
email: "user@example.com"
|
|
205
|
-
token: "reset-token-from-email"
|
|
206
|
-
newPassword: "new-secure-password"
|
|
207
|
-
}) {
|
|
208
|
-
session {
|
|
209
|
-
accessToken
|
|
210
|
-
refreshToken
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
### Change a password
|
|
217
|
-
|
|
218
|
-
This mutation needs authentication:
|
|
219
|
-
|
|
220
|
-
```graphql
|
|
221
|
-
mutation {
|
|
222
|
-
passwordUpdate(input: {
|
|
223
|
-
currentPassword: "old-password"
|
|
224
|
-
newPassword: "new-secure-password"
|
|
225
|
-
}) {
|
|
226
|
-
success
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
## Multi-factor authentication (MFA)
|
|
232
|
-
|
|
233
|
-
MFA adds a second layer of security, and it uses a telephone to verify the user. The
|
|
234
|
-
API can add an MFA factor, send a challenge, verify a challenge, and remove a factor.
|
|
235
|
-
Every MFA mutation needs authentication.
|
|
236
|
-
|
|
237
|
-
### Add a factor
|
|
238
|
-
|
|
239
|
-
```graphql
|
|
240
|
-
mutation {
|
|
241
|
-
mfaFactorEnroll(input: {
|
|
242
|
-
factorType: PHONE
|
|
243
|
-
phone: "+15551234567"
|
|
244
|
-
friendlyName: "My Phone"
|
|
245
|
-
}) {
|
|
246
|
-
factor {
|
|
247
|
-
id
|
|
248
|
-
factorType
|
|
249
|
-
status
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
A new factor has the status `UNVERIFIED` until a challenge confirms it.
|
|
256
|
-
|
|
257
|
-
### Send a challenge
|
|
258
|
-
|
|
259
|
-
```graphql
|
|
260
|
-
mutation {
|
|
261
|
-
mfaChallengeSend(input: {
|
|
262
|
-
factorId: "factor-id"
|
|
263
|
-
}) {
|
|
264
|
-
challengeId
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
This sends a verification code to the telephone number of the factor.
|
|
270
|
-
|
|
271
|
-
### Verify the challenge
|
|
272
|
-
|
|
273
|
-
```graphql
|
|
274
|
-
mutation {
|
|
275
|
-
mfaChallengeVerify(input: {
|
|
276
|
-
factorId: "factor-id"
|
|
277
|
-
challengeId: "challenge-id"
|
|
278
|
-
code: "123456"
|
|
279
|
-
}) {
|
|
280
|
-
session {
|
|
281
|
-
accessToken
|
|
282
|
-
refreshToken
|
|
283
|
-
aal
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
On success, the session moves to Authenticator Assurance Level `AAL2`. The status of
|
|
290
|
-
the factor changes to `VERIFIED`.
|
|
291
|
-
|
|
292
|
-
### Remove a factor
|
|
293
|
-
|
|
294
|
-
```graphql
|
|
295
|
-
mutation {
|
|
296
|
-
mfaFactorUnenroll(input: {
|
|
297
|
-
factorId: "factor-id"
|
|
298
|
-
}) {
|
|
299
|
-
success
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
## Use a session
|
|
305
|
-
|
|
306
|
-
After the caller has a session, it puts the access token in the `Authorization`
|
|
307
|
-
header of every request that needs authentication:
|
|
308
|
-
|
|
309
|
-
```
|
|
310
|
-
Authorization: Bearer <accessToken>
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
The `expiresAt` field of the session gives the time at which the access token
|
|
314
|
-
expires. The caller must refresh the session before that time.
|
|
315
|
-
|
|
316
|
-
### Authenticator assurance levels
|
|
317
|
-
|
|
318
|
-
The session holds an `aal` field, and it gives the strength of the authentication:
|
|
319
|
-
|
|
320
|
-
| Level | Meaning |
|
|
321
|
-
|-------|---------|
|
|
322
|
-
| `AAL1` | One factor: an email address and a password, OAuth, or a magic link |
|
|
323
|
-
| `AAL2` | More than one factor: the user completed an MFA challenge |
|
|
324
|
-
|
|
325
|
-
Some operations need `AAL2`. When a caller at `AAL1` tries one of them, the API
|
|
326
|
-
returns an authorization error.
|
|
327
|
-
|
|
328
|
-
## Refresh a session
|
|
329
|
-
|
|
330
|
-
An access token has a short life. The `sessionRefresh` mutation exchanges a refresh
|
|
331
|
-
token for a new session:
|
|
332
|
-
|
|
333
|
-
```graphql
|
|
334
|
-
mutation {
|
|
335
|
-
sessionRefresh(input: {
|
|
336
|
-
refreshToken: "v1.refresh-token..."
|
|
337
|
-
}) {
|
|
338
|
-
session {
|
|
339
|
-
accessToken
|
|
340
|
-
refreshToken
|
|
341
|
-
expiresAt
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
The response holds a new `accessToken` and a new `refreshToken`. The API invalidates
|
|
348
|
-
the earlier refresh token. This mutation needs no `Authorization` header.
|
|
349
|
-
|
|
350
|
-
## API key authentication
|
|
351
|
-
|
|
352
|
-
An API key gives access to the API for a long time, inside a set of scopes. Most
|
|
353
|
-
callers use an API key for a server-to-server integration or for an automated
|
|
354
|
-
workflow.
|
|
355
|
-
|
|
356
|
-
To authenticate with an API key, include it in the `x-api-key` header:
|
|
357
|
-
|
|
358
|
-
```
|
|
359
|
-
x-api-key: pk_live_abc123...
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
An API key belongs to an organization, and it can also belong to one project. It
|
|
363
|
-
carries a set of [authorization scopes](./authorization-and-scopes.md), and those
|
|
364
|
-
scopes decide which operations the key can do.
|
|
365
|
-
|
|
366
|
-
See [API Keys](/api-keys) for how to control a key from the dashboard.
|
|
367
|
-
|
|
368
|
-
### Create an API key
|
|
369
|
-
|
|
370
|
-
The `apiKeyCreate` mutation creates a new API key. Only a user with a session can
|
|
371
|
-
call it. Another API key cannot:
|
|
372
|
-
|
|
373
|
-
```graphql
|
|
374
|
-
mutation {
|
|
375
|
-
apiKeyCreate(input: {
|
|
376
|
-
organizationId: "org-id"
|
|
377
|
-
name: "CI/CD Pipeline Key"
|
|
378
|
-
projectId: "project-id"
|
|
379
|
-
scopes: [ORGANIZATION_READ, ORGANIZATION_PROJECTS_READ]
|
|
380
|
-
}) {
|
|
381
|
-
apiKey
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
```
|
|
385
|
-
|
|
386
|
-
The response holds the full API key string one time only. Keep it in a secure place, because
|
|
387
|
-
you cannot read it again.
|
|
388
|
-
|
|
389
|
-
The scopes that you ask for must all be scopes of the user who creates the key. See
|
|
390
|
-
[Authorization and Scopes](./authorization-and-scopes.md) for more detail.
|
|
391
|
-
|
|
392
|
-
### Revoke an API key
|
|
393
|
-
|
|
394
|
-
```graphql
|
|
395
|
-
mutation {
|
|
396
|
-
apiKeyRevoke(input: {
|
|
397
|
-
keyId: "key-id"
|
|
398
|
-
organizationId: "org-id"
|
|
399
|
-
})
|
|
400
|
-
}
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
The API invalidates a revoked key immediately. No later request can use it.
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
layout: docs
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Chrome Extension
|
|
6
|
-
|
|
7
|
-
The extension for the Picked Developer Tools adds a Picked panel to Chrome DevTools.
|
|
8
|
-
Use the panel to check and debug your Picked integration on any page that runs the
|
|
9
|
-
SDK.
|
|
10
|
-
|
|
11
|
-

|
|
12
|
-
|
|
13
|
-
## Installation
|
|
14
|
-
|
|
15
|
-
Install the extension from the
|
|
16
|
-
[Chrome Web Store](https://chromewebstore.google.com/detail/picked-developer-tools/nimmdamgnhlhdpngnalkpmnleebngidh).
|
|
17
|
-
|
|
18
|
-
## Setup
|
|
19
|
-
|
|
20
|
-
Add the `svelteDevtoolsPlugin` to your Picked client. The extension then connects to
|
|
21
|
-
the SDK.
|
|
22
|
-
|
|
23
|
-
```typescript
|
|
24
|
-
import { createPicked } from '@picked/client'
|
|
25
|
-
import { svelteDevtoolsPlugin } from '@picked/svelte/plugins/devtools'
|
|
26
|
-
|
|
27
|
-
const picked = createPicked({
|
|
28
|
-
projectId: 'your-project-id',
|
|
29
|
-
plugins: [
|
|
30
|
-
svelteDevtoolsPlugin(),
|
|
31
|
-
],
|
|
32
|
-
})
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Custom Tools
|
|
36
|
-
|
|
37
|
-
You can extend the Developer Tools with your own tools for one project. They appear
|
|
38
|
-
under a **Custom Tools** tab.
|
|
39
|
-
|
|
40
|
-
Each tool is a framework-adapted component. Write it with the same
|
|
41
|
-
`adaptReactComponent` or `adaptSvelteComponent` helper that you already use. You can
|
|
42
|
-
therefore build the tool in the framework of your application.
|
|
43
|
-
|
|
44
|
-
The tool receives the live Picked client, exactly as an experience component does. In
|
|
45
|
-
React, use `usePicked()`. In Svelte, use `getPicked()`. A tool can read client state
|
|
46
|
-
and call client methods.
|
|
47
|
-
|
|
48
|
-
```typescript
|
|
49
|
-
import { createPicked } from '@picked/client'
|
|
50
|
-
import { adaptReactComponent } from '@picked/react'
|
|
51
|
-
import { svelteDevtoolsPlugin } from '@picked/svelte/plugins/devtools'
|
|
52
|
-
import MyTool from './MyTool'
|
|
53
|
-
|
|
54
|
-
const picked = createPicked({
|
|
55
|
-
projectId: 'your-project-id',
|
|
56
|
-
plugins: [
|
|
57
|
-
svelteDevtoolsPlugin({
|
|
58
|
-
customTools: [{ id: 'my-tool', label: 'My Tool', component: adaptReactComponent(MyTool) }],
|
|
59
|
-
}),
|
|
60
|
-
],
|
|
61
|
-
})
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
Svelte renders the Developer Tools shell, so you must also register the framework of
|
|
65
|
-
your tool on the client. A React application needs `reactFrameworkPlugin` for the
|
|
66
|
-
tool, together with the Svelte framework and `svelteDevtoolsPlugin` for the shell.
|
|
67
|
-
When the framework of a tool is not registered, the tab of that tool shows a warning
|
|
68
|
-
and no content.
|
package/dist/docs/conditions.mdx
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
layout: docs
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
import { Screenshot } from '../../components/Screenshot'
|
|
6
|
-
|
|
7
|
-
# Conditions
|
|
8
|
-
|
|
9
|
-
A condition evaluates a rule and splits the flow into two paths. One path is for a
|
|
10
|
-
true result, the other for a false result.
|
|
11
|
-
|
|
12
|
-
<Screenshot
|
|
13
|
-
route="/{orgSlug}/{projectId}/workspaces/{workspaceId}/conditions"
|
|
14
|
-
alt="The conditions list for a workspace on the Picked dashboard"
|
|
15
|
-
/>
|
|
16
|
-
|
|
17
|
-
## Create a condition
|
|
18
|
-
|
|
19
|
-
1. Open your project.
|
|
20
|
-
2. Click **Conditions** in the sidebar.
|
|
21
|
-
3. Click **New Condition**.
|
|
22
|
-
4. Enter a name and a key.
|
|
23
|
-
5. Click **Create**.
|
|
24
|
-
|
|
25
|
-
## Set up a condition
|
|
26
|
-
|
|
27
|
-
**Name**: The name that the dashboard shows. Your visitors do not see it.
|
|
28
|
-
|
|
29
|
-
**Key**: The identifier for your application. You set it once and you cannot change
|
|
30
|
-
it. Your visitors do not see it.
|
|
31
|
-
|
|
32
|
-
## Define the rule
|
|
33
|
-
|
|
34
|
-
Choose a condition node in the flow builder to open its inspector. The **Logic**
|
|
35
|
-
section holds a visual [condition builder](/flow-builder/condition-builder).
|
|
36
|
-
|
|
37
|
-
The condition builder lets you write a rule with AND groups and OR groups. Each rule
|
|
38
|
-
compares a data source against an operator and a value.
|
|
39
|
-
|
|
40
|
-
### Data sources
|
|
41
|
-
|
|
42
|
-
**Responses** — the values that your visitors send through form fields. An example is
|
|
43
|
-
a check of whether a visitor entered one email domain, or chose one option.
|
|
44
|
-
|
|
45
|
-
**Actions** — the actions that ran during the flow.
|
|
46
|
-
|
|
47
|
-
**Feature flags** — the state of each feature flag in your project. Branch on whether
|
|
48
|
-
Picked allocates a visitor to a flag.
|
|
49
|
-
|
|
50
|
-
**Location** — the parts of the current page URL of the visitor. These are the
|
|
51
|
-
pathname, the search parameters, the hostname, and the hash. An example is content
|
|
52
|
-
that changes with the page that the visitor is on.
|
|
53
|
-
|
|
54
|
-
### Example
|
|
55
|
-
|
|
56
|
-
To take a branch on the country that a visitor chooses:
|
|
57
|
-
|
|
58
|
-
1. Add a rule: **Responses → country** equals `US`.
|
|
59
|
-
2. The green path, for a true result, handles a visitor in the US. The red path, for
|
|
60
|
-
a false result, handles every other visitor.
|
|
61
|
-
|
|
62
|
-
To join more than one rule, create an AND group or an OR group and add the rules
|
|
63
|
-
inside it.
|
|
64
|
-
|
|
65
|
-
## Branches
|
|
66
|
-
|
|
67
|
-
In the flow builder, a condition node has two output handles. The green handle, for a
|
|
68
|
-
true result, leads to the path for a match. The red handle, for a false result, leads
|
|
69
|
-
to the other path.
|
|
70
|
-
|
|
71
|
-
You can chain conditions. Connect the output of one condition to the input of another
|
|
72
|
-
to build a decision tree.
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
layout: docs
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
import { Screenshot } from '../../../components/Screenshot'
|
|
6
|
-
|
|
7
|
-
# Asset Library
|
|
8
|
-
|
|
9
|
-
The Asset Library holds the files that your content points at. These are images,
|
|
10
|
-
video, documents, and HTML.
|
|
11
|
-
|
|
12
|
-
<Screenshot
|
|
13
|
-
route="/{orgSlug}/{projectId}/assets"
|
|
14
|
-
alt="The asset library on the Picked dashboard"
|
|
15
|
-
/>
|
|
16
|
-
|
|
17
|
-
## Upload and control your assets
|
|
18
|
-
|
|
19
|
-
The Asset Library is a project-level store. Upload a file, then point at it from any
|
|
20
|
-
Content Entry in the project.
|
|
21
|
-
|
|
22
|
-
- **Size limit:** 50 MB for each file.
|
|
23
|
-
- **Allowed types:** an image in PNG, JPEG, WebP, AVIF, GIF, or SVG. A video in MP4
|
|
24
|
-
or WebM. A common document format. HTML, as `text/html`.
|
|
25
|
-
|
|
26
|
-
Picked rejects a file of another type. It also rejects a file above the size limit.
|
|
27
|
-
|
|
28
|
-
## Reference an asset from a field
|
|
29
|
-
|
|
30
|
-
Two field types point at an item in the library:
|
|
31
|
-
|
|
32
|
-
- An **Asset** field points at an image, a video, or a document.
|
|
33
|
-
- An **HTML asset** field takes a `.html` file from your library.
|
|
34
|
-
|
|
35
|
-
Add the field to a [layout](/content/layouts). Then choose an item from the library
|
|
36
|
-
when you fill in the [Content Entry](/content/content-entries).
|
|
37
|
-
|
|
38
|
-
## Pick an asset
|
|
39
|
-
|
|
40
|
-
Every Asset field opens the same picker. Click **Choose file** to open it. On a field
|
|
41
|
-
with a value already, click **Replace**. The modal has two tabs: **Library**, where
|
|
42
|
-
you browse the assets that are there, and **Upload**, where you add a new file.
|
|
43
|
-
|
|
44
|
-
<Screenshot
|
|
45
|
-
route="/{orgSlug}/{projectId}/design-systems/new"
|
|
46
|
-
wait='button:has-text("Upload file")'
|
|
47
|
-
click='button:has-text("Upload file")'
|
|
48
|
-
selector="[role=dialog]"
|
|
49
|
-
alt="The asset picker modal on the Picked dashboard, with the Library tab, its search box, its type filter, and its Sort by menu"
|
|
50
|
-
renderWidth={1072}
|
|
51
|
-
renderHeight={790}
|
|
52
|
-
/>
|
|
53
|
-
|
|
54
|
-
### Search, filter, and sort
|
|
55
|
-
|
|
56
|
-
The Library tab has three controls that make a large asset list smaller. The server
|
|
57
|
-
applies each one across the whole library, and not only across the assets that it
|
|
58
|
-
loaded already:
|
|
59
|
-
|
|
60
|
-
- **Search:** narrows the list by file name while you type.
|
|
61
|
-
- **Type filter:** narrows the list to one media type. The choices are All types,
|
|
62
|
-
Images, Video, Audio, Documents, and Archive files.
|
|
63
|
-
- **Sort by:** orders the list by the Name or by the Date uploaded, each one
|
|
64
|
-
ascending or descending.
|
|
65
|
-
|
|
66
|
-
:::note
|
|
67
|
-
The results come one page at a time. Click **Load more** at the bottom of the list to
|
|
68
|
-
read the next page.
|
|
69
|
-
:::
|
|
70
|
-
|
|
71
|
-
### Choose one asset or several
|
|
72
|
-
|
|
73
|
-
The picker changes with the number of assets that the field takes:
|
|
74
|
-
|
|
75
|
-
- A field that holds one asset shows a **radio** indicator next to each row. The
|
|
76
|
-
Asset field of a layout and the guidance file of a design system both do this. A
|
|
77
|
-
new choice replaces the current asset.
|
|
78
|
-
- A place that takes several assets at once shows a **checkbox** indicator. The
|
|
79
|
-
detail panel then also shows a count of what you chose. The Files tab of a
|
|
80
|
-
workbench does this.
|
|
81
|
-
|
|
82
|
-
The detail panel on the right shows the kind, the dimensions, the size, and the
|
|
83
|
-
upload date of the asset that you chose.
|
|
84
|
-
|
|
85
|
-
### Open an asset in a new tab
|
|
86
|
-
|
|
87
|
-
Each row has an **Open in new tab** control, and so does the detail panel of the
|
|
88
|
-
asset that you chose. It links to the full detail page of the asset, and your choice
|
|
89
|
-
in the picker stays as it is.
|
|
90
|
-
|
|
91
|
-
:::tip
|
|
92
|
-
Use this to check an asset again before you choose it. You can see the full-size
|
|
93
|
-
preview and every version that somebody uploaded.
|
|
94
|
-
:::
|
|
95
|
-
|
|
96
|
-
## HTML assets
|
|
97
|
-
|
|
98
|
-
Upload a `.html` file and point at it from an **HTML asset** field. Picked then scans
|
|
99
|
-
the file. The scan is advisory: it helps you, and it never stops you. It
|
|
100
|
-
reports findings about speed, about search rank, and about accessibility, so that you
|
|
101
|
-
can improve the file before you publish it:
|
|
102
|
-
|
|
103
|
-
- **File size:** a warning at 100 KB, and a stronger one at 250 KB.
|
|
104
|
-
- **Inline images:** a note when inline `base64` image data adds about 50 KB or more.
|
|
105
|
-
- **Image dimensions:** an image with no width and no height. Such an image can move
|
|
106
|
-
the content around it while the page loads.
|
|
107
|
-
- **Lazy load:** an image with no `loading="lazy"` attribute.
|
|
108
|
-
- **Link safety:** an external link with `target="_blank"` and no `rel="noopener"`.
|
|
109
|
-
- **Link search rank:** an external link with no `rel="nofollow"`.
|
|
110
|
-
- **Accessibility:** a pass by `axe-core`. It covers alt text, heading order,
|
|
111
|
-
contrast, and more.
|
|
112
|
-
|
|
113
|
-
Every finding is advisory. You can always upload the file as it is.
|
|
114
|
-
|
|
115
|
-
## How assets are served
|
|
116
|
-
|
|
117
|
-
Picked serves each asset from a sandboxed storage origin. That origin is separate
|
|
118
|
-
from the trusted origin of your application. HTML therefore comes from its own
|
|
119
|
-
origin, so a document that you upload runs in isolation and cannot reach the page
|
|
120
|
-
that holds it.
|
|
121
|
-
|
|
122
|
-
An [Experience Content](/delivery-api/experience-content) response can hold an HTML
|
|
123
|
-
asset. The response then carries the content of that asset, and the SDK renders it
|
|
124
|
-
with no second request to storage.
|