@picked/client 0.0.1-dev.1786072899095 → 0.0.1-dev.1786601464574

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 (96) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/api-C8B96Kwv.js +22 -0
  3. package/dist/api-DS7fA9kj.cjs +1 -0
  4. package/dist/cjs/index.js +2 -2
  5. package/dist/cjs/plugins/dynamic-experiences/index.js +1 -1
  6. package/dist/cjs/server/index.js +1 -1
  7. package/dist/docs/explanation/content-references.md +99 -0
  8. package/dist/docs/explanation/how-picked-works.md +25 -3
  9. package/dist/docs/explanation/the-content-model.md +38 -28
  10. package/dist/docs/how-to/authenticate-the-cli.md +95 -0
  11. package/dist/docs/how-to/create-a-content-entry.md +48 -0
  12. package/dist/docs/how-to/define-a-page-layout.md +12 -5
  13. package/dist/docs/how-to/install-the-sdk.md +7 -0
  14. package/dist/docs/how-to/point-one-entry-at-another.md +61 -0
  15. package/dist/docs/how-to/read-a-referenced-entry.md +111 -0
  16. package/dist/docs/how-to/reuse-a-section.md +26 -10
  17. package/dist/docs/how-to/switch-workspaces.md +123 -0
  18. package/dist/docs/index.md +1 -1
  19. package/dist/docs/reference/dashboard/content/blocks.mdx +57 -0
  20. package/dist/docs/reference/dashboard/content/content-entries.mdx +61 -10
  21. package/dist/docs/reference/dashboard/content/models.mdx +108 -0
  22. package/dist/docs/reference/dashboard/content/pages.mdx +4 -3
  23. package/dist/docs/reference/dashboard/fields.mdx +1 -1
  24. package/dist/docs/reference/dashboard/steps.mdx +2 -2
  25. package/dist/docs/reference/delivery-api/experience-content.md +68 -13
  26. package/dist/docs/reference/delivery-api/workspace-schema.md +74 -0
  27. package/dist/docs/reference/glossary.md +13 -5
  28. package/dist/docs/reference/management-api/error-handling.md +2 -2
  29. package/dist/docs/reference/sdk/content.md +216 -0
  30. package/dist/docs/reference/sdk/plugins/dynamic-experiences.md +51 -3
  31. package/dist/docs/reference/sdk/ssr/serialize.md +6 -3
  32. package/dist/docs/reference/sdk/type-generation.md +130 -0
  33. package/dist/docs/reference/tools/cli.md +141 -0
  34. package/dist/docs/reference/tools/vite-plugin.md +90 -8
  35. package/dist/docs/tutorials/first-api-call.md +1 -1
  36. package/dist/docs/tutorials/first-server-rendered-page.mdx +1 -1
  37. package/dist/esm/index.js +496 -432
  38. package/dist/esm/plugins/dynamic-experiences/index.js +5 -3
  39. package/dist/esm/server/index.js +43 -46
  40. package/dist/plugin-C8hWW3ed.js +157 -0
  41. package/dist/plugin-Dtg2sOad.cjs +1 -0
  42. package/dist/provider-BEpRDCyr.js +69 -0
  43. package/dist/provider-ixdOyYTA.cjs +1 -0
  44. package/dist/registry-C1t8l3t9.cjs +1 -0
  45. package/dist/registry-CXZv0uLg.js +18 -0
  46. package/dist/types/data-source/api.d.ts +60 -0
  47. package/dist/types/data-source/api.d.ts.map +1 -0
  48. package/dist/types/data-source/provider.d.ts +90 -0
  49. package/dist/types/data-source/provider.d.ts.map +1 -0
  50. package/dist/types/data-source/registry.d.ts +26 -0
  51. package/dist/types/data-source/registry.d.ts.map +1 -0
  52. package/dist/types/data-source/virtual-data.d.ts +19 -0
  53. package/dist/types/data-source/virtual-data.d.ts.map +1 -0
  54. package/dist/types/entities/content/reference.d.ts +101 -0
  55. package/dist/types/entities/content/reference.d.ts.map +1 -0
  56. package/dist/types/entities/response/response.d.ts +22 -6
  57. package/dist/types/entities/response/response.d.ts.map +1 -1
  58. package/dist/types/exports.d.ts +2 -0
  59. package/dist/types/exports.d.ts.map +1 -1
  60. package/dist/types/form/create-submit-pipeline.d.ts +32 -3
  61. package/dist/types/form/create-submit-pipeline.d.ts.map +1 -1
  62. package/dist/types/index.d.ts +3 -0
  63. package/dist/types/index.d.ts.map +1 -1
  64. package/dist/types/picked.d.ts +68 -4
  65. package/dist/types/picked.d.ts.map +1 -1
  66. package/dist/types/ping.d.ts +4 -3
  67. package/dist/types/ping.d.ts.map +1 -1
  68. package/dist/types/plugins/dynamic-experiences/index.d.ts +2 -1
  69. package/dist/types/plugins/dynamic-experiences/index.d.ts.map +1 -1
  70. package/dist/types/plugins/dynamic-experiences/plugin.d.ts +9 -40
  71. package/dist/types/plugins/dynamic-experiences/plugin.d.ts.map +1 -1
  72. package/dist/types/plugins/dynamic-experiences/types.d.ts +22 -129
  73. package/dist/types/plugins/dynamic-experiences/types.d.ts.map +1 -1
  74. package/dist/types/schema-registry.d.ts +190 -0
  75. package/dist/types/schema-registry.d.ts.map +1 -0
  76. package/dist/types/server/index.d.ts +2 -2
  77. package/dist/types/server/index.d.ts.map +1 -1
  78. package/dist/types/server/serialize.d.ts +37 -34
  79. package/dist/types/server/serialize.d.ts.map +1 -1
  80. package/dist/types/typed-content.d.ts +17 -0
  81. package/dist/types/typed-content.d.ts.map +1 -0
  82. package/dist/types/utils/picked-config.d.ts +19 -1
  83. package/dist/types/utils/picked-config.d.ts.map +1 -1
  84. package/dist/version-BLzNWQ-j.cjs +1 -0
  85. package/dist/version-IAAIvoH9.js +4 -0
  86. package/package.json +5 -3
  87. package/dist/api-BzK4kXRt.js +0 -38
  88. package/dist/api-CgENjKwJ.cjs +0 -1
  89. package/dist/docs/reference/dashboard/content/layouts.mdx +0 -62
  90. package/dist/docs/reference/dashboard/content/sections.mdx +0 -28
  91. package/dist/plugin-DJjtc5df.js +0 -252
  92. package/dist/plugin-jHxSAqGG.cjs +0 -1
  93. package/dist/types/utils/api.d.ts +0 -25
  94. package/dist/types/utils/api.d.ts.map +0 -1
  95. package/dist/types/utils/client-headers.d.ts +0 -2
  96. package/dist/types/utils/client-headers.d.ts.map +0 -1
@@ -5,52 +5,61 @@ layout: docs
5
5
 
6
6
  # About the content model
7
7
 
8
- Picked splits your content into three pieces: a layout, a section, and a content entry.
8
+ Picked splits your content into three pieces: a Model, a Block, and a content entry.
9
9
  Why three, when a page editor needs only one?
10
10
 
11
11
  ## Schema and data are separate
12
12
 
13
- A **layout** is a schema. It sets which fields a piece of content can hold, and it holds
13
+ A **Model** is a schema. It sets which fields a piece of content can hold, and it holds
14
14
  no data itself. A **content entry** is one instance of that schema, filled with real
15
15
  values.
16
16
 
17
- One layout backs many entries. Describe a campaign page one time, then make many pages
17
+ One Model backs many entries. Describe a campaign page one time, then make many pages
18
18
  from it. Each entry carries its own title, its own body, and its own image, but they all
19
19
  share the shape.
20
20
 
21
21
  That split is also what lets your code depend on content that it never saw. Your component
22
- reads `content.title` because the layout promises a `title`. It works for every entry that
23
- comes from that layout.
22
+ reads `content.title` because the Model promises a `title`. It works for every entry that
23
+ comes from that Model.
24
24
 
25
- ## A layout has a fixed category
25
+ ## A category gives a Model a role
26
26
 
27
- Each layout is a **page layout** or a **step layout**, and you choose which when you
28
- create it. The category cannot change later.
29
-
30
- | Layout | It gives shape to | Who renders it |
31
- | --- | --- | --- |
32
- | Page layout | A standalone [Page](/reference/dashboard/content/pages). | The SDK renders the entry on your server. |
33
- | Step layout | One [Step](/reference/dashboard/steps) inside a Flow. | The Step renders the entry in the browser. |
27
+ A Model can carry a **category**, and the category decides what the Model gives its shape
28
+ to. A **page layout** backs a standalone Page. A **step layout** backs one Step inside a
29
+ Flow.
34
30
 
35
31
  The category is fixed because it decides where the SDK renders the entry. That is not a
36
- property you can change under an entry that exists already. See
37
- [About pages and flows](/explanation/pages-and-flows).
32
+ property that you can change under an entry that exists already.
33
+
34
+ A Model can also carry no category. Such a Model has no layout role, and nothing renders
35
+ its entries directly. It holds the content that other content points at, such as a
36
+ product or a category of your own. See
37
+ [About content references](/explanation/content-references).
38
+
39
+ The three roles are one machine. A layout is a Model with a job in the render path. A
40
+ Model with no category is the same machine with no such job.
38
41
 
39
- ## A section is a schema fragment
42
+ ## A Block is a schema fragment
40
43
 
41
- A layout gives shape to a whole page or a whole step. A **section** is a part that you put
42
- inside one or more layouts.
44
+ A Model gives shape to a whole page or a whole step. A **Block** is a part that you put
45
+ inside one or more Models.
43
46
 
44
- Define a hero one time as a section, then point at it from every page layout that needs
45
- one. Change the section and every layout that holds it changes with it.
47
+ Define a hero one time as a Block, then point at it from every Model that needs one.
48
+ Change the Block and every Model that holds it changes with it.
46
49
 
47
- This is the reason sections exist at all. Without them you must describe a common
48
- structure again in each layout, and the copies then become different. It is the same
50
+ This is the reason Blocks exist at all. Without them you must describe a common
51
+ structure again in each Model, and the copies then become different. It is the same
49
52
  argument for one fact in one place that runs through the rest of this documentation.
50
53
 
54
+ A Block sits **inside** the entry that embeds it. It has no entry of its own, and no id
55
+ that you can point at.
56
+
57
+ That is the difference between a Block and a reference. A Block is a shape that many
58
+ entries hold. A reference is a pointer at one entry that many entries share.
59
+
51
60
  ## Why a schema change does not migrate your data
52
61
 
53
- Change a layout or a section, and Picked does not rewrite the entries behind it. An entry
62
+ Change a Model or a Block, and Picked does not rewrite the entries behind it. An entry
54
63
  that no longer matches its schema becomes invalid, and the dashboard shows an error on
55
64
  each field that does not fit.
56
65
 
@@ -58,20 +67,21 @@ That is deliberate. An automatic change must decide what a new required field ho
58
67
  every entry that came before it. Any value that it chooses is content that nobody wrote.
59
68
  Picked reports the error instead, and you correct it.
60
69
 
61
- The cost is real. After a schema change, check every entry that uses that layout and fix
70
+ The cost is real. After a schema change, check every entry that uses that Model and fix
62
71
  each error before you publish. Picked serves valid content only, so an entry with an error
63
72
  does not reach a visitor.
64
73
 
65
74
  ## An error points at the exact field
66
75
 
67
76
  A validation error carries a path in JSON style, such as `sections[0].data.title`. The
68
- path holds through nested groups, repeated fields, and sections. An error inside a
77
+ path holds through nested groups, repeated fields, and Blocks. An error inside a
69
78
  repeated group therefore tells you which item in that group holds it.
70
79
 
71
80
  ## Related
72
81
 
73
- - [Page and step layouts](/reference/dashboard/content/layouts) — every field type.
74
- - [Sections](/reference/dashboard/content/sections) — the reusable fragments.
82
+ - [Models](/reference/dashboard/content/models) — every field type.
83
+ - [Blocks](/reference/dashboard/content/blocks) — the reusable fragments.
75
84
  - [Content entries](/reference/dashboard/content/content-entries) — the editor and the
76
85
  validation.
77
- - [About pages and flows](/explanation/pages-and-flows) — which layout category you need.
86
+ - [About content references](/explanation/content-references) — how one entry points at another.
87
+ - [About pages and flows](/explanation/pages-and-flows) — which category you need.
@@ -0,0 +1,95 @@
1
+ ---
2
+ type: how-to
3
+ layout: docs
4
+ ---
5
+
6
+ # How to authenticate the CLI
7
+
8
+ This guide shows you how to install `@picked/cli` and sign it in. Commands that read your
9
+ organizations, projects, and workspaces then know who you are. It expects a Picked account
10
+ and a project directory to work in.
11
+
12
+ ## 1. Install the CLI
13
+
14
+ :::code-group
15
+
16
+ ```bash [npm]
17
+ npm install --save-dev @picked/cli
18
+ ```
19
+
20
+ ```bash [pnpm]
21
+ pnpm add -D @picked/cli
22
+ ```
23
+
24
+ ```bash [yarn]
25
+ yarn add -D @picked/cli
26
+ ```
27
+
28
+ :::
29
+
30
+ The binary is `picked`. Run it from the directory that holds your `picked.config.ts`, so it
31
+ reads your configuration and writes your selection next to it.
32
+
33
+ ## 2. Sign in
34
+
35
+ ```bash
36
+ picked login
37
+ ```
38
+
39
+ The command opens your browser for a one-time sign-in and prints your identity:
40
+
41
+ ```
42
+ Opening your browser to sign in...
43
+ https://api.picked.app/…/oauth/authorize?…
44
+ Logged in as you@example.com (https://api.picked.app)
45
+ ```
46
+
47
+ The CLI stores the session in `~/.picked/auth/<origin>.json`, outside any repository, with
48
+ file mode `600`. It refreshes the session as it nears expiry.
49
+
50
+ ## 3. Confirm the session
51
+
52
+ ```bash
53
+ picked whoami
54
+ ```
55
+
56
+ ```
57
+ you@example.com (https://api.picked.app)
58
+ ```
59
+
60
+ Each command acts on the API origin your current directory resolves to, and on no other. To
61
+ end the session for that origin:
62
+
63
+ ```bash
64
+ picked logout
65
+ ```
66
+
67
+ ```
68
+ Logged out of https://api.picked.app.
69
+ ```
70
+
71
+ ## Run the CLI in CI
72
+
73
+ CI has no browser, so give the CLI a token instead of a session. `PICKED_TOKEN` takes
74
+ precedence over any stored session:
75
+
76
+ ```bash
77
+ PICKED_TOKEN="$PICKED_ACCESS_TOKEN" picked generate types --check
78
+ ```
79
+
80
+ If an API deployment does not offer OAuth client registration, `picked login` fails and
81
+ tells you to set `PICKED_TOKEN`. It falls back to no other flow.
82
+
83
+ :::note
84
+ This is a developer session for local tooling. It is not the same as an
85
+ [API key](/reference/dashboard/api-keys), which authenticates server-to-server delivery and
86
+ management calls, or [dashboard sign-in](/reference/management-api/authentication). Use an
87
+ API key for an application; use `picked login` for the CLI on your machine.
88
+ :::
89
+
90
+ ## Related
91
+
92
+ - [CLI](/reference/tools/cli) — every command, flag, and environment variable.
93
+ - [How to switch workspaces](/how-to/switch-workspaces) — the draft-preview workflow.
94
+ - [How to create and revoke an API key](/how-to/create-and-revoke-an-api-key) — credentials
95
+ for applications.
@@ -0,0 +1,48 @@
1
+ ---
2
+ type: how-to
3
+ layout: docs
4
+ ---
5
+
6
+ # How to create a content entry
7
+
8
+ This guide shows you how to make one instance of a Model and fill it with data. You need
9
+ a Model first. See [How to define a page layout](/how-to/define-a-page-layout).
10
+
11
+ A Page makes its own entry when you create the page. Use this guide for the content that
12
+ no Page and no Step owns, such as an author or a product.
13
+
14
+ ## 1. Open the entries list
15
+
16
+ 1. Open your workspace.
17
+ 2. Click **CMS** in the sidebar.
18
+ 3. Click **Content entries**.
19
+
20
+ ## 2. Create the entry
21
+
22
+ 1. Click **New content**.
23
+ 2. Choose the **Model** for the entry.
24
+ 3. Fill in each field. The form comes from the schema of the Model.
25
+ 4. Click **Create entry**.
26
+
27
+ The Model is fixed when you create the entry. To move content to another Model, make a
28
+ new entry and copy the values across.
29
+
30
+ ## 3. Correct every error
31
+
32
+ An invalid field shows an error next to it while you edit. The error carries the path to
33
+ the exact field. Correct each one before you publish, because Picked serves valid content
34
+ only.
35
+
36
+ ## Find an entry again
37
+
38
+ The entries list shows a title for each entry. The title is the first single-line text
39
+ field of the entry. It shows the entry id when no such field holds a value.
40
+
41
+ Use the **Model** filter to narrow the list to one Model.
42
+
43
+ ## Related
44
+
45
+ - [Content entries](/reference/dashboard/content/content-entries) — the editor reference.
46
+ - [Models](/reference/dashboard/content/models) — every field type.
47
+ - [How to point one entry at another](/how-to/point-one-entry-at-another)
48
+ - [How to publish a workspace](/how-to/publish-a-workspace)
@@ -5,8 +5,8 @@ layout: docs
5
5
 
6
6
  # How to define a page layout
7
7
 
8
- This guide shows you how to define the shape of a page. A layout sets which fields a page
9
- can hold, and it holds no data itself.
8
+ This guide shows you how to define the shape of a page. A page layout sets which fields a
9
+ page can hold, and it holds no data itself.
10
10
 
11
11
  ## Steps
12
12
 
@@ -19,7 +19,7 @@ can hold, and it holds no data itself.
19
19
  6. Add your fields. Choose a type for each one.
20
20
  7. Click **Create model**.
21
21
 
22
- The category is fixed when you create the layout. You cannot change it later.
22
+ The category is fixed when you create the Model. You cannot change it later.
23
23
 
24
24
  ## Make a field repeatable
25
25
 
@@ -31,9 +31,16 @@ for a gallery, or for a list of features.
31
31
  Add a **Group** field to hold a set of fields under one key. Make the group repeatable to
32
32
  describe a list of objects, such as a list of feature cards.
33
33
 
34
+ ## Define content with no layout role
35
+
36
+ A Model needs no category. Leave **Category** as **None (general content)** for content
37
+ that no Page and no Step renders, such as an author or a product. Reach such a Model
38
+ under **CMS** in the sidebar, and point at its entries with a **Reference** field.
39
+
34
40
  ## Related
35
41
 
36
42
  - [About the content model](/explanation/the-content-model) — why the schema and the data
37
43
  are separate.
38
- - [Page and step layouts](/reference/dashboard/content/layouts) — every field type.
39
- - [How to reuse a section](/how-to/reuse-a-section).
44
+ - [Models](/reference/dashboard/content/models) — every field type.
45
+ - [How to reuse a section](/how-to/reuse-a-section)
46
+ - [How to point one entry at another](/how-to/point-one-entry-at-another)
@@ -22,6 +22,13 @@ npm install @picked/client @picked/svelte effector
22
22
 
23
23
  :::
24
24
 
25
+ :::note
26
+ `picked` is a shorter name for the same client. `npm install picked` gives you
27
+ `createClient` from `picked` and the `picked.config` helpers from `picked/config`. It also
28
+ gives you the `picked` command. npm adds `@picked/client` with it, which is where the
29
+ generated types attach.
30
+ :::
31
+
25
32
  ## 2. Create and start the client
26
33
 
27
34
  :::code-group
@@ -0,0 +1,61 @@
1
+ ---
2
+ type: how-to
3
+ layout: docs
4
+ ---
5
+
6
+ # How to point one entry at another
7
+
8
+ This guide shows you how to point one content entry at another, such as a product at its
9
+ category. You need two Models: the one that holds the pointer, and the one that the
10
+ pointer reaches.
11
+
12
+ ## 1. Create the target Model
13
+
14
+ 1. Click **CMS** in the sidebar, then **Models**.
15
+ 2. Click **New model**.
16
+ 3. Enter a **Name** and a **Key**, such as `category`.
17
+ 4. Leave **Category** as **None (general content)**.
18
+ 5. Add your fields.
19
+ 6. Click **Create model**.
20
+
21
+ ## 2. Add a Reference field
22
+
23
+ 1. Open the Model that holds the pointer.
24
+ 2. Drag a **Reference** property onto the schema.
25
+ 3. Enter a **Name** and a **Key**, such as `category`.
26
+ 4. Set **Target Model** to the Model from step 1.
27
+ 5. Click **Save**.
28
+
29
+ Turn on **repeatable** for a field that points at more than one entry. Leave **Target
30
+ Model** as **Any Model** to accept an entry of any Model in the workspace.
31
+
32
+ ## 3. Choose a target on an entry
33
+
34
+ 1. Open a content entry that uses the Model.
35
+ 2. Find your Reference field.
36
+ 3. Click **Choose entry**.
37
+ 4. Search for the entry.
38
+ 5. Choose the entry.
39
+ 6. Click **Save**.
40
+
41
+ Use **Change entry** to point the field somewhere else. Use **Clear** to remove the
42
+ pointer. **Clear** deletes no content.
43
+
44
+ ## Delete a target
45
+
46
+ Picked does not delete an entry while another entry points at it. Clear the reference on
47
+ each entry that points at the target, then delete the target.
48
+
49
+ The same rule holds for a Model. Remove the Reference field that holds it as its **Target
50
+ Model** first.
51
+
52
+ ## Read it in your code
53
+
54
+ The pointer and the entry travel separately. See
55
+ [How to read a referenced entry](/how-to/read-a-referenced-entry).
56
+
57
+ ## Related
58
+
59
+ - [About content references](/explanation/content-references) — why a reference is a pointer.
60
+ - [Models](/reference/dashboard/content/models) — the field and its options.
61
+ - [Content entries](/reference/dashboard/content/content-entries) — the editor reference.
@@ -0,0 +1,111 @@
1
+ ---
2
+ type: how-to
3
+ layout: docs
4
+ ---
5
+
6
+ # How to read a referenced entry
7
+
8
+ This guide shows you how to read the content that a
9
+ [Reference field](/reference/dashboard/content/models#reference-fields) points at. You
10
+ need a component that renders a step first. See
11
+ [How to render a step form](/how-to/render-a-step-form).
12
+
13
+ A Reference field holds a pointer, and not the content. The entry travels beside the
14
+ content of the step, so you resolve the pointer against the content of the client.
15
+
16
+ ## 1. Resolve a single reference
17
+
18
+ Pass the raw field value to `useReference()` in React, or to `getReference()` in Svelte.
19
+
20
+ :::code-group
21
+
22
+ ```tsx [React]
23
+ import { useUnit } from 'effector-react'
24
+ import { useReference, useStepContent } from '@picked/react/hooks'
25
+
26
+ export function ProductCategory() {
27
+ const content = useStepContent()
28
+ const category = useUnit(useReference(content?.category))
29
+
30
+ if (!category) return null
31
+
32
+ return <span>{String(category.data.name ?? '')}</span>
33
+ }
34
+ ```
35
+
36
+ ```svelte [Svelte]
37
+ <script lang="ts">
38
+ import { getStepContent, getReference } from '@picked/svelte/hooks'
39
+
40
+ const content = getStepContent()
41
+ const category = getReference(content.map((c) => c?.category ?? null, { skipVoid: false }))
42
+ </script>
43
+
44
+ {#if $category}
45
+ <span>{$category.data.name ?? ''}</span>
46
+ {/if}
47
+ ```
48
+
49
+ :::
50
+
51
+ In Svelte, pass a store and not a plain value. Content arrives after the component
52
+ starts. A plain value therefore holds the result at "not set".
53
+
54
+ ## 2. Resolve a repeatable reference
55
+
56
+ Use `useReferences()` or `getReferences()`. They give a list in field order.
57
+
58
+ :::code-group
59
+
60
+ ```tsx [React]
61
+ import { useUnit } from 'effector-react'
62
+ import { useReferences, useStepContent } from '@picked/react/hooks'
63
+
64
+ export function ProductCategories() {
65
+ const content = useStepContent()
66
+ const categories = useUnit(useReferences(content?.categories))
67
+
68
+ return (
69
+ <ul>
70
+ {categories.map((category) => (
71
+ <li key={category.id}>{String(category.data.name ?? '')}</li>
72
+ ))}
73
+ </ul>
74
+ )
75
+ }
76
+ ```
77
+
78
+ ```svelte [Svelte]
79
+ <script lang="ts">
80
+ import { getStepContent, getReferences } from '@picked/svelte/hooks'
81
+
82
+ const content = getStepContent()
83
+ const categories = getReferences(content.map((c) => c?.categories ?? null, { skipVoid: false }))
84
+ </script>
85
+
86
+ <ul>
87
+ {#each $categories as category (category.id)}
88
+ <li>{category.data.name ?? ''}</li>
89
+ {/each}
90
+ </ul>
91
+ ```
92
+
93
+ :::
94
+
95
+ The list holds no empty places, so you need no check for each item.
96
+
97
+ ## Handle a target that does not resolve
98
+
99
+ A single reference gives an empty result when Picked cannot resolve the target. A
100
+ repeatable reference leaves the item out of the list.
101
+
102
+ This happens when somebody deleted the target, when the target belongs to another
103
+ workspace, or when the chain of references is deeper than the limit.
104
+
105
+ Render something else for the empty case, as the React example above does.
106
+
107
+ ## Related
108
+
109
+ - [Content](/reference/sdk/content) — every hook and its return type.
110
+ - [About content references](/explanation/content-references) — why the entry travels separately.
111
+ - [How to point one entry at another](/how-to/point-one-entry-at-another) — the dashboard side.
@@ -6,27 +6,42 @@ layout: docs
6
6
  # How to reuse a section
7
7
 
8
8
  This guide shows you how to define a common structure one time and use it in more than
9
- one layout.
9
+ one Model.
10
10
 
11
- ## Create a section
11
+ ## 1. Create the section
12
12
 
13
- 1. Open your workspace.
14
- 2. Click **Pages** in the sidebar, then **Sections**.
13
+ 1. Click **Pages** in the sidebar.
14
+ 2. Click **Page Sections**.
15
15
  3. Click **New block**.
16
16
  4. Enter a **Name** and a **Key**.
17
17
  5. Add your fields.
18
18
  6. Click **Create block**.
19
19
 
20
- ## Use it in a layout
20
+ The **Category** is **Section** already, because you opened the list from **Page
21
+ Sections**.
22
+
23
+ ## 2. Accept the section in a Model
21
24
 
22
25
  1. Open a page layout or a step layout.
23
- 2. Add a **Section** field.
24
- 3. Point that field at your section.
26
+ 2. Add a **Page Sections** field to the schema.
27
+ 3. Click **Save**.
28
+
29
+ The field now accepts any Block of the Section category. Make the field repeatable to
30
+ build a page from a list of sections.
31
+
32
+ If you want one section at a fixed place instead of a list, add a **Content block** field.
33
+ Set its **Block category** to the **Section** category.
34
+
35
+ ## 3. Choose the section in an entry
25
36
 
26
- The layout now carries the fields of the section at every place where that field appears.
37
+ 1. Open a content entry that uses the Model.
38
+ 2. Find the field that you added.
39
+ 3. Choose your Block.
40
+ 4. Fill in the fields of the Block.
41
+ 5. Click **Save**.
27
42
 
28
43
  :::warning
29
- An edit to a section does not migrate the entries that use it. Check each affected content
44
+ An edit to a Block does not migrate the entries that use it. Check each affected content
30
45
  entry again, and correct every field error before you publish.
31
46
  :::
32
47
 
@@ -34,4 +49,5 @@ entry again, and correct every field error before you publish.
34
49
 
35
50
  - [About the content model](/explanation/the-content-model) — why a schema change does not
36
51
  migrate your data.
37
- - [Sections](/reference/dashboard/content/sections) — the reference.
52
+ - [Blocks](/reference/dashboard/content/blocks) — the reference.
53
+ - [Models](/reference/dashboard/content/models) — every field type.
@@ -0,0 +1,123 @@
1
+ ---
2
+ type: how-to
3
+ layout: docs
4
+ ---
5
+
6
+ # How to switch workspaces
7
+
8
+ This guide shows you how to point your local tooling at a different project or workspace.
9
+ Your application then renders that workspace's content and types on your machine. It expects
10
+ a `picked.config.ts` and the [CLI](/reference/tools/cli).
11
+
12
+ Your tooling reads the project and surface named in the committed `picked.config.ts`. The
13
+ CLI writes your choice to `.picked/settings.json` instead. That file is per-developer and
14
+ Git ignores it, so the committed default stays as it is and one command puts it back.
15
+
16
+ See [Workspaces](/reference/dashboard/workspaces) for what Live, Draft, and Archived mean.
17
+
18
+ ## 1. Sign in
19
+
20
+ ```bash
21
+ picked login
22
+ ```
23
+
24
+ This opens your browser for a one-time OAuth sign-in and stores a session under
25
+ `~/.picked/`. Confirm it with `picked whoami`. For CI, set `PICKED_TOKEN` instead — see
26
+ [CLI authentication](/how-to/authenticate-the-cli).
27
+
28
+ ## 2. Find a workspace
29
+
30
+ ```bash
31
+ picked workspace list
32
+ ```
33
+
34
+ ```
35
+ Acme Corp. (acme-corporation)
36
+ Storefront [proj_a1b2]
37
+ Default Storefront [LIVE] (live)
38
+ Checkout rework [DRAFT]
39
+ ```
40
+
41
+ Note the **project id** (`proj_a1b2`) and the name or the id of the workspace you want.
42
+
43
+ ## 3. Switch to the draft
44
+
45
+ ```bash
46
+ picked workspace use --project proj_a1b2 --workspace ws_draft
47
+ ```
48
+
49
+ ```
50
+ Active workspace: Checkout rework [DRAFT] in project proj_a1b2 (source: preview)
51
+ Generated types at /app/src/picked-env.d.ts
52
+ ```
53
+
54
+ A command that names **one specific workspace** (draft, live, or archived):
55
+
56
+ - writes the selection (and its [preview token](/reference/delivery-api/preview-caching-crawling)) to
57
+ `.picked/settings.json`,
58
+ - switches the resolved `source` to `preview` for that project, and
59
+ - regenerates `picked-env.d.ts` from that workspace's schema (skip with `--no-generate`).
60
+
61
+ To browse instead, run `picked workspace use` with no flags. The interactive picker lists
62
+ every project, with **Published (live version)** and each of its workspaces.
63
+
64
+ ## 4. See the draft in your app
65
+
66
+ Both readers of the selection use `.picked/settings.json` with no change to your
67
+ configuration:
68
+
69
+ - **Type generation** now reads the draft schema. Rerun `picked generate types` after more
70
+ edits.
71
+ - The **[Vite plugin](/reference/tools/vite-plugin)** reads the draft's configuration and
72
+ content in development and in a build. It sends the preview token to the
73
+ [Delivery API](/reference/delivery-api). Restart the dev server to apply a switch.
74
+
75
+ Your application renders the unpublished draft on your machine, with types.
76
+
77
+ ## 5. Switch back to live
78
+
79
+ ```bash
80
+ picked workspace use --project proj_a1b2
81
+ ```
82
+
83
+ A command that names a project with no `--workspace`, or **Published (live version)** in the
84
+ picker, discards the preview token and returns `source` to `published`. To confirm what is
85
+ active:
86
+
87
+ ```bash
88
+ picked status
89
+ ```
90
+
91
+ ```
92
+ Config default: project proj_a1b2 (source: published)
93
+ Active selection: none (using the config default).
94
+ ```
95
+
96
+ ## CI and headless runs
97
+
98
+ `.picked/settings.json` is a local, per-developer file. Do not commit it. To choose one
99
+ workspace in CI with no selection file, set the environment directly:
100
+
101
+ ```bash
102
+ PICKED_TOKEN="$TOKEN" \
103
+ PICKED_PROJECT_ID=proj_a1b2 \
104
+ PICKED_PREVIEW_TOKEN="$DRAFT_TOKEN" \
105
+ picked generate types --check
106
+ ```
107
+
108
+ `PICKED_PREVIEW_TOKEN` applies only when the resolved `source` is `preview`. See the
109
+ [CLI environment variables](/reference/tools/cli#environment-variables) for the full
110
+ precedence order.
111
+
112
+ :::note
113
+ A preview token is a long-lived credential for one workspace. Keep it out of the version
114
+ control system, as you do with each other credential. Git ignores `.picked/settings.json`
115
+ for this reason, because `picked workspace use` writes a token there.
116
+ :::
117
+
118
+ ## Related
119
+
120
+ - [CLI](/reference/tools/cli) — every command and flag.
121
+ - [Workspaces](/reference/dashboard/workspaces) — Live, Draft, and Archived states.
122
+ - [Type generation](/reference/sdk/type-generation) — how the schema becomes types.
123
+ - [Preview, cache, and crawlers](/reference/delivery-api/preview-caching-crawling) — preview tokens on the Delivery API.
@@ -25,7 +25,7 @@ Then:
25
25
 
26
26
  - **[Build](/how-to/create-an-experience)** — experiences, flows, conditions, and A/B
27
27
  tests.
28
- - **[Content](/how-to/define-a-page-layout)** — layouts, sections, pages, and assets.
28
+ - **[Content](/how-to/define-a-page-layout)** — Models, Blocks, entries, pages, and assets.
29
29
  - **[Publish](/how-to/publish-a-workspace)** — preview, publish, and roll back.
30
30
  - **[Administer and measure](/how-to/invite-and-remove-members)** — members, API keys,
31
31
  analytics, and the tools that connect Picked to Google Tag Manager and to an AI tool.